init
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
/* Copyright (c) 2018-2020, Arm Limited and Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
VulkanException::VulkanException(const VkResult result, const std::string &msg) :
|
||||
result{result},
|
||||
std::runtime_error{msg}
|
||||
{
|
||||
error_message = std::string(std::runtime_error::what()) + std::string{" : "} + to_string(result);
|
||||
}
|
||||
|
||||
const char *VulkanException::what() const noexcept
|
||||
{
|
||||
return error_message.c_str();
|
||||
}
|
||||
} // namespace vkb
|
||||
@@ -0,0 +1,75 @@
|
||||
/* Copyright (c) 2018-2024, Arm Limited and Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "core/util/error.hpp"
|
||||
|
||||
#include "common/strings.h"
|
||||
#include "core/util/logging.hpp"
|
||||
#include "vk_common.h"
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
/**
|
||||
* @brief Vulkan exception structure
|
||||
*/
|
||||
class VulkanException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Vulkan exception constructor
|
||||
*/
|
||||
VulkanException(VkResult result, const std::string &msg = "Vulkan error");
|
||||
|
||||
/**
|
||||
* @brief Returns the Vulkan error code as string
|
||||
* @return String message of exception
|
||||
*/
|
||||
const char *what() const noexcept override;
|
||||
|
||||
VkResult result;
|
||||
|
||||
private:
|
||||
std::string error_message;
|
||||
};
|
||||
} // namespace vkb
|
||||
|
||||
/// @brief Helper macro to test the result of Vulkan calls which can return an error.
|
||||
#define VK_CHECK(x) \
|
||||
do \
|
||||
{ \
|
||||
VkResult err = x; \
|
||||
if (err) \
|
||||
{ \
|
||||
throw std::runtime_error("Detected Vulkan error: " + vkb::to_string(err)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_VK_HANDLE(handle) \
|
||||
do \
|
||||
{ \
|
||||
if ((handle) == VK_NULL_HANDLE) \
|
||||
{ \
|
||||
LOGE("Handle is NULL"); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
@@ -0,0 +1,28 @@
|
||||
/* Copyright (c) 2019, Arm Limited and Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef GLM_FORCE_RADIANS
|
||||
# define GLM_FORCE_RADIANS
|
||||
#endif
|
||||
#ifndef GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||
# define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||
#endif
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/rotate_vector.hpp>
|
||||
#include <glm/gtx/transform.hpp>
|
||||
@@ -0,0 +1,215 @@
|
||||
/* Copyright (c) 2018-2024, Arm Limited and Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "common/error.h"
|
||||
|
||||
#include "common/glm_common.h"
|
||||
#include <glm/gtx/hash.hpp>
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
template <typename T>
|
||||
inline void read(std::istringstream &is, T &value)
|
||||
{
|
||||
is.read(reinterpret_cast<char *>(&value), sizeof(T));
|
||||
}
|
||||
|
||||
inline void read(std::istringstream &is, std::string &value)
|
||||
{
|
||||
std::size_t size;
|
||||
read(is, size);
|
||||
value.resize(size);
|
||||
is.read(const_cast<char *>(value.data()), size);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void read(std::istringstream &is, std::set<T> &value)
|
||||
{
|
||||
std::size_t size;
|
||||
read(is, size);
|
||||
for (uint32_t i = 0; i < size; i++)
|
||||
{
|
||||
T item;
|
||||
is.read(reinterpret_cast<char *>(&item), sizeof(T));
|
||||
value.insert(std::move(item));
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void read(std::istringstream &is, std::vector<T> &value)
|
||||
{
|
||||
std::size_t size;
|
||||
read(is, size);
|
||||
value.resize(size);
|
||||
is.read(reinterpret_cast<char *>(value.data()), value.size() * sizeof(T));
|
||||
}
|
||||
|
||||
template <class T, class S>
|
||||
inline void read(std::istringstream &is, std::map<T, S> &value)
|
||||
{
|
||||
std::size_t size;
|
||||
read(is, size);
|
||||
|
||||
for (uint32_t i = 0; i < size; i++)
|
||||
{
|
||||
std::pair<T, S> item;
|
||||
read(is, item.first);
|
||||
read(is, item.second);
|
||||
|
||||
value.insert(std::move(item));
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, uint32_t N>
|
||||
inline void read(std::istringstream &is, std::array<T, N> &value)
|
||||
{
|
||||
is.read(reinterpret_cast<char *>(value.data()), N * sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
inline void read(std::istringstream &is, T &first_arg, Args &...args)
|
||||
{
|
||||
read(is, first_arg);
|
||||
|
||||
read(is, args...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void write(std::ostringstream &os, const T &value)
|
||||
{
|
||||
os.write(reinterpret_cast<const char *>(&value), sizeof(T));
|
||||
}
|
||||
|
||||
inline void write(std::ostringstream &os, const std::string &value)
|
||||
{
|
||||
write(os, value.size());
|
||||
os.write(value.data(), value.size());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void write(std::ostringstream &os, const std::set<T> &value)
|
||||
{
|
||||
write(os, value.size());
|
||||
for (const T &item : value)
|
||||
{
|
||||
os.write(reinterpret_cast<const char *>(&item), sizeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void write(std::ostringstream &os, const std::vector<T> &value)
|
||||
{
|
||||
write(os, value.size());
|
||||
os.write(reinterpret_cast<const char *>(value.data()), value.size() * sizeof(T));
|
||||
}
|
||||
|
||||
template <class T, class S>
|
||||
inline void write(std::ostringstream &os, const std::map<T, S> &value)
|
||||
{
|
||||
write(os, value.size());
|
||||
|
||||
for (const std::pair<T, S> &item : value)
|
||||
{
|
||||
write(os, item.first);
|
||||
write(os, item.second);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, uint32_t N>
|
||||
inline void write(std::ostringstream &os, const std::array<T, N> &value)
|
||||
{
|
||||
os.write(reinterpret_cast<const char *>(value.data()), N * sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
inline void write(std::ostringstream &os, const T &first_arg, const Args &...args)
|
||||
{
|
||||
write(os, first_arg);
|
||||
|
||||
write(os, args...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function to combine a given hash
|
||||
* with a generated hash for the input param.
|
||||
*/
|
||||
template <class T>
|
||||
inline void hash_combine(size_t &seed, const T &v)
|
||||
{
|
||||
std::hash<T> hasher;
|
||||
glm::detail::hash_combine(seed, hasher(v));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert a data type
|
||||
* to string using output stream operator.
|
||||
* @param value The object to be converted to string
|
||||
* @return String version of the given object
|
||||
*/
|
||||
template <class T>
|
||||
inline std::string to_string(const T &value)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::fixed << value;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function to check size_t is correctly converted to uint32_t
|
||||
* @param value Value of type size_t to convert
|
||||
* @return An uint32_t representation of the same value
|
||||
*/
|
||||
template <class T>
|
||||
uint32_t to_u32(T value)
|
||||
{
|
||||
static_assert(std::is_arithmetic<T>::value, "T must be numeric");
|
||||
|
||||
if (static_cast<uintmax_t>(value) > static_cast<uintmax_t>(std::numeric_limits<uint32_t>::max()))
|
||||
{
|
||||
throw std::runtime_error("to_u32() failed, value is too big to be converted to uint32_t");
|
||||
}
|
||||
|
||||
return static_cast<uint32_t>(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::vector<uint8_t> to_bytes(const T &value)
|
||||
{
|
||||
return std::vector<uint8_t>{reinterpret_cast<const uint8_t *>(&value),
|
||||
reinterpret_cast<const uint8_t *>(&value) + sizeof(T)};
|
||||
}
|
||||
|
||||
} // namespace vkb
|
||||
@@ -0,0 +1,41 @@
|
||||
/* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/error.h>
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
/**
|
||||
* @brief facade class around vkb::VulkanException, providing a vulkan.hpp-based interface
|
||||
*
|
||||
* See vkb::VulkanException for documentation
|
||||
*/
|
||||
class HPPVulkanException : public vkb::VulkanException
|
||||
{
|
||||
public:
|
||||
HPPVulkanException(vk::Result result, std::string const &msg = "Vulkan error") :
|
||||
vkb::VulkanException(static_cast<VkResult>(result), msg)
|
||||
{}
|
||||
};
|
||||
} // namespace common
|
||||
} // namespace vkb
|
||||
@@ -0,0 +1,414 @@
|
||||
/* Copyright (c) 2023-2025, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/hpp_vk_common.h"
|
||||
#include "core/hpp_descriptor_set.h"
|
||||
#include "core/hpp_image_view.h"
|
||||
#include "core/hpp_render_pass.h"
|
||||
#include "core/hpp_shader_module.h"
|
||||
#include "hpp_resource_record.h"
|
||||
#include "rendering/hpp_render_target.h"
|
||||
#include "resource_caching.h"
|
||||
#include <vulkan/vulkan_hash.hpp>
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <typename Key, typename Value>
|
||||
struct hash<std::map<Key, Value>>
|
||||
{
|
||||
size_t operator()(std::map<Key, Value> const &bindings) const
|
||||
{
|
||||
size_t result = 0;
|
||||
vkb::hash_combine(result, bindings.size());
|
||||
for (auto const &binding : bindings)
|
||||
{
|
||||
vkb::hash_combine(result, binding.first);
|
||||
vkb::hash_combine(result, binding.second);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct hash<std::vector<T>>
|
||||
{
|
||||
size_t operator()(std::vector<T> const &values) const
|
||||
{
|
||||
size_t result = 0;
|
||||
vkb::hash_combine(result, values.size());
|
||||
for (auto const &value : values)
|
||||
{
|
||||
vkb::hash_combine(result, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::common::HPPLoadStoreInfo>
|
||||
{
|
||||
size_t operator()(vkb::common::HPPLoadStoreInfo const &lsi) const
|
||||
{
|
||||
size_t result = 0;
|
||||
vkb::hash_combine(result, lsi.load_op);
|
||||
vkb::hash_combine(result, lsi.store_op);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <vkb::BindingType bindingType, typename T>
|
||||
struct hash<vkb::core::VulkanResource<bindingType, T>>
|
||||
{
|
||||
size_t operator()(const vkb::core::VulkanResource<bindingType, T> &vulkan_resource) const
|
||||
{
|
||||
return std::hash<T>()(vulkan_resource.get_handle());
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::core::HPPDescriptorPool>
|
||||
{
|
||||
size_t operator()(const vkb::core::HPPDescriptorPool &descriptor_pool) const
|
||||
{
|
||||
return std::hash<vkb::DescriptorPool>()(reinterpret_cast<vkb::DescriptorPool const &>(descriptor_pool));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::core::HPPDescriptorSet>
|
||||
{
|
||||
size_t operator()(vkb::core::HPPDescriptorSet &descriptor_set) const
|
||||
{
|
||||
size_t result = 0;
|
||||
vkb::hash_combine(result, descriptor_set.get_layout());
|
||||
// descriptor_pool ?
|
||||
vkb::hash_combine(result, descriptor_set.get_buffer_infos());
|
||||
vkb::hash_combine(result, descriptor_set.get_image_infos());
|
||||
vkb::hash_combine(result, descriptor_set.get_handle());
|
||||
// write_descriptor_sets ?
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::core::HPPDescriptorSetLayout>
|
||||
{
|
||||
size_t operator()(const vkb::core::HPPDescriptorSetLayout &descriptor_set_layout) const
|
||||
{
|
||||
return std::hash<vkb::DescriptorSetLayout>()(reinterpret_cast<vkb::DescriptorSetLayout const &>(descriptor_set_layout));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::core::HPPImage>
|
||||
{
|
||||
size_t operator()(const vkb::core::HPPImage &image) const
|
||||
{
|
||||
size_t result = 0;
|
||||
vkb::hash_combine(result, image.get_memory());
|
||||
vkb::hash_combine(result, image.get_type());
|
||||
vkb::hash_combine(result, image.get_extent());
|
||||
vkb::hash_combine(result, image.get_format());
|
||||
vkb::hash_combine(result, image.get_usage());
|
||||
vkb::hash_combine(result, image.get_sample_count());
|
||||
vkb::hash_combine(result, image.get_tiling());
|
||||
vkb::hash_combine(result, image.get_subresource());
|
||||
vkb::hash_combine(result, image.get_array_layer_count());
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::core::HPPImageView>
|
||||
{
|
||||
size_t operator()(const vkb::core::HPPImageView &image_view) const
|
||||
{
|
||||
size_t result = std::hash<vkb::core::VulkanResourceCpp<vk::ImageView>>()(image_view);
|
||||
vkb::hash_combine(result, image_view.get_image());
|
||||
vkb::hash_combine(result, image_view.get_format());
|
||||
vkb::hash_combine(result, image_view.get_subresource_range());
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::core::HPPRenderPass>
|
||||
{
|
||||
size_t operator()(const vkb::core::HPPRenderPass &render_pass) const
|
||||
{
|
||||
return std::hash<vkb::RenderPass>()(reinterpret_cast<vkb::RenderPass const &>(render_pass));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::core::HPPShaderModule>
|
||||
{
|
||||
size_t operator()(const vkb::core::HPPShaderModule &shader_module) const
|
||||
{
|
||||
return std::hash<vkb::ShaderModule>()(reinterpret_cast<vkb::ShaderModule const &>(shader_module));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::core::HPPShaderResource>
|
||||
{
|
||||
size_t operator()(vkb::core::HPPShaderResource const &shader_resource) const
|
||||
{
|
||||
size_t result = 0;
|
||||
vkb::hash_combine(result, shader_resource.stages);
|
||||
vkb::hash_combine(result, shader_resource.type);
|
||||
vkb::hash_combine(result, shader_resource.mode);
|
||||
vkb::hash_combine(result, shader_resource.set);
|
||||
vkb::hash_combine(result, shader_resource.binding);
|
||||
vkb::hash_combine(result, shader_resource.location);
|
||||
vkb::hash_combine(result, shader_resource.input_attachment_index);
|
||||
vkb::hash_combine(result, shader_resource.vec_size);
|
||||
vkb::hash_combine(result, shader_resource.columns);
|
||||
vkb::hash_combine(result, shader_resource.array_size);
|
||||
vkb::hash_combine(result, shader_resource.offset);
|
||||
vkb::hash_combine(result, shader_resource.size);
|
||||
vkb::hash_combine(result, shader_resource.constant_id);
|
||||
vkb::hash_combine(result, shader_resource.qualifiers);
|
||||
vkb::hash_combine(result, shader_resource.name);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::core::HPPShaderSource>
|
||||
{
|
||||
size_t operator()(const vkb::core::HPPShaderSource &shader_source) const
|
||||
{
|
||||
return std::hash<vkb::ShaderSource>()(reinterpret_cast<vkb::ShaderSource const &>(shader_source));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::core::HPPShaderVariant>
|
||||
{
|
||||
size_t operator()(const vkb::core::HPPShaderVariant &shader_variant) const
|
||||
{
|
||||
return std::hash<vkb::ShaderVariant>()(reinterpret_cast<vkb::ShaderVariant const &>(shader_variant));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::core::HPPSubpassInfo>
|
||||
{
|
||||
size_t operator()(vkb::core::HPPSubpassInfo const &subpass_info) const
|
||||
{
|
||||
size_t result = 0;
|
||||
vkb::hash_combine(result, subpass_info.input_attachments);
|
||||
vkb::hash_combine(result, subpass_info.output_attachments);
|
||||
vkb::hash_combine(result, subpass_info.color_resolve_attachments);
|
||||
vkb::hash_combine(result, subpass_info.disable_depth_stencil_attachment);
|
||||
vkb::hash_combine(result, subpass_info.depth_stencil_resolve_attachment);
|
||||
vkb::hash_combine(result, subpass_info.depth_stencil_resolve_mode);
|
||||
vkb::hash_combine(result, subpass_info.debug_name);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::rendering::HPPAttachment>
|
||||
{
|
||||
size_t operator()(const vkb::rendering::HPPAttachment &attachment) const
|
||||
{
|
||||
size_t result = 0;
|
||||
vkb::hash_combine(result, attachment.format);
|
||||
vkb::hash_combine(result, attachment.samples);
|
||||
vkb::hash_combine(result, attachment.usage);
|
||||
vkb::hash_combine(result, attachment.initial_layout);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::rendering::HPPPipelineState>
|
||||
{
|
||||
size_t operator()(const vkb::rendering::HPPPipelineState &pipeline_state) const
|
||||
{
|
||||
return std::hash<vkb::PipelineState>()(reinterpret_cast<vkb::PipelineState const &>(pipeline_state));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::rendering::HPPRenderTarget>
|
||||
{
|
||||
size_t operator()(const vkb::rendering::HPPRenderTarget &render_target) const
|
||||
{
|
||||
size_t result = 0;
|
||||
vkb::hash_combine(result, render_target.get_extent());
|
||||
for (auto const &view : render_target.get_views())
|
||||
{
|
||||
vkb::hash_combine(result, view);
|
||||
}
|
||||
for (auto const &attachment : render_target.get_attachments())
|
||||
{
|
||||
vkb::hash_combine(result, attachment);
|
||||
}
|
||||
for (auto const &input : render_target.get_input_attachments())
|
||||
{
|
||||
vkb::hash_combine(result, input);
|
||||
}
|
||||
for (auto const &output : render_target.get_output_attachments())
|
||||
{
|
||||
vkb::hash_combine(result, output);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
/**
|
||||
* @brief facade helper functions and structs around the functions and structs in common/resource_caching, providing a vulkan.hpp-based interface
|
||||
*/
|
||||
|
||||
namespace
|
||||
{
|
||||
template <class T, class... A>
|
||||
struct HPPRecordHelper
|
||||
{
|
||||
size_t record(HPPResourceRecord & /*recorder*/, A &.../*args*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void index(HPPResourceRecord & /*recorder*/, size_t /*index*/, T & /*resource*/)
|
||||
{}
|
||||
};
|
||||
|
||||
template <class... A>
|
||||
struct HPPRecordHelper<vkb::core::HPPShaderModule, A...>
|
||||
{
|
||||
size_t record(HPPResourceRecord &recorder, A &...args)
|
||||
{
|
||||
return recorder.register_shader_module(args...);
|
||||
}
|
||||
|
||||
void index(HPPResourceRecord &recorder, size_t index, vkb::core::HPPShaderModule &shader_module)
|
||||
{
|
||||
recorder.set_shader_module(index, shader_module);
|
||||
}
|
||||
};
|
||||
|
||||
template <class... A>
|
||||
struct HPPRecordHelper<vkb::core::HPPPipelineLayout, A...>
|
||||
{
|
||||
size_t record(HPPResourceRecord &recorder, A &...args)
|
||||
{
|
||||
return recorder.register_pipeline_layout(args...);
|
||||
}
|
||||
|
||||
void index(HPPResourceRecord &recorder, size_t index, vkb::core::HPPPipelineLayout &pipeline_layout)
|
||||
{
|
||||
recorder.set_pipeline_layout(index, pipeline_layout);
|
||||
}
|
||||
};
|
||||
|
||||
template <class... A>
|
||||
struct HPPRecordHelper<vkb::core::HPPRenderPass, A...>
|
||||
{
|
||||
size_t record(HPPResourceRecord &recorder, A &...args)
|
||||
{
|
||||
return recorder.register_render_pass(args...);
|
||||
}
|
||||
|
||||
void index(HPPResourceRecord &recorder, size_t index, vkb::core::HPPRenderPass &render_pass)
|
||||
{
|
||||
recorder.set_render_pass(index, render_pass);
|
||||
}
|
||||
};
|
||||
|
||||
template <class... A>
|
||||
struct HPPRecordHelper<vkb::core::HPPGraphicsPipeline, A...>
|
||||
{
|
||||
size_t record(HPPResourceRecord &recorder, A &...args)
|
||||
{
|
||||
return recorder.register_graphics_pipeline(args...);
|
||||
}
|
||||
|
||||
void index(HPPResourceRecord &recorder, size_t index, vkb::core::HPPGraphicsPipeline &graphics_pipeline)
|
||||
{
|
||||
recorder.set_graphics_pipeline(index, graphics_pipeline);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
template <class T, class... A>
|
||||
T &request_resource(vkb::core::DeviceCpp &device, vkb::HPPResourceRecord *recorder, std::unordered_map<size_t, T> &resources, A &...args)
|
||||
{
|
||||
HPPRecordHelper<T, A...> record_helper;
|
||||
|
||||
size_t hash{0U};
|
||||
hash_param(hash, args...);
|
||||
|
||||
auto res_it = resources.find(hash);
|
||||
|
||||
if (res_it != resources.end())
|
||||
{
|
||||
return res_it->second;
|
||||
}
|
||||
|
||||
// If we do not have it already, create and cache it
|
||||
const char *res_type = typeid(T).name();
|
||||
size_t res_id = resources.size();
|
||||
|
||||
LOGD("Building #{} cache object ({})", res_id, res_type);
|
||||
|
||||
// Only error handle in release
|
||||
#ifndef DEBUG
|
||||
try
|
||||
{
|
||||
#endif
|
||||
T resource(device, args...);
|
||||
|
||||
auto res_ins_it = resources.emplace(hash, std::move(resource));
|
||||
|
||||
if (!res_ins_it.second)
|
||||
{
|
||||
throw std::runtime_error{std::string{"Insertion error for #"} + std::to_string(res_id) + "cache object (" + res_type + ")"};
|
||||
}
|
||||
|
||||
res_it = res_ins_it.first;
|
||||
|
||||
if (recorder)
|
||||
{
|
||||
size_t index = record_helper.record(*recorder, args...);
|
||||
record_helper.index(*recorder, index, res_it->second);
|
||||
}
|
||||
#ifndef DEBUG
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
LOGE("Creation error for #{} cache object ({})", res_id, res_type);
|
||||
throw e;
|
||||
}
|
||||
#endif
|
||||
|
||||
return res_it->second;
|
||||
}
|
||||
} // namespace common
|
||||
} // namespace vkb
|
||||
@@ -0,0 +1,36 @@
|
||||
/* Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/strings.h>
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
/**
|
||||
* @brief facade helper functions around the functions in common/strings.h, providing a vulkan.hpp-based interface
|
||||
*/
|
||||
std::string to_string(vk::Extent2D const &extent)
|
||||
{
|
||||
return vkb::to_string(static_cast<VkExtent2D const &>(extent));
|
||||
}
|
||||
} // namespace common
|
||||
} // namespace vkb
|
||||
@@ -0,0 +1,42 @@
|
||||
/* Copyright (c) 2021-2024, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/utils.h>
|
||||
|
||||
#include <rendering/hpp_render_context.h>
|
||||
#include <scene_graph/hpp_scene.h>
|
||||
|
||||
/**
|
||||
* @brief facade helper functions around the functions in common/utils.h, providing a vulkan.hpp-based interface
|
||||
*/
|
||||
namespace vkb
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
inline sg::Node &add_free_camera(vkb::scene_graph::HPPScene &scene, const std::string &node_name, vk::Extent2D const &extent)
|
||||
{
|
||||
return vkb::add_free_camera(reinterpret_cast<vkb::sg::Scene &>(scene), node_name, static_cast<VkExtent2D>(extent));
|
||||
}
|
||||
|
||||
inline void screenshot(vkb::rendering::HPPRenderContext &render_context, const std::string &filename)
|
||||
{
|
||||
vkb::screenshot(reinterpret_cast<vkb::RenderContext &>(render_context), filename);
|
||||
}
|
||||
} // namespace common
|
||||
} // namespace vkb
|
||||
@@ -0,0 +1,453 @@
|
||||
/* Copyright (c) 2021-2025, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/vk_common.h"
|
||||
|
||||
#include "core/util/logging.hpp"
|
||||
#include "vulkan/vulkan.hpp"
|
||||
#include "vulkan/vulkan_format_traits.hpp"
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
/**
|
||||
* @brief facade helper functions and structs around the functions and structs in common/vk_common, providing a vulkan.hpp-based interface
|
||||
*/
|
||||
|
||||
struct HPPBufferMemoryBarrier
|
||||
{
|
||||
vk::PipelineStageFlags src_stage_mask = vk::PipelineStageFlagBits::eBottomOfPipe;
|
||||
vk::PipelineStageFlags dst_stage_mask = vk::PipelineStageFlagBits::eTopOfPipe;
|
||||
vk::AccessFlags src_access_mask = {};
|
||||
vk::AccessFlags dst_access_mask = {};
|
||||
};
|
||||
|
||||
struct HPPImageMemoryBarrier
|
||||
{
|
||||
vk::PipelineStageFlags src_stage_mask = vk::PipelineStageFlagBits::eBottomOfPipe;
|
||||
vk::PipelineStageFlags dst_stage_mask = vk::PipelineStageFlagBits::eTopOfPipe;
|
||||
vk::AccessFlags src_access_mask;
|
||||
vk::AccessFlags dst_access_mask;
|
||||
vk::ImageLayout old_layout = vk::ImageLayout::eUndefined;
|
||||
vk::ImageLayout new_layout = vk::ImageLayout::eUndefined;
|
||||
uint32_t src_queue_family = VK_QUEUE_FAMILY_IGNORED;
|
||||
uint32_t dst_queue_family = VK_QUEUE_FAMILY_IGNORED;
|
||||
};
|
||||
|
||||
struct HPPLoadStoreInfo
|
||||
{
|
||||
vk::AttachmentLoadOp load_op = vk::AttachmentLoadOp::eClear;
|
||||
vk::AttachmentStoreOp store_op = vk::AttachmentStoreOp::eStore;
|
||||
};
|
||||
|
||||
inline int32_t get_bits_per_pixel(vk::Format format)
|
||||
{
|
||||
return vkb::get_bits_per_pixel(static_cast<VkFormat>(format));
|
||||
}
|
||||
|
||||
inline vk::Format get_suitable_depth_format(vk::PhysicalDevice physical_device,
|
||||
bool depth_only = false,
|
||||
const std::vector<vk::Format> &depth_format_priority_list = {
|
||||
vk::Format::eD32Sfloat, vk::Format::eD24UnormS8Uint, vk::Format::eD16Unorm})
|
||||
{
|
||||
return static_cast<vk::Format>(
|
||||
vkb::get_suitable_depth_format(physical_device, depth_only, reinterpret_cast<std::vector<VkFormat> const &>(depth_format_priority_list)));
|
||||
}
|
||||
|
||||
inline bool is_buffer_descriptor_type(vk::DescriptorType descriptor_type)
|
||||
{
|
||||
return vkb::is_buffer_descriptor_type(static_cast<VkDescriptorType>(descriptor_type));
|
||||
}
|
||||
|
||||
inline bool is_depth_only_format(vk::Format format)
|
||||
{
|
||||
assert(vkb::is_depth_only_format(static_cast<VkFormat>(format)) ==
|
||||
((vk::componentCount(format) == 1) && (std::string(vk::componentName(format, 0)) == "D")));
|
||||
return vkb::is_depth_only_format(static_cast<VkFormat>(format));
|
||||
}
|
||||
|
||||
inline bool is_depth_stencil_format(vk::Format format)
|
||||
{
|
||||
assert(vkb::is_depth_stencil_format(static_cast<VkFormat>(format)) ==
|
||||
((vk::componentCount(format) == 2) && (std::string(vk::componentName(format, 0)) == "D") &&
|
||||
(std::string(vk::componentName(format, 1)) == "S")));
|
||||
return vkb::is_depth_stencil_format(static_cast<VkFormat>(format));
|
||||
}
|
||||
|
||||
inline bool is_depth_format(vk::Format format)
|
||||
{
|
||||
assert(vkb::is_depth_format(static_cast<VkFormat>(format)) == (std::string(vk::componentName(format, 0)) == "D"));
|
||||
return vkb::is_depth_format(static_cast<VkFormat>(format));
|
||||
}
|
||||
|
||||
inline bool is_dynamic_buffer_descriptor_type(vk::DescriptorType descriptor_type)
|
||||
{
|
||||
return vkb::is_dynamic_buffer_descriptor_type(static_cast<VkDescriptorType>(descriptor_type));
|
||||
}
|
||||
|
||||
inline vk::ShaderModule load_shader(const std::string &filename, vk::Device device, vk::ShaderStageFlagBits stage)
|
||||
{
|
||||
return static_cast<vk::ShaderModule>(vkb::load_shader(filename, device, static_cast<VkShaderStageFlagBits>(stage)));
|
||||
}
|
||||
|
||||
inline void image_layout_transition(vk::CommandBuffer command_buffer,
|
||||
vk::Image image,
|
||||
vk::ImageLayout old_layout,
|
||||
vk::ImageLayout new_layout)
|
||||
{
|
||||
vkb::image_layout_transition(static_cast<VkCommandBuffer>(command_buffer),
|
||||
static_cast<VkImage>(image),
|
||||
static_cast<VkImageLayout>(old_layout),
|
||||
static_cast<VkImageLayout>(new_layout));
|
||||
}
|
||||
|
||||
inline void image_layout_transition(vk::CommandBuffer command_buffer,
|
||||
vk::Image image,
|
||||
vk::ImageLayout old_layout,
|
||||
vk::ImageLayout new_layout,
|
||||
vk::ImageSubresourceRange subresource_range)
|
||||
{
|
||||
vkb::image_layout_transition(static_cast<VkCommandBuffer>(command_buffer),
|
||||
static_cast<VkImage>(image),
|
||||
static_cast<VkImageLayout>(old_layout),
|
||||
static_cast<VkImageLayout>(new_layout),
|
||||
static_cast<VkImageSubresourceRange>(subresource_range));
|
||||
}
|
||||
|
||||
inline void image_layout_transition(vk::CommandBuffer command_buffer,
|
||||
vk::Image image,
|
||||
vk::PipelineStageFlags src_stage_mask,
|
||||
vk::PipelineStageFlags dst_stage_mask,
|
||||
vk::AccessFlags src_access_mask,
|
||||
vk::AccessFlags dst_access_mask,
|
||||
vk::ImageLayout old_layout,
|
||||
vk::ImageLayout new_layout,
|
||||
vk::ImageSubresourceRange const &subresource_range)
|
||||
{
|
||||
vkb::image_layout_transition(static_cast<VkCommandBuffer>(command_buffer),
|
||||
static_cast<VkImage>(image),
|
||||
static_cast<VkPipelineStageFlags>(src_stage_mask),
|
||||
static_cast<VkPipelineStageFlags>(dst_stage_mask),
|
||||
static_cast<VkAccessFlags>(src_access_mask),
|
||||
static_cast<VkAccessFlags>(dst_access_mask),
|
||||
static_cast<VkImageLayout>(old_layout),
|
||||
static_cast<VkImageLayout>(new_layout),
|
||||
static_cast<VkImageSubresourceRange const &>(subresource_range));
|
||||
}
|
||||
|
||||
inline void make_filters_valid(vk::PhysicalDevice physical_device, vk::Format format, vk::Filter *filter, vk::SamplerMipmapMode *mipmapMode = nullptr)
|
||||
{
|
||||
// Not all formats support linear filtering, so we need to adjust them if they don't
|
||||
if (*filter == vk::Filter::eNearest && (mipmapMode == nullptr || *mipmapMode == vk::SamplerMipmapMode::eNearest))
|
||||
{
|
||||
return; // These must already be valid
|
||||
}
|
||||
|
||||
vk::FormatProperties properties = physical_device.getFormatProperties(format);
|
||||
|
||||
if (!(properties.optimalTilingFeatures & vk::FormatFeatureFlagBits::eSampledImageFilterLinear))
|
||||
{
|
||||
*filter = vk::Filter::eNearest;
|
||||
if (mipmapMode)
|
||||
{
|
||||
*mipmapMode = vk::SamplerMipmapMode::eNearest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline vk::SurfaceFormatKHR select_surface_format(vk::PhysicalDevice gpu,
|
||||
vk::SurfaceKHR surface,
|
||||
std::vector<vk::Format> const &preferred_formats = {
|
||||
vk::Format::eR8G8B8A8Srgb, vk::Format::eB8G8R8A8Srgb, vk::Format::eA8B8G8R8SrgbPack32})
|
||||
{
|
||||
std::vector<vk::SurfaceFormatKHR> supported_surface_formats = gpu.getSurfaceFormatsKHR(surface);
|
||||
assert(!supported_surface_formats.empty());
|
||||
|
||||
auto it = std::ranges::find_if(supported_surface_formats,
|
||||
[&preferred_formats](vk::SurfaceFormatKHR surface_format) {
|
||||
return std::ranges::any_of(preferred_formats,
|
||||
[&surface_format](vk::Format format) { return format == surface_format.format; });
|
||||
});
|
||||
|
||||
// We use the first supported format as a fallback in case none of the preferred formats is available
|
||||
return it != supported_surface_formats.end() ? *it : supported_surface_formats[0];
|
||||
}
|
||||
|
||||
inline vk::Format choose_blendable_format(vk::PhysicalDevice gpu, const std::vector<vk::Format> &format_priority_list)
|
||||
{
|
||||
for (const auto &format : format_priority_list)
|
||||
{
|
||||
vk::FormatProperties fmt_props = gpu.getFormatProperties(format);
|
||||
|
||||
if (fmt_props.optimalTilingFeatures & vk::FormatFeatureFlagBits::eColorAttachmentBlend)
|
||||
return format;
|
||||
}
|
||||
|
||||
throw std::runtime_error("No suitable blendable format could be determined");
|
||||
}
|
||||
|
||||
// helper functions not backed by vk_common.h
|
||||
inline vk::CommandBuffer
|
||||
allocate_command_buffer(vk::Device device, vk::CommandPool command_pool, vk::CommandBufferLevel level = vk::CommandBufferLevel::ePrimary)
|
||||
{
|
||||
vk::CommandBufferAllocateInfo command_buffer_allocate_info{.commandPool = command_pool, .level = level, .commandBufferCount = 1};
|
||||
return device.allocateCommandBuffers(command_buffer_allocate_info).front();
|
||||
}
|
||||
|
||||
inline vk::DescriptorSet allocate_descriptor_set(vk::Device device, vk::DescriptorPool descriptor_pool, vk::DescriptorSetLayout descriptor_set_layout)
|
||||
{
|
||||
vk::DescriptorSetAllocateInfo descriptor_set_allocate_info{.descriptorPool = descriptor_pool,
|
||||
.descriptorSetCount = 1,
|
||||
.pSetLayouts = &descriptor_set_layout};
|
||||
return device.allocateDescriptorSets(descriptor_set_allocate_info).front();
|
||||
}
|
||||
|
||||
inline vk::Framebuffer
|
||||
create_framebuffer(vk::Device device, vk::RenderPass render_pass, std::vector<vk::ImageView> const &attachments, vk::Extent2D const &extent)
|
||||
{
|
||||
vk::FramebufferCreateInfo framebuffer_create_info{.renderPass = render_pass,
|
||||
.attachmentCount = static_cast<uint32_t>(attachments.size()),
|
||||
.pAttachments = attachments.data(),
|
||||
.width = extent.width,
|
||||
.height = extent.height,
|
||||
.layers = 1};
|
||||
return device.createFramebuffer(framebuffer_create_info);
|
||||
}
|
||||
|
||||
inline vk::Pipeline create_graphics_pipeline(vk::Device device,
|
||||
vk::PipelineCache pipeline_cache,
|
||||
std::vector<vk::PipelineShaderStageCreateInfo> const &shader_stages,
|
||||
vk::PipelineVertexInputStateCreateInfo const &vertex_input_state,
|
||||
vk::PrimitiveTopology primitive_topology,
|
||||
uint32_t patch_control_points,
|
||||
vk::PolygonMode polygon_mode,
|
||||
vk::CullModeFlags cull_mode,
|
||||
vk::FrontFace front_face,
|
||||
std::vector<vk::PipelineColorBlendAttachmentState> const &blend_attachment_states,
|
||||
vk::PipelineDepthStencilStateCreateInfo const &depth_stencil_state,
|
||||
vk::PipelineLayout pipeline_layout,
|
||||
vk::RenderPass render_pass)
|
||||
{
|
||||
vk::PipelineInputAssemblyStateCreateInfo input_assembly_state{.topology = primitive_topology};
|
||||
|
||||
vk::PipelineTessellationStateCreateInfo tessellation_state{.patchControlPoints = patch_control_points};
|
||||
|
||||
vk::PipelineViewportStateCreateInfo viewport_state{.viewportCount = 1, .scissorCount = 1};
|
||||
|
||||
vk::PipelineRasterizationStateCreateInfo rasterization_state{
|
||||
.polygonMode = polygon_mode, .cullMode = cull_mode, .frontFace = front_face, .lineWidth = 1.0f};
|
||||
|
||||
vk::PipelineMultisampleStateCreateInfo multisample_state{.rasterizationSamples = vk::SampleCountFlagBits::e1};
|
||||
|
||||
vk::PipelineColorBlendStateCreateInfo color_blend_state{.attachmentCount = static_cast<uint32_t>(blend_attachment_states.size()),
|
||||
.pAttachments = blend_attachment_states.data()};
|
||||
|
||||
std::array<vk::DynamicState, 2> dynamic_state_enables = {vk::DynamicState::eViewport, vk::DynamicState::eScissor};
|
||||
vk::PipelineDynamicStateCreateInfo dynamic_state{.dynamicStateCount = static_cast<uint32_t>(dynamic_state_enables.size()),
|
||||
.pDynamicStates = dynamic_state_enables.data()};
|
||||
|
||||
// Final fullscreen composition pass pipeline
|
||||
vk::GraphicsPipelineCreateInfo pipeline_create_info{.stageCount = static_cast<uint32_t>(shader_stages.size()),
|
||||
.pStages = shader_stages.data(),
|
||||
.pVertexInputState = &vertex_input_state,
|
||||
.pInputAssemblyState = &input_assembly_state,
|
||||
.pTessellationState = &tessellation_state,
|
||||
.pViewportState = &viewport_state,
|
||||
.pRasterizationState = &rasterization_state,
|
||||
.pMultisampleState = &multisample_state,
|
||||
.pDepthStencilState = &depth_stencil_state,
|
||||
.pColorBlendState = &color_blend_state,
|
||||
.pDynamicState = &dynamic_state,
|
||||
.layout = pipeline_layout,
|
||||
.renderPass = render_pass,
|
||||
.basePipelineIndex = -1};
|
||||
|
||||
vk::Result result;
|
||||
vk::Pipeline pipeline;
|
||||
std::tie(result, pipeline) = device.createGraphicsPipeline(pipeline_cache, pipeline_create_info);
|
||||
assert(result == vk::Result::eSuccess);
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
inline vk::ImageView create_image_view(vk::Device device,
|
||||
vk::Image image,
|
||||
vk::ImageViewType view_type,
|
||||
vk::Format format,
|
||||
vk::ImageAspectFlags aspect_mask = vk::ImageAspectFlagBits::eColor,
|
||||
uint32_t base_mip_level = 0,
|
||||
uint32_t level_count = 1,
|
||||
uint32_t base_array_layer = 0,
|
||||
uint32_t layer_count = 1)
|
||||
{
|
||||
vk::ImageViewCreateInfo image_view_create_info{.image = image,
|
||||
.viewType = view_type,
|
||||
.format = format,
|
||||
.subresourceRange = {.aspectMask = aspect_mask,
|
||||
.baseMipLevel = base_mip_level,
|
||||
.levelCount = level_count,
|
||||
.baseArrayLayer = base_array_layer,
|
||||
.layerCount = layer_count}};
|
||||
return device.createImageView(image_view_create_info);
|
||||
}
|
||||
|
||||
inline vk::QueryPool create_query_pool(vk::Device device, vk::QueryType query_type, uint32_t query_count, vk::QueryPipelineStatisticFlags pipeline_statistics = {})
|
||||
{
|
||||
vk::QueryPoolCreateInfo query_pool_create_info{.queryType = query_type, .queryCount = query_count, .pipelineStatistics = pipeline_statistics};
|
||||
return device.createQueryPool(query_pool_create_info);
|
||||
}
|
||||
|
||||
inline vk::Sampler create_sampler(vk::Device device,
|
||||
vk::Filter mag_filter,
|
||||
vk::Filter min_filter,
|
||||
vk::SamplerMipmapMode mipmap_mode,
|
||||
vk::SamplerAddressMode sampler_address_mode,
|
||||
float max_anisotropy,
|
||||
float max_LOD)
|
||||
{
|
||||
vk::SamplerCreateInfo sampler_create_info{.magFilter = mag_filter,
|
||||
.minFilter = min_filter,
|
||||
.mipmapMode = mipmap_mode,
|
||||
.addressModeU = sampler_address_mode,
|
||||
.addressModeV = sampler_address_mode,
|
||||
.addressModeW = sampler_address_mode,
|
||||
.anisotropyEnable = (1.0f < max_anisotropy),
|
||||
.maxAnisotropy = max_anisotropy,
|
||||
.compareOp = vk::CompareOp::eNever,
|
||||
.minLod = 0.0f,
|
||||
.maxLod = max_LOD,
|
||||
.borderColor = vk::BorderColor::eFloatOpaqueWhite};
|
||||
return device.createSampler(sampler_create_info);
|
||||
}
|
||||
|
||||
inline vk::Sampler create_sampler(vk::PhysicalDevice gpu,
|
||||
vk::Device device,
|
||||
vk::Format format,
|
||||
vk::Filter filter,
|
||||
vk::SamplerAddressMode sampler_address_mode,
|
||||
float max_anisotropy,
|
||||
float max_LOD)
|
||||
{
|
||||
const vk::FormatProperties fmt_props = gpu.getFormatProperties(format);
|
||||
|
||||
bool has_linear_filter = !!(fmt_props.optimalTilingFeatures & vk::FormatFeatureFlagBits::eSampledImageFilterLinear);
|
||||
|
||||
return create_sampler(device,
|
||||
has_linear_filter ? filter : vk::Filter::eNearest,
|
||||
has_linear_filter ? filter : vk::Filter::eNearest,
|
||||
has_linear_filter ? vk::SamplerMipmapMode::eLinear : vk::SamplerMipmapMode::eNearest,
|
||||
sampler_address_mode,
|
||||
max_anisotropy,
|
||||
max_LOD);
|
||||
}
|
||||
|
||||
inline vk::ImageAspectFlags get_image_aspect_flags(vk::ImageUsageFlagBits usage, vk::Format format)
|
||||
{
|
||||
vk::ImageAspectFlags image_aspect_flags;
|
||||
|
||||
switch (usage)
|
||||
{
|
||||
case vk::ImageUsageFlagBits::eColorAttachment:
|
||||
assert(!vkb::common::is_depth_format(format));
|
||||
image_aspect_flags = vk::ImageAspectFlagBits::eColor;
|
||||
break;
|
||||
case vk::ImageUsageFlagBits::eDepthStencilAttachment:
|
||||
assert(vkb::common::is_depth_format(format));
|
||||
image_aspect_flags = vk::ImageAspectFlagBits::eDepth;
|
||||
// Stencil aspect should only be set on depth + stencil formats
|
||||
if (vkb::common::is_depth_stencil_format(format))
|
||||
{
|
||||
image_aspect_flags |= vk::ImageAspectFlagBits::eStencil;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
return image_aspect_flags;
|
||||
}
|
||||
|
||||
inline void submit_and_wait(vk::Device device, vk::Queue queue, std::vector<vk::CommandBuffer> command_buffers, std::vector<vk::Semaphore> semaphores = {})
|
||||
{
|
||||
// Submit command_buffer
|
||||
vk::SubmitInfo submit_info{.commandBufferCount = static_cast<uint32_t>(command_buffers.size()),
|
||||
.pCommandBuffers = command_buffers.data(),
|
||||
.signalSemaphoreCount = static_cast<uint32_t>(semaphores.size()),
|
||||
.pSignalSemaphores = semaphores.data()};
|
||||
|
||||
// Create fence to ensure that command_buffer has finished executing
|
||||
vk::Fence fence = device.createFence({});
|
||||
|
||||
// Submit to the queue
|
||||
queue.submit(submit_info, fence);
|
||||
|
||||
// Wait for the fence to signal that command_buffer has finished executing
|
||||
vk::Result result = device.waitForFences(fence, true, DEFAULT_FENCE_TIMEOUT);
|
||||
if (result != vk::Result::eSuccess)
|
||||
{
|
||||
LOGE("Vulkan error on waitForFences: {}", vk::to_string(result));
|
||||
abort();
|
||||
}
|
||||
|
||||
// Destroy the fence
|
||||
device.destroyFence(fence);
|
||||
}
|
||||
|
||||
inline uint32_t get_queue_family_index(std::vector<vk::QueueFamilyProperties> const &queue_family_properties, vk::QueueFlagBits queue_flag)
|
||||
{
|
||||
// Dedicated queue for compute
|
||||
// Try to find a queue family index that supports compute but not graphics
|
||||
if (queue_flag & vk::QueueFlagBits::eCompute)
|
||||
{
|
||||
auto propertyIt = std::ranges::find_if(queue_family_properties,
|
||||
[queue_flag](const vk::QueueFamilyProperties &property) { return (property.queueFlags & queue_flag) && !(property.queueFlags & vk::QueueFlagBits::eGraphics); });
|
||||
if (propertyIt != queue_family_properties.end())
|
||||
{
|
||||
return static_cast<uint32_t>(std::distance(queue_family_properties.begin(), propertyIt));
|
||||
}
|
||||
}
|
||||
|
||||
// Dedicated queue for transfer
|
||||
// Try to find a queue family index that supports transfer but not graphics and compute
|
||||
if (queue_flag & vk::QueueFlagBits::eTransfer)
|
||||
{
|
||||
auto propertyIt = std::ranges::find_if(queue_family_properties,
|
||||
[queue_flag](const vk::QueueFamilyProperties &property) {
|
||||
return (property.queueFlags & queue_flag) && !(property.queueFlags & vk::QueueFlagBits::eGraphics) &&
|
||||
!(property.queueFlags & vk::QueueFlagBits::eCompute);
|
||||
});
|
||||
if (propertyIt != queue_family_properties.end())
|
||||
{
|
||||
return static_cast<uint32_t>(std::distance(queue_family_properties.begin(), propertyIt));
|
||||
}
|
||||
}
|
||||
|
||||
// For other queue types or if no separate compute queue is present, return the first one to support the requested flags
|
||||
auto propertyIt = std::ranges::find_if(
|
||||
queue_family_properties, [queue_flag](const vk::QueueFamilyProperties &property) { return (property.queueFlags & queue_flag) == queue_flag; });
|
||||
if (propertyIt != queue_family_properties.end())
|
||||
{
|
||||
return static_cast<uint32_t>(std::distance(queue_family_properties.begin(), propertyIt));
|
||||
}
|
||||
|
||||
throw std::runtime_error("Could not find a matching queue family index");
|
||||
}
|
||||
|
||||
} // namespace common
|
||||
} // namespace vkb
|
||||
@@ -0,0 +1,36 @@
|
||||
/* Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ktx_common.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
namespace ktx
|
||||
{
|
||||
ktxTexture *load_texture(std::string const &filename)
|
||||
{
|
||||
ktxTexture *ktx_texture;
|
||||
KTX_error_code result = ktxTexture_CreateFromNamedFile(filename.c_str(), KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, &ktx_texture);
|
||||
if ((result != KTX_SUCCESS) || (ktx_texture == nullptr))
|
||||
{
|
||||
throw std::runtime_error("Couldn't load texture");
|
||||
}
|
||||
return ktx_texture;
|
||||
}
|
||||
} // namespace ktx
|
||||
} // namespace vkb
|
||||
@@ -0,0 +1,29 @@
|
||||
/* Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ktx.h>
|
||||
#include <string>
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
namespace ktx
|
||||
{
|
||||
ktxTexture *load_texture(std::string const &filename);
|
||||
}
|
||||
} // namespace vkb
|
||||
@@ -0,0 +1,133 @@
|
||||
/* Copyright (c) 2021, Arm Limited and Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
// Simple optional class for pre c++17 std::optional
|
||||
// May be replaced by std::optional in the future
|
||||
template <typename Type>
|
||||
class Optional
|
||||
{
|
||||
public:
|
||||
virtual ~Optional() = default;
|
||||
Optional() = default;
|
||||
|
||||
Optional(const Optional &optional);
|
||||
|
||||
template <typename U = Type>
|
||||
Optional(const U &value);
|
||||
|
||||
bool has_value() const;
|
||||
const Type &value() const;
|
||||
const Type value_or(Type &&alternative) const;
|
||||
const Type value_or(const Type &alternative = {}) const;
|
||||
|
||||
Optional &operator=(Optional &&opt)
|
||||
{
|
||||
_has_value = opt._has_value;
|
||||
_value = opt._value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U = Type>
|
||||
Optional &operator=(U &&value)
|
||||
{
|
||||
_has_value = true;
|
||||
_value = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Optional &operator=(const Optional &value)
|
||||
{
|
||||
_has_value = value._has_value;
|
||||
_value = value._value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U = Type>
|
||||
Optional &operator=(U *value)
|
||||
{
|
||||
if (value == nullptr)
|
||||
{
|
||||
_has_value = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
_has_value = true;
|
||||
_value = *value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
bool _has_value = false;
|
||||
Type _value;
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
Optional<Type>::Optional(const Optional &optional)
|
||||
{
|
||||
_has_value = optional._has_value;
|
||||
_value = optional._value;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
template <typename U>
|
||||
Optional<Type>::Optional(const U &value)
|
||||
{
|
||||
_has_value = true;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
bool Optional<Type>::has_value() const
|
||||
{
|
||||
return _has_value;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
const Type &Optional<Type>::value() const
|
||||
{
|
||||
assert(_has_value && "Value does not exist");
|
||||
return _value;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
const Type Optional<Type>::value_or(Type &&alternative) const
|
||||
{
|
||||
if (has_value())
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
return alternative;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
const Type Optional<Type>::value_or(const Type &alternative) const
|
||||
{
|
||||
if (has_value())
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
return alternative;
|
||||
}
|
||||
} // namespace vkb
|
||||
@@ -0,0 +1,781 @@
|
||||
/* Copyright (c) 2018-2025, Arm Limited and Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/descriptor_pool.h"
|
||||
#include "core/descriptor_set.h"
|
||||
#include "core/descriptor_set_layout.h"
|
||||
#include "core/framebuffer.h"
|
||||
#include "core/image.h"
|
||||
#include "core/pipeline.h"
|
||||
#include "rendering/pipeline_state.h"
|
||||
#include "rendering/render_target.h"
|
||||
#include "resource_record.h"
|
||||
|
||||
#include "common/helpers.h"
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<vkb::ShaderSource>
|
||||
{
|
||||
std::size_t operator()(const vkb::ShaderSource &shader_source) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, shader_source.get_id());
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::ShaderVariant>
|
||||
{
|
||||
std::size_t operator()(const vkb::ShaderVariant &shader_variant) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, shader_variant.get_id());
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::ShaderModule>
|
||||
{
|
||||
std::size_t operator()(const vkb::ShaderModule &shader_module) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, shader_module.get_id());
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::DescriptorSetLayout>
|
||||
{
|
||||
std::size_t operator()(const vkb::DescriptorSetLayout &descriptor_set_layout) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, descriptor_set_layout.get_handle());
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::DescriptorPool>
|
||||
{
|
||||
std::size_t operator()(const vkb::DescriptorPool &descriptor_pool) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, descriptor_pool.get_descriptor_set_layout());
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::PipelineLayout>
|
||||
{
|
||||
std::size_t operator()(const vkb::PipelineLayout &pipeline_layout) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, pipeline_layout.get_handle());
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::RenderPass>
|
||||
{
|
||||
std::size_t operator()(const vkb::RenderPass &render_pass) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, render_pass.get_handle());
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::Attachment>
|
||||
{
|
||||
std::size_t operator()(const vkb::Attachment &attachment) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkFormat>::type>(attachment.format));
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkSampleCountFlagBits>::type>(attachment.samples));
|
||||
vkb::hash_combine(result, attachment.usage);
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkImageLayout>::type>(attachment.initial_layout));
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::LoadStoreInfo>
|
||||
{
|
||||
std::size_t operator()(const vkb::LoadStoreInfo &load_store_info) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkAttachmentLoadOp>::type>(load_store_info.load_op));
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkAttachmentStoreOp>::type>(load_store_info.store_op));
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::SubpassInfo>
|
||||
{
|
||||
std::size_t operator()(const vkb::SubpassInfo &subpass_info) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
for (uint32_t output_attachment : subpass_info.output_attachments)
|
||||
{
|
||||
vkb::hash_combine(result, output_attachment);
|
||||
}
|
||||
|
||||
for (uint32_t input_attachment : subpass_info.input_attachments)
|
||||
{
|
||||
vkb::hash_combine(result, input_attachment);
|
||||
}
|
||||
|
||||
for (uint32_t resolve_attachment : subpass_info.color_resolve_attachments)
|
||||
{
|
||||
vkb::hash_combine(result, resolve_attachment);
|
||||
}
|
||||
|
||||
vkb::hash_combine(result, subpass_info.disable_depth_stencil_attachment);
|
||||
vkb::hash_combine(result, subpass_info.depth_stencil_resolve_attachment);
|
||||
vkb::hash_combine(result, subpass_info.depth_stencil_resolve_mode);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::SpecializationConstantState>
|
||||
{
|
||||
std::size_t operator()(const vkb::SpecializationConstantState &specialization_constant_state) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
for (auto constants : specialization_constant_state.get_specialization_constant_state())
|
||||
{
|
||||
vkb::hash_combine(result, constants.first);
|
||||
for (const auto data : constants.second)
|
||||
{
|
||||
vkb::hash_combine(result, data);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::ShaderResource>
|
||||
{
|
||||
std::size_t operator()(const vkb::ShaderResource &shader_resource) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
if (shader_resource.type == vkb::ShaderResourceType::Input ||
|
||||
shader_resource.type == vkb::ShaderResourceType::Output ||
|
||||
shader_resource.type == vkb::ShaderResourceType::PushConstant ||
|
||||
shader_resource.type == vkb::ShaderResourceType::SpecializationConstant)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
vkb::hash_combine(result, shader_resource.set);
|
||||
vkb::hash_combine(result, shader_resource.binding);
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<vkb::ShaderResourceType>::type>(shader_resource.type));
|
||||
vkb::hash_combine(result, shader_resource.mode);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<VkDescriptorBufferInfo>
|
||||
{
|
||||
std::size_t operator()(const VkDescriptorBufferInfo &descriptor_buffer_info) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, descriptor_buffer_info.buffer);
|
||||
vkb::hash_combine(result, descriptor_buffer_info.range);
|
||||
vkb::hash_combine(result, descriptor_buffer_info.offset);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<VkDescriptorImageInfo>
|
||||
{
|
||||
std::size_t operator()(const VkDescriptorImageInfo &descriptor_image_info) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, descriptor_image_info.imageView);
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkImageLayout>::type>(descriptor_image_info.imageLayout));
|
||||
vkb::hash_combine(result, descriptor_image_info.sampler);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<VkWriteDescriptorSet>
|
||||
{
|
||||
std::size_t operator()(const VkWriteDescriptorSet &write_descriptor_set) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, write_descriptor_set.dstSet);
|
||||
vkb::hash_combine(result, write_descriptor_set.dstBinding);
|
||||
vkb::hash_combine(result, write_descriptor_set.dstArrayElement);
|
||||
vkb::hash_combine(result, write_descriptor_set.descriptorCount);
|
||||
vkb::hash_combine(result, write_descriptor_set.descriptorType);
|
||||
|
||||
switch (write_descriptor_set.descriptorType)
|
||||
{
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLER:
|
||||
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
|
||||
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
|
||||
for (uint32_t i = 0; i < write_descriptor_set.descriptorCount; i++)
|
||||
{
|
||||
vkb::hash_combine(result, write_descriptor_set.pImageInfo[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
|
||||
for (uint32_t i = 0; i < write_descriptor_set.descriptorCount; i++)
|
||||
{
|
||||
vkb::hash_combine(result, write_descriptor_set.pTexelBufferView[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
|
||||
for (uint32_t i = 0; i < write_descriptor_set.descriptorCount; i++)
|
||||
{
|
||||
vkb::hash_combine(result, write_descriptor_set.pBufferInfo[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Not implemented
|
||||
break;
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<VkVertexInputAttributeDescription>
|
||||
{
|
||||
std::size_t operator()(const VkVertexInputAttributeDescription &vertex_attrib) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, vertex_attrib.binding);
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkFormat>::type>(vertex_attrib.format));
|
||||
vkb::hash_combine(result, vertex_attrib.location);
|
||||
vkb::hash_combine(result, vertex_attrib.offset);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<VkVertexInputBindingDescription>
|
||||
{
|
||||
std::size_t operator()(const VkVertexInputBindingDescription &vertex_binding) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, vertex_binding.binding);
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkVertexInputRate>::type>(vertex_binding.inputRate));
|
||||
vkb::hash_combine(result, vertex_binding.stride);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::StencilOpState>
|
||||
{
|
||||
std::size_t operator()(const vkb::StencilOpState &stencil) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkCompareOp>::type>(stencil.compare_op));
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkStencilOp>::type>(stencil.depth_fail_op));
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkStencilOp>::type>(stencil.fail_op));
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkStencilOp>::type>(stencil.pass_op));
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<VkExtent2D>
|
||||
{
|
||||
size_t operator()(const VkExtent2D &extent) const
|
||||
{
|
||||
size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, extent.width);
|
||||
vkb::hash_combine(result, extent.height);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<VkOffset2D>
|
||||
{
|
||||
size_t operator()(const VkOffset2D &offset) const
|
||||
{
|
||||
size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, offset.x);
|
||||
vkb::hash_combine(result, offset.y);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<VkRect2D>
|
||||
{
|
||||
size_t operator()(const VkRect2D &rect) const
|
||||
{
|
||||
size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, rect.extent);
|
||||
vkb::hash_combine(result, rect.offset);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<VkViewport>
|
||||
{
|
||||
size_t operator()(const VkViewport &viewport) const
|
||||
{
|
||||
size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, viewport.width);
|
||||
vkb::hash_combine(result, viewport.height);
|
||||
vkb::hash_combine(result, viewport.maxDepth);
|
||||
vkb::hash_combine(result, viewport.minDepth);
|
||||
vkb::hash_combine(result, viewport.x);
|
||||
vkb::hash_combine(result, viewport.y);
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::ColorBlendAttachmentState>
|
||||
{
|
||||
std::size_t operator()(const vkb::ColorBlendAttachmentState &color_blend_attachment) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkBlendOp>::type>(color_blend_attachment.alpha_blend_op));
|
||||
vkb::hash_combine(result, color_blend_attachment.blend_enable);
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkBlendOp>::type>(color_blend_attachment.color_blend_op));
|
||||
vkb::hash_combine(result, color_blend_attachment.color_write_mask);
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkBlendFactor>::type>(color_blend_attachment.dst_alpha_blend_factor));
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkBlendFactor>::type>(color_blend_attachment.dst_color_blend_factor));
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkBlendFactor>::type>(color_blend_attachment.src_alpha_blend_factor));
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkBlendFactor>::type>(color_blend_attachment.src_color_blend_factor));
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::RenderTarget>
|
||||
{
|
||||
std::size_t operator()(const vkb::RenderTarget &render_target) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
for (auto &view : render_target.get_views())
|
||||
{
|
||||
vkb::hash_combine(result, view.get_handle());
|
||||
vkb::hash_combine(result, view.get_image().get_handle());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<vkb::PipelineState>
|
||||
{
|
||||
std::size_t operator()(const vkb::PipelineState &pipeline_state) const
|
||||
{
|
||||
std::size_t result = 0;
|
||||
|
||||
vkb::hash_combine(result, pipeline_state.get_pipeline_layout().get_handle());
|
||||
|
||||
// For graphics only
|
||||
if (auto render_pass = pipeline_state.get_render_pass())
|
||||
{
|
||||
vkb::hash_combine(result, render_pass->get_handle());
|
||||
}
|
||||
|
||||
vkb::hash_combine(result, pipeline_state.get_specialization_constant_state());
|
||||
|
||||
vkb::hash_combine(result, pipeline_state.get_subpass_index());
|
||||
|
||||
for (auto shader_module : pipeline_state.get_pipeline_layout().get_shader_modules())
|
||||
{
|
||||
vkb::hash_combine(result, shader_module->get_id());
|
||||
}
|
||||
|
||||
// VkPipelineVertexInputStateCreateInfo
|
||||
for (auto &attribute : pipeline_state.get_vertex_input_state().attributes)
|
||||
{
|
||||
vkb::hash_combine(result, attribute);
|
||||
}
|
||||
|
||||
for (auto &binding : pipeline_state.get_vertex_input_state().bindings)
|
||||
{
|
||||
vkb::hash_combine(result, binding);
|
||||
}
|
||||
|
||||
// VkPipelineInputAssemblyStateCreateInfo
|
||||
vkb::hash_combine(result, pipeline_state.get_input_assembly_state().primitive_restart_enable);
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkPrimitiveTopology>::type>(pipeline_state.get_input_assembly_state().topology));
|
||||
|
||||
// VkPipelineViewportStateCreateInfo
|
||||
vkb::hash_combine(result, pipeline_state.get_viewport_state().viewport_count);
|
||||
vkb::hash_combine(result, pipeline_state.get_viewport_state().scissor_count);
|
||||
|
||||
// VkPipelineRasterizationStateCreateInfo
|
||||
vkb::hash_combine(result, pipeline_state.get_rasterization_state().cull_mode);
|
||||
vkb::hash_combine(result, pipeline_state.get_rasterization_state().depth_bias_enable);
|
||||
vkb::hash_combine(result, pipeline_state.get_rasterization_state().depth_clamp_enable);
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkFrontFace>::type>(pipeline_state.get_rasterization_state().front_face));
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkPolygonMode>::type>(pipeline_state.get_rasterization_state().polygon_mode));
|
||||
vkb::hash_combine(result, pipeline_state.get_rasterization_state().rasterizer_discard_enable);
|
||||
|
||||
// VkPipelineMultisampleStateCreateInfo
|
||||
vkb::hash_combine(result, pipeline_state.get_multisample_state().alpha_to_coverage_enable);
|
||||
vkb::hash_combine(result, pipeline_state.get_multisample_state().alpha_to_one_enable);
|
||||
vkb::hash_combine(result, pipeline_state.get_multisample_state().min_sample_shading);
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkSampleCountFlagBits>::type>(pipeline_state.get_multisample_state().rasterization_samples));
|
||||
vkb::hash_combine(result, pipeline_state.get_multisample_state().sample_shading_enable);
|
||||
vkb::hash_combine(result, pipeline_state.get_multisample_state().sample_mask);
|
||||
|
||||
// VkPipelineDepthStencilStateCreateInfo
|
||||
vkb::hash_combine(result, pipeline_state.get_depth_stencil_state().back);
|
||||
vkb::hash_combine(result, pipeline_state.get_depth_stencil_state().depth_bounds_test_enable);
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkCompareOp>::type>(pipeline_state.get_depth_stencil_state().depth_compare_op));
|
||||
vkb::hash_combine(result, pipeline_state.get_depth_stencil_state().depth_test_enable);
|
||||
vkb::hash_combine(result, pipeline_state.get_depth_stencil_state().depth_write_enable);
|
||||
vkb::hash_combine(result, pipeline_state.get_depth_stencil_state().front);
|
||||
vkb::hash_combine(result, pipeline_state.get_depth_stencil_state().stencil_test_enable);
|
||||
|
||||
// VkPipelineColorBlendStateCreateInfo
|
||||
vkb::hash_combine(result, static_cast<std::underlying_type<VkLogicOp>::type>(pipeline_state.get_color_blend_state().logic_op));
|
||||
vkb::hash_combine(result, pipeline_state.get_color_blend_state().logic_op_enable);
|
||||
|
||||
for (auto &attachment : pipeline_state.get_color_blend_state().attachments)
|
||||
{
|
||||
vkb::hash_combine(result, attachment);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
namespace
|
||||
{
|
||||
template <typename T>
|
||||
inline void hash_param(size_t &seed, const T &value)
|
||||
{
|
||||
hash_combine(seed, value);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void hash_param(size_t & /*seed*/, const VkPipelineCache & /*value*/)
|
||||
{
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void hash_param<std::vector<uint8_t>>(
|
||||
size_t &seed,
|
||||
const std::vector<uint8_t> &value)
|
||||
{
|
||||
hash_combine(seed, std::string{value.begin(), value.end()});
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void hash_param<std::vector<Attachment>>(
|
||||
size_t &seed,
|
||||
const std::vector<Attachment> &value)
|
||||
{
|
||||
for (auto &attachment : value)
|
||||
{
|
||||
hash_combine(seed, attachment);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void hash_param<std::vector<LoadStoreInfo>>(
|
||||
size_t &seed,
|
||||
const std::vector<LoadStoreInfo> &value)
|
||||
{
|
||||
for (auto &load_store_info : value)
|
||||
{
|
||||
hash_combine(seed, load_store_info);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void hash_param<std::vector<SubpassInfo>>(
|
||||
size_t &seed,
|
||||
const std::vector<SubpassInfo> &value)
|
||||
{
|
||||
for (auto &subpass_info : value)
|
||||
{
|
||||
hash_combine(seed, subpass_info);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void hash_param<std::vector<ShaderModule *>>(
|
||||
size_t &seed,
|
||||
const std::vector<ShaderModule *> &value)
|
||||
{
|
||||
for (auto &shader_module : value)
|
||||
{
|
||||
hash_combine(seed, shader_module->get_id());
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void hash_param<std::vector<ShaderResource>>(
|
||||
size_t &seed,
|
||||
const std::vector<ShaderResource> &value)
|
||||
{
|
||||
for (auto &resource : value)
|
||||
{
|
||||
hash_combine(seed, resource);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void hash_param<std::map<uint32_t, std::map<uint32_t, VkDescriptorBufferInfo>>>(
|
||||
size_t &seed,
|
||||
const std::map<uint32_t, std::map<uint32_t, VkDescriptorBufferInfo>> &value)
|
||||
{
|
||||
for (auto &binding_set : value)
|
||||
{
|
||||
hash_combine(seed, binding_set.first);
|
||||
|
||||
for (auto &binding_element : binding_set.second)
|
||||
{
|
||||
hash_combine(seed, binding_element.first);
|
||||
hash_combine(seed, binding_element.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void hash_param<std::map<uint32_t, std::map<uint32_t, VkDescriptorImageInfo>>>(
|
||||
size_t &seed,
|
||||
const std::map<uint32_t, std::map<uint32_t, VkDescriptorImageInfo>> &value)
|
||||
{
|
||||
for (auto &binding_set : value)
|
||||
{
|
||||
hash_combine(seed, binding_set.first);
|
||||
|
||||
for (auto &binding_element : binding_set.second)
|
||||
{
|
||||
hash_combine(seed, binding_element.first);
|
||||
hash_combine(seed, binding_element.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
inline void hash_param(size_t &seed, const T &first_arg, const Args &...args)
|
||||
{
|
||||
hash_param(seed, first_arg);
|
||||
|
||||
hash_param(seed, args...);
|
||||
}
|
||||
|
||||
template <class T, class... A>
|
||||
struct RecordHelper
|
||||
{
|
||||
size_t record(ResourceRecord & /*recorder*/, A &.../*args*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void index(ResourceRecord & /*recorder*/, size_t /*index*/, T & /*resource*/)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <class... A>
|
||||
struct RecordHelper<ShaderModule, A...>
|
||||
{
|
||||
size_t record(ResourceRecord &recorder, A &...args)
|
||||
{
|
||||
return recorder.register_shader_module(args...);
|
||||
}
|
||||
|
||||
void index(ResourceRecord &recorder, size_t index, ShaderModule &shader_module)
|
||||
{
|
||||
recorder.set_shader_module(index, shader_module);
|
||||
}
|
||||
};
|
||||
|
||||
template <class... A>
|
||||
struct RecordHelper<PipelineLayout, A...>
|
||||
{
|
||||
size_t record(ResourceRecord &recorder, A &...args)
|
||||
{
|
||||
return recorder.register_pipeline_layout(args...);
|
||||
}
|
||||
|
||||
void index(ResourceRecord &recorder, size_t index, PipelineLayout &pipeline_layout)
|
||||
{
|
||||
recorder.set_pipeline_layout(index, pipeline_layout);
|
||||
}
|
||||
};
|
||||
|
||||
template <class... A>
|
||||
struct RecordHelper<RenderPass, A...>
|
||||
{
|
||||
size_t record(ResourceRecord &recorder, A &...args)
|
||||
{
|
||||
return recorder.register_render_pass(args...);
|
||||
}
|
||||
|
||||
void index(ResourceRecord &recorder, size_t index, RenderPass &render_pass)
|
||||
{
|
||||
recorder.set_render_pass(index, render_pass);
|
||||
}
|
||||
};
|
||||
|
||||
template <class... A>
|
||||
struct RecordHelper<GraphicsPipeline, A...>
|
||||
{
|
||||
size_t record(ResourceRecord &recorder, A &...args)
|
||||
{
|
||||
return recorder.register_graphics_pipeline(args...);
|
||||
}
|
||||
|
||||
void index(ResourceRecord &recorder, size_t index, GraphicsPipeline &graphics_pipeline)
|
||||
{
|
||||
recorder.set_graphics_pipeline(index, graphics_pipeline);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
template <class T, class... A>
|
||||
T &request_resource(vkb::core::DeviceC &device, ResourceRecord *recorder, std::unordered_map<std::size_t, T> &resources, A &...args)
|
||||
{
|
||||
RecordHelper<T, A...> record_helper;
|
||||
|
||||
std::size_t hash{0U};
|
||||
hash_param(hash, args...);
|
||||
|
||||
auto res_it = resources.find(hash);
|
||||
|
||||
if (res_it != resources.end())
|
||||
{
|
||||
return res_it->second;
|
||||
}
|
||||
|
||||
// If we do not have it already, create and cache it
|
||||
const char *res_type = typeid(T).name();
|
||||
size_t res_id = resources.size();
|
||||
|
||||
LOGD("Building #{} cache object ({})", res_id, res_type);
|
||||
|
||||
// Only error handle in release
|
||||
#ifndef DEBUG
|
||||
try
|
||||
{
|
||||
#endif
|
||||
T resource(device, args...);
|
||||
|
||||
auto res_ins_it = resources.emplace(hash, std::move(resource));
|
||||
|
||||
if (!res_ins_it.second)
|
||||
{
|
||||
throw std::runtime_error{std::string{"Insertion error for #"} + std::to_string(res_id) + "cache object (" + res_type + ")"};
|
||||
}
|
||||
|
||||
res_it = res_ins_it.first;
|
||||
|
||||
if (recorder)
|
||||
{
|
||||
size_t index = record_helper.record(*recorder, args...);
|
||||
record_helper.index(*recorder, index, res_it->second);
|
||||
}
|
||||
#ifndef DEBUG
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
LOGE("Creation error for #{} cache object ({})", res_id, res_type);
|
||||
throw e;
|
||||
}
|
||||
#endif
|
||||
|
||||
return res_it->second;
|
||||
}
|
||||
} // namespace vkb
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,304 @@
|
||||
/* Copyright (c) 2018-2024, Arm Limited and Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <volk.h>
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
enum class ShaderResourceType;
|
||||
|
||||
namespace sg
|
||||
{
|
||||
enum class AlphaMode;
|
||||
}
|
||||
|
||||
std::vector<std::string> split(const std::string &str, const std::string &delimiter);
|
||||
std::string join(const std::vector<std::string> &str, const std::string &separator);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert a VkFormat enum to a string
|
||||
* @param format Vulkan format to convert.
|
||||
* @return The string to return.
|
||||
*/
|
||||
const std::string to_string(VkFormat format);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert a VkPresentModeKHR to a string
|
||||
* @param present_mode Vulkan present mode to convert.
|
||||
* @return The string to return.
|
||||
*/
|
||||
const std::string to_string(VkPresentModeKHR present_mode);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert a VkResult enum to a string
|
||||
* @param result Vulkan result to convert.
|
||||
* @return The string to return.
|
||||
*/
|
||||
const std::string to_string(VkResult result);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert a VkPhysicalDeviceType enum to a string
|
||||
* @param type Vulkan physical device type to convert.
|
||||
* @return The string to return.
|
||||
*/
|
||||
const std::string to_string(VkPhysicalDeviceType type);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert a VkSurfaceTransformFlagBitsKHR flag to a string
|
||||
* @param transform_flag Vulkan surface transform flag bit to convert.
|
||||
* @return The string to return.
|
||||
*/
|
||||
const std::string to_string(VkSurfaceTransformFlagBitsKHR transform_flag);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert a VkSurfaceFormatKHR format to a string
|
||||
* @param surface_format Vulkan surface format to convert.
|
||||
* @return The string to return.
|
||||
*/
|
||||
const std::string to_string(VkSurfaceFormatKHR surface_format);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert a VkCompositeAlphaFlagBitsKHR flag to a string
|
||||
* @param composite_alpha Vulkan composite alpha flag bit to convert.
|
||||
* @return The string to return.
|
||||
*/
|
||||
const std::string to_string(VkCompositeAlphaFlagBitsKHR composite_alpha);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert a VkImageUsageFlagBits flag to a string
|
||||
* @param image_usage Vulkan image usage flag bit to convert.
|
||||
* @return The string to return.
|
||||
*/
|
||||
const std::string to_string(VkImageUsageFlagBits image_usage);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert a VkExtent2D flag to a string
|
||||
* @param format Vulkan format to convert.
|
||||
* @return The string to return.
|
||||
*/
|
||||
std::string to_string(VkExtent2D format);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkSampleCountFlagBits to a string
|
||||
* @param flags Vulkan sample count flags to convert
|
||||
* @return const std::string
|
||||
*/
|
||||
const std::string to_string(VkSampleCountFlagBits flags);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkImageTiling to a string
|
||||
* @param tiling Vulkan VkImageTiling to convert
|
||||
* @return The string to return
|
||||
*/
|
||||
const std::string to_string(VkImageTiling tiling);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkImageType to a string
|
||||
* @param type Vulkan VkImageType to convert
|
||||
* @return The string to return
|
||||
*/
|
||||
const std::string to_string(VkImageType type);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkBlendFactor to a string
|
||||
* @param blend Vulkan VkBlendFactor to convert
|
||||
* @return The string to return
|
||||
*/
|
||||
const std::string to_string(VkBlendFactor blend);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkVertexInputRate to a string
|
||||
* @param rate Vulkan VkVertexInputRate to convert
|
||||
* @return The string to return
|
||||
*/
|
||||
const std::string to_string(VkVertexInputRate rate);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkBool32 to a string
|
||||
* @param state Vulkan VkBool32 to convert
|
||||
* @return The string to return
|
||||
*/
|
||||
const std::string to_string_vk_bool(VkBool32 state);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkPrimitiveTopology to a string
|
||||
* @param topology Vulkan VkPrimitiveTopology to convert
|
||||
* @return The string to return
|
||||
*/
|
||||
const std::string to_string(VkPrimitiveTopology topology);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkFrontFace to a string
|
||||
* @param face Vulkan VkFrontFace to convert
|
||||
* @return The string to return
|
||||
*/
|
||||
const std::string to_string(VkFrontFace face);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkPolygonMode to a string
|
||||
* @param mode Vulkan VkPolygonMode to convert
|
||||
* @return The string to return
|
||||
*/
|
||||
const std::string to_string(VkPolygonMode mode);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkCompareOp to a string
|
||||
* @param operation Vulkan VkCompareOp to convert
|
||||
* @return The string to return
|
||||
*/
|
||||
const std::string to_string(VkCompareOp operation);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkStencilOp to a string
|
||||
* @param operation Vulkan VkStencilOp to convert
|
||||
* @return The string to return
|
||||
*/
|
||||
const std::string to_string(VkStencilOp operation);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkLogicOp to a string
|
||||
* @param operation Vulkan VkLogicOp to convert
|
||||
* @return The string to return
|
||||
*/
|
||||
const std::string to_string(VkLogicOp operation);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkBlendOp to a string
|
||||
* @param operation Vulkan VkBlendOp to convert
|
||||
* @return The string to return
|
||||
*/
|
||||
const std::string to_string(VkBlendOp operation);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert AlphaMode to a string
|
||||
* @param mode Vulkan AlphaMode to convert
|
||||
* @return The string to return
|
||||
*/
|
||||
const std::string to_string(sg::AlphaMode mode);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert bool to a string
|
||||
* @param flag Vulkan bool to convert (true/false)
|
||||
* @return The string to return
|
||||
*/
|
||||
const std::string to_string(bool flag);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert ShaderResourceType to a string
|
||||
* @param type Vulkan ShaderResourceType to convert
|
||||
* @return The string to return
|
||||
*/
|
||||
const std::string to_string(ShaderResourceType type);
|
||||
|
||||
/**
|
||||
* @brief Helper generic function to convert a bitmask to a string of its components
|
||||
* @param bitmask The bitmask to convert
|
||||
* @param string_map A map of bitmask bits to the string that describe the Vulkan flag
|
||||
* @returns A string of the enabled bits in the bitmask
|
||||
*/
|
||||
template <typename T>
|
||||
inline const std::string to_string(uint32_t bitmask, const std::map<T, const char *> string_map)
|
||||
{
|
||||
std::stringstream result;
|
||||
bool append = false;
|
||||
for (const auto &s : string_map)
|
||||
{
|
||||
if (bitmask & s.first)
|
||||
{
|
||||
if (append)
|
||||
{
|
||||
result << " | ";
|
||||
}
|
||||
result << s.second;
|
||||
append = true;
|
||||
}
|
||||
}
|
||||
return result.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkBufferUsageFlags to a string
|
||||
* @param bitmask The buffer usage bitmask to convert to strings
|
||||
* @return The converted string to return
|
||||
*/
|
||||
const std::string buffer_usage_to_string(VkBufferUsageFlags bitmask);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkShaderStageFlags to a string
|
||||
* @param bitmask The shader stage bitmask to convert
|
||||
* @return The converted string to return
|
||||
*/
|
||||
const std::string shader_stage_to_string(VkShaderStageFlags bitmask);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkImageUsageFlags to a string
|
||||
* @param bitmask The image usage bitmask to convert
|
||||
* @return The converted string to return
|
||||
*/
|
||||
const std::string image_usage_to_string(VkImageUsageFlags bitmask);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkImageAspectFlags to a string
|
||||
* @param bitmask The image aspect bitmask to convert
|
||||
* @return The converted string to return
|
||||
*/
|
||||
const std::string image_aspect_to_string(VkImageAspectFlags bitmask);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkCullModeFlags to a string
|
||||
* @param bitmask The cull mode bitmask to convert
|
||||
* @return The converted string to return
|
||||
*/
|
||||
const std::string cull_mode_to_string(VkCullModeFlags bitmask);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkColorComponentFlags to a string
|
||||
* @param bitmask The color component bitmask to convert
|
||||
* @return The converted string to return
|
||||
*/
|
||||
const std::string color_component_to_string(VkColorComponentFlags bitmask);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkImageCompressionFlagsEXT to a string
|
||||
* @param flags The flags to convert
|
||||
* @return The converted string to return
|
||||
*/
|
||||
const std::string image_compression_flags_to_string(VkImageCompressionFlagsEXT flags);
|
||||
|
||||
/**
|
||||
* @brief Helper function to convert VkImageCompressionFixedRateFlagsEXT to a string
|
||||
* @param flags The flags to convert
|
||||
* @return The converted string to return
|
||||
*/
|
||||
const std::string image_compression_fixed_rate_flags_to_string(VkImageCompressionFixedRateFlagsEXT flags);
|
||||
|
||||
/**
|
||||
* @brief Helper function to split a single string into a vector of strings by a delimiter
|
||||
* @param input The input string to be split
|
||||
* @param delim The character to delimit by
|
||||
* @return The vector of tokenized strings
|
||||
*/
|
||||
std::vector<std::string> split(const std::string &input, char delim);
|
||||
} // namespace vkb
|
||||
@@ -0,0 +1,85 @@
|
||||
/* Copyright (c) 2020-2025, Arm Limited and Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @brief Used to represent a tag
|
||||
*/
|
||||
typedef void (*TagID)();
|
||||
|
||||
/**
|
||||
* @brief Tag acts as a unique identifier to categories objects
|
||||
*
|
||||
* Tags are uniquely defined using different type names. The easiest way of creating a new tag is to use an empty struct
|
||||
* struct TagName{};
|
||||
* struct DifferentTag{};
|
||||
* Tag<TagName>::ID == Tag<TagName>::member != Tag<DifferentTag>:ID
|
||||
*
|
||||
* @tparam TAGS A set of tags
|
||||
*/
|
||||
template <typename... TAGS>
|
||||
class Tag
|
||||
{
|
||||
public:
|
||||
Tag()
|
||||
{
|
||||
tags = {Tag<TAGS>::ID...};
|
||||
}
|
||||
|
||||
static void member(){};
|
||||
|
||||
/**
|
||||
* @brief Unique TagID for a given Tag<TagName>
|
||||
*/
|
||||
constexpr static TagID ID = &member;
|
||||
|
||||
static bool has_tag(TagID id)
|
||||
{
|
||||
return std::ranges::find(tags, id) != tags.end();
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
static bool has_tag()
|
||||
{
|
||||
return has_tag(Tag<C>::ID);
|
||||
}
|
||||
|
||||
template <typename... C>
|
||||
static bool has_tags()
|
||||
{
|
||||
std::vector<TagID> query = {Tag<C>::ID...};
|
||||
bool res = true;
|
||||
for (auto id : query)
|
||||
{
|
||||
res &= has_tag(id);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private:
|
||||
static std::vector<TagID> tags;
|
||||
};
|
||||
|
||||
#ifndef DOXYGEN_SKIP
|
||||
|
||||
template <typename... TAGS>
|
||||
std::vector<TagID> Tag<TAGS...>::tags;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,311 @@
|
||||
/* Copyright (c) 2018-2025, Arm Limited and Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include <queue>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "scene_graph/components/material.h"
|
||||
#include "scene_graph/components/perspective_camera.h"
|
||||
#include "scene_graph/components/sub_mesh.h"
|
||||
#include "scene_graph/node.h"
|
||||
#include "scene_graph/script.h"
|
||||
#include "scene_graph/scripts/free_camera.h"
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
std::string get_extension(const std::string &uri)
|
||||
{
|
||||
auto dot_pos = uri.find_last_of('.');
|
||||
if (dot_pos == std::string::npos)
|
||||
{
|
||||
throw std::runtime_error{"Uri has no extension"};
|
||||
}
|
||||
|
||||
return uri.substr(dot_pos + 1);
|
||||
}
|
||||
|
||||
void screenshot(RenderContext &render_context, const std::string &filename)
|
||||
{
|
||||
assert(render_context.get_format() == VK_FORMAT_R8G8B8A8_UNORM ||
|
||||
render_context.get_format() == VK_FORMAT_B8G8R8A8_UNORM ||
|
||||
render_context.get_format() == VK_FORMAT_R8G8B8A8_SRGB ||
|
||||
render_context.get_format() == VK_FORMAT_B8G8R8A8_SRGB);
|
||||
|
||||
// We want the last completed frame since we don't want to be reading from an incomplete framebuffer
|
||||
auto &frame = render_context.get_last_rendered_frame();
|
||||
assert(!frame.get_render_target().get_views().empty());
|
||||
auto &src_image_view = frame.get_render_target().get_views()[0];
|
||||
|
||||
auto width = render_context.get_surface_extent().width;
|
||||
auto height = render_context.get_surface_extent().height;
|
||||
auto dst_size = width * height * 4;
|
||||
|
||||
vkb::core::BufferC dst_buffer{render_context.get_device(),
|
||||
dst_size,
|
||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
VMA_MEMORY_USAGE_GPU_TO_CPU,
|
||||
VMA_ALLOCATION_CREATE_MAPPED_BIT};
|
||||
|
||||
const auto &queue = render_context.get_device().get_queue_by_flags(VK_QUEUE_GRAPHICS_BIT, 0);
|
||||
|
||||
auto cmd_buf = render_context.get_device().get_command_pool().request_command_buffer();
|
||||
|
||||
cmd_buf->begin(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
|
||||
|
||||
// Enable destination buffer to be written to
|
||||
{
|
||||
BufferMemoryBarrier memory_barrier{};
|
||||
memory_barrier.src_access_mask = 0;
|
||||
memory_barrier.dst_access_mask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
memory_barrier.src_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
memory_barrier.dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
|
||||
cmd_buf->buffer_memory_barrier(dst_buffer, 0, dst_size, memory_barrier);
|
||||
}
|
||||
|
||||
// Enable framebuffer image view to be read from
|
||||
{
|
||||
ImageMemoryBarrier memory_barrier{};
|
||||
memory_barrier.old_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
memory_barrier.new_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
memory_barrier.src_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
memory_barrier.dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
|
||||
cmd_buf->image_memory_barrier(src_image_view, memory_barrier);
|
||||
}
|
||||
|
||||
// Check if framebuffer images are in a BGR format
|
||||
auto bgr_formats = {VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SNORM};
|
||||
bool swizzle = std::ranges::find(bgr_formats, src_image_view.get_format()) != bgr_formats.end();
|
||||
|
||||
// Copy framebuffer image memory
|
||||
VkBufferImageCopy image_copy_region{};
|
||||
image_copy_region.bufferRowLength = width;
|
||||
image_copy_region.bufferImageHeight = height;
|
||||
image_copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
image_copy_region.imageSubresource.layerCount = 1;
|
||||
image_copy_region.imageExtent.width = width;
|
||||
image_copy_region.imageExtent.height = height;
|
||||
image_copy_region.imageExtent.depth = 1;
|
||||
|
||||
cmd_buf->copy_image_to_buffer(src_image_view.get_image(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_buffer, {image_copy_region});
|
||||
|
||||
// Enable destination buffer to map memory
|
||||
{
|
||||
BufferMemoryBarrier memory_barrier{};
|
||||
memory_barrier.src_access_mask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
memory_barrier.dst_access_mask = VK_ACCESS_HOST_READ_BIT;
|
||||
memory_barrier.src_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
memory_barrier.dst_stage_mask = VK_PIPELINE_STAGE_HOST_BIT;
|
||||
|
||||
cmd_buf->buffer_memory_barrier(dst_buffer, 0, dst_size, memory_barrier);
|
||||
}
|
||||
|
||||
// Revert back the framebuffer image view from transfer to present
|
||||
{
|
||||
ImageMemoryBarrier memory_barrier{};
|
||||
memory_barrier.old_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
memory_barrier.new_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
memory_barrier.src_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
memory_barrier.dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
|
||||
cmd_buf->image_memory_barrier(src_image_view, memory_barrier);
|
||||
}
|
||||
|
||||
cmd_buf->end();
|
||||
|
||||
queue.submit(*cmd_buf, frame.get_fence_pool().request_fence());
|
||||
|
||||
queue.wait_idle();
|
||||
|
||||
auto raw_data = dst_buffer.map();
|
||||
|
||||
// Creates a pointer to the address of the first byte of the image data
|
||||
// Replace the A component with 255 (remove transparency)
|
||||
// If swapchain format is BGR, swapping the R and B components
|
||||
uint8_t *data = raw_data;
|
||||
if (swizzle)
|
||||
{
|
||||
for (size_t i = 0; i < height; ++i)
|
||||
{
|
||||
// Iterate over each pixel, swapping R and B components and writing the max value for alpha
|
||||
for (size_t j = 0; j < width; ++j)
|
||||
{
|
||||
auto temp = *(data + 2);
|
||||
*(data + 2) = *(data);
|
||||
*(data) = temp;
|
||||
*(data + 3) = 255;
|
||||
|
||||
// Get next pixel
|
||||
data += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < height; ++i)
|
||||
{
|
||||
// Iterate over each pixel, writing the max value for alpha
|
||||
for (size_t j = 0; j < width; ++j)
|
||||
{
|
||||
*(data + 3) = 255;
|
||||
|
||||
// Get next pixel
|
||||
data += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vkb::fs::write_image(raw_data,
|
||||
filename,
|
||||
width,
|
||||
height,
|
||||
4,
|
||||
width * 4);
|
||||
|
||||
dst_buffer.unmap();
|
||||
} // namespace vkb
|
||||
|
||||
std::string to_snake_case(const std::string &text)
|
||||
{
|
||||
std::stringstream result;
|
||||
|
||||
for (const auto ch : text)
|
||||
{
|
||||
if (std::isalpha(ch))
|
||||
{
|
||||
if (std::isspace(ch))
|
||||
{
|
||||
result << "_";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (std::isupper(ch))
|
||||
{
|
||||
result << "_";
|
||||
}
|
||||
|
||||
result << static_cast<char>(std::tolower(ch));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result << ch;
|
||||
}
|
||||
}
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
sg::Light &add_light(sg::Scene &scene, sg::LightType type, const glm::vec3 &position, const glm::quat &rotation, const sg::LightProperties &props, sg::Node *parent_node)
|
||||
{
|
||||
auto light_ptr = std::make_unique<sg::Light>("light");
|
||||
auto node = std::make_unique<sg::Node>(-1, "light node");
|
||||
|
||||
if (parent_node)
|
||||
{
|
||||
node->set_parent(*parent_node);
|
||||
}
|
||||
|
||||
light_ptr->set_node(*node);
|
||||
light_ptr->set_light_type(type);
|
||||
light_ptr->set_properties(props);
|
||||
|
||||
auto &t = node->get_transform();
|
||||
t.set_translation(position);
|
||||
t.set_rotation(rotation);
|
||||
|
||||
// Storing the light component because the unique_ptr will be moved to the scene
|
||||
auto &light = *light_ptr;
|
||||
|
||||
node->set_component(light);
|
||||
scene.add_child(*node);
|
||||
scene.add_component(std::move(light_ptr));
|
||||
scene.add_node(std::move(node));
|
||||
|
||||
return light;
|
||||
}
|
||||
|
||||
sg::Light &add_point_light(sg::Scene &scene, const glm::vec3 &position, const sg::LightProperties &props, sg::Node *parent_node)
|
||||
{
|
||||
return add_light(scene, sg::LightType::Point, position, {}, props, parent_node);
|
||||
}
|
||||
|
||||
sg::Light &add_directional_light(sg::Scene &scene, const glm::quat &rotation, const sg::LightProperties &props, sg::Node *parent_node)
|
||||
{
|
||||
return add_light(scene, sg::LightType::Directional, {}, rotation, props, parent_node);
|
||||
}
|
||||
|
||||
sg::Light &add_spot_light(sg::Scene &scene, const glm::vec3 &position, const glm::quat &rotation, const sg::LightProperties &props, sg::Node *parent_node)
|
||||
{
|
||||
return add_light(scene, sg::LightType::Spot, position, rotation, props, parent_node);
|
||||
}
|
||||
|
||||
sg::Node &add_free_camera(sg::Scene &scene, const std::string &node_name, VkExtent2D extent)
|
||||
{
|
||||
auto camera_node = scene.find_node(node_name);
|
||||
|
||||
if (!camera_node)
|
||||
{
|
||||
LOGW("Camera node `{}` not found. Looking for `default_camera` node.", node_name.c_str());
|
||||
|
||||
camera_node = scene.find_node("default_camera");
|
||||
}
|
||||
|
||||
if (!camera_node)
|
||||
{
|
||||
throw std::runtime_error("Camera node with name `" + node_name + "` not found.");
|
||||
}
|
||||
|
||||
if (!camera_node->has_component<sg::Camera>())
|
||||
{
|
||||
throw std::runtime_error("No camera component found for `" + node_name + "` node.");
|
||||
}
|
||||
|
||||
auto free_camera_script = std::make_unique<sg::FreeCamera>(*camera_node);
|
||||
|
||||
free_camera_script->resize(extent.width, extent.height);
|
||||
|
||||
scene.add_component(std::move(free_camera_script), *camera_node);
|
||||
|
||||
return *camera_node;
|
||||
}
|
||||
|
||||
size_t calculate_hash(const std::vector<uint8_t> &data)
|
||||
{
|
||||
static_assert(sizeof(data[0]) == 1);
|
||||
constexpr size_t chunk_size = sizeof(size_t) / sizeof(data[0]);
|
||||
size_t data_hash = 0;
|
||||
size_t offset = 0;
|
||||
|
||||
for (; offset + chunk_size < data.size(); offset += chunk_size)
|
||||
{
|
||||
glm::detail::hash_combine(data_hash, *reinterpret_cast<size_t const *>(&data[offset]));
|
||||
}
|
||||
|
||||
if (offset < data.size())
|
||||
{
|
||||
size_t it = 0;
|
||||
std::memcpy(&it, &data[offset], data.size() - offset);
|
||||
glm::detail::hash_combine(data_hash, it);
|
||||
}
|
||||
return data_hash;
|
||||
}
|
||||
|
||||
} // namespace vkb
|
||||
@@ -0,0 +1,112 @@
|
||||
/* Copyright (c) 2018-2025, Arm Limited and Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/error.h"
|
||||
|
||||
#include "common/glm_common.h"
|
||||
#include "glm/gtx/quaternion.hpp"
|
||||
|
||||
#include "filesystem/legacy.h"
|
||||
#include "rendering/pipeline_state.h"
|
||||
#include "rendering/render_context.h"
|
||||
#include "scene_graph/components/sub_mesh.h"
|
||||
#include "scene_graph/scene.h"
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
/**
|
||||
* @brief Extracts the extension from an uri
|
||||
* @param uri An uniform Resource Identifier
|
||||
* @return The extension
|
||||
*/
|
||||
std::string get_extension(const std::string &uri);
|
||||
/**
|
||||
* @brief Generates a hash from an array
|
||||
* @param data
|
||||
* @return data_hash hash of the data
|
||||
*/
|
||||
size_t calculate_hash(const std::vector<uint8_t> &data);
|
||||
|
||||
/**
|
||||
* @param name String to convert to snake case
|
||||
* @return a snake case version of the string
|
||||
*/
|
||||
std::string to_snake_case(const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Takes a screenshot of the app by writing the swapchain image to file (slow function)
|
||||
* @param render_context The RenderContext to use
|
||||
* @param filename The name of the file to save the output to
|
||||
*/
|
||||
void screenshot(RenderContext &render_context, const std::string &filename);
|
||||
|
||||
/**
|
||||
* @brief Adds a light to the scene with the specified parameters
|
||||
* @param scene The scene to add the light to
|
||||
* @param type The light type
|
||||
* @param position The position of the light
|
||||
* @param rotation The rotation of the light
|
||||
* @param props The light properties, such as color and intensity
|
||||
* @param parent_node The parent node for the line, defaults to root
|
||||
* @return The newly created light component
|
||||
*/
|
||||
sg::Light &add_light(sg::Scene &scene, sg::LightType type, const glm::vec3 &position, const glm::quat &rotation = {}, const sg::LightProperties &props = {}, sg::Node *parent_node = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Adds a point light to the scene with the specified parameters
|
||||
* @param scene The scene to add the light to
|
||||
* @param position The position of the light
|
||||
* @param props The light properties, such as color and intensity
|
||||
* @param parent_node The parent node for the line, defaults to root
|
||||
* @return The newly created light component
|
||||
*/
|
||||
sg::Light &add_point_light(sg::Scene &scene, const glm::vec3 &position, const sg::LightProperties &props = {}, sg::Node *parent_node = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Adds a directional light to the scene with the specified parameters
|
||||
* @param scene The scene to add the light to
|
||||
* @param rotation The rotation of the light
|
||||
* @param props The light properties, such as color and intensity
|
||||
* @param parent_node The parent node for the line, defaults to root
|
||||
* @return The newly created light component
|
||||
*/
|
||||
sg::Light &add_directional_light(sg::Scene &scene, const glm::quat &rotation, const sg::LightProperties &props = {}, sg::Node *parent_node = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Adds a spot light to the scene with the specified parameters
|
||||
* @param scene The scene to add the light to
|
||||
* @param position The position of the light
|
||||
* @param rotation The rotation of the light
|
||||
* @param props The light properties, such as color and intensity
|
||||
* @param parent_node The parent node for the line, defaults to root
|
||||
* @return The newly created light component
|
||||
*/
|
||||
sg::Light &add_spot_light(sg::Scene &scene, const glm::vec3 &position, const glm::quat &rotation, const sg::LightProperties &props = {}, sg::Node *parent_node = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Add free camera script to a node with a camera object.
|
||||
* Fallback to the default_camera if node not found.
|
||||
* @param scene The scene to add the camera to
|
||||
* @param node_name The scene node name
|
||||
* @param extent The initial resolution of the camera
|
||||
* @return Node where the script was attached as component
|
||||
*/
|
||||
sg::Node &add_free_camera(sg::Scene &scene, const std::string &node_name, VkExtent2D extent);
|
||||
|
||||
} // namespace vkb
|
||||
@@ -0,0 +1,719 @@
|
||||
/* Copyright (c) 2018-2025, Arm Limited and Contributors
|
||||
* Copyright (c) 2019-2025, Sascha Willems
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "vk_common.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "filesystem/legacy.h"
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const VkResult result)
|
||||
{
|
||||
#define WRITE_VK_ENUM(r) \
|
||||
case VK_##r: \
|
||||
os << #r; \
|
||||
break;
|
||||
|
||||
switch (result)
|
||||
{
|
||||
WRITE_VK_ENUM(NOT_READY);
|
||||
WRITE_VK_ENUM(TIMEOUT);
|
||||
WRITE_VK_ENUM(EVENT_SET);
|
||||
WRITE_VK_ENUM(EVENT_RESET);
|
||||
WRITE_VK_ENUM(INCOMPLETE);
|
||||
WRITE_VK_ENUM(ERROR_OUT_OF_HOST_MEMORY);
|
||||
WRITE_VK_ENUM(ERROR_OUT_OF_DEVICE_MEMORY);
|
||||
WRITE_VK_ENUM(ERROR_INITIALIZATION_FAILED);
|
||||
WRITE_VK_ENUM(ERROR_DEVICE_LOST);
|
||||
WRITE_VK_ENUM(ERROR_MEMORY_MAP_FAILED);
|
||||
WRITE_VK_ENUM(ERROR_LAYER_NOT_PRESENT);
|
||||
WRITE_VK_ENUM(ERROR_EXTENSION_NOT_PRESENT);
|
||||
WRITE_VK_ENUM(ERROR_FEATURE_NOT_PRESENT);
|
||||
WRITE_VK_ENUM(ERROR_INCOMPATIBLE_DRIVER);
|
||||
WRITE_VK_ENUM(ERROR_TOO_MANY_OBJECTS);
|
||||
WRITE_VK_ENUM(ERROR_FORMAT_NOT_SUPPORTED);
|
||||
WRITE_VK_ENUM(ERROR_SURFACE_LOST_KHR);
|
||||
WRITE_VK_ENUM(ERROR_NATIVE_WINDOW_IN_USE_KHR);
|
||||
WRITE_VK_ENUM(SUBOPTIMAL_KHR);
|
||||
WRITE_VK_ENUM(ERROR_OUT_OF_DATE_KHR);
|
||||
WRITE_VK_ENUM(ERROR_INCOMPATIBLE_DISPLAY_KHR);
|
||||
WRITE_VK_ENUM(ERROR_VALIDATION_FAILED_EXT);
|
||||
WRITE_VK_ENUM(ERROR_INVALID_SHADER_NV);
|
||||
default:
|
||||
os << "UNKNOWN_ERROR";
|
||||
}
|
||||
|
||||
#undef WRITE_VK_ENUM
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
bool is_depth_only_format(VkFormat format)
|
||||
{
|
||||
return format == VK_FORMAT_D16_UNORM ||
|
||||
format == VK_FORMAT_D32_SFLOAT;
|
||||
}
|
||||
|
||||
bool is_depth_stencil_format(VkFormat format)
|
||||
{
|
||||
return format == VK_FORMAT_D16_UNORM_S8_UINT ||
|
||||
format == VK_FORMAT_D24_UNORM_S8_UINT ||
|
||||
format == VK_FORMAT_D32_SFLOAT_S8_UINT;
|
||||
}
|
||||
|
||||
bool is_depth_format(VkFormat format)
|
||||
{
|
||||
return is_depth_only_format(format) || is_depth_stencil_format(format);
|
||||
}
|
||||
|
||||
VkFormat get_suitable_depth_format(VkPhysicalDevice physical_device, bool depth_only, const std::vector<VkFormat> &depth_format_priority_list)
|
||||
{
|
||||
VkFormat depth_format{VK_FORMAT_UNDEFINED};
|
||||
|
||||
for (auto &format : depth_format_priority_list)
|
||||
{
|
||||
if (depth_only && !is_depth_only_format(format))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
VkFormatProperties properties;
|
||||
vkGetPhysicalDeviceFormatProperties(physical_device, format, &properties);
|
||||
|
||||
// Format must support depth stencil attachment for optimal tiling
|
||||
if (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||
{
|
||||
depth_format = format;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (depth_format != VK_FORMAT_UNDEFINED)
|
||||
{
|
||||
LOGI("Depth format selected: {}", to_string(depth_format));
|
||||
return depth_format;
|
||||
}
|
||||
|
||||
throw std::runtime_error("No suitable depth format could be determined");
|
||||
}
|
||||
|
||||
VkFormat choose_blendable_format(VkPhysicalDevice physical_device, const std::vector<VkFormat> &format_priority_list)
|
||||
{
|
||||
for (const auto &format : format_priority_list)
|
||||
{
|
||||
VkFormatProperties properties;
|
||||
vkGetPhysicalDeviceFormatProperties(physical_device, format, &properties);
|
||||
if (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT)
|
||||
{
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error("No suitable blendable format could be determined");
|
||||
}
|
||||
|
||||
void make_filters_valid(VkPhysicalDevice physical_device, VkFormat format, VkFilter *filter, VkSamplerMipmapMode *mipmapMode)
|
||||
{
|
||||
// Not all formats support linear filtering, so we need to adjust them if they don't
|
||||
if (*filter == VK_FILTER_NEAREST && (mipmapMode == nullptr || *mipmapMode == VK_SAMPLER_MIPMAP_MODE_NEAREST))
|
||||
{
|
||||
return; // These must already be valid
|
||||
}
|
||||
|
||||
VkFormatProperties properties;
|
||||
vkGetPhysicalDeviceFormatProperties(physical_device, format, &properties);
|
||||
|
||||
if (!(properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT))
|
||||
{
|
||||
*filter = VK_FILTER_NEAREST;
|
||||
if (mipmapMode)
|
||||
{
|
||||
*mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_dynamic_buffer_descriptor_type(VkDescriptorType descriptor_type)
|
||||
{
|
||||
return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC ||
|
||||
descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
||||
}
|
||||
|
||||
bool is_buffer_descriptor_type(VkDescriptorType descriptor_type)
|
||||
{
|
||||
return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
|
||||
descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
|
||||
is_dynamic_buffer_descriptor_type(descriptor_type);
|
||||
}
|
||||
|
||||
int32_t get_bits_per_pixel(VkFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case VK_FORMAT_R4G4_UNORM_PACK8:
|
||||
return 8;
|
||||
case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
|
||||
case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
|
||||
case VK_FORMAT_R5G6B5_UNORM_PACK16:
|
||||
case VK_FORMAT_B5G6R5_UNORM_PACK16:
|
||||
case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
|
||||
case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
|
||||
case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
|
||||
return 16;
|
||||
case VK_FORMAT_R8_UNORM:
|
||||
case VK_FORMAT_R8_SNORM:
|
||||
case VK_FORMAT_R8_USCALED:
|
||||
case VK_FORMAT_R8_SSCALED:
|
||||
case VK_FORMAT_R8_UINT:
|
||||
case VK_FORMAT_R8_SINT:
|
||||
case VK_FORMAT_R8_SRGB:
|
||||
return 8;
|
||||
case VK_FORMAT_R8G8_UNORM:
|
||||
case VK_FORMAT_R8G8_SNORM:
|
||||
case VK_FORMAT_R8G8_USCALED:
|
||||
case VK_FORMAT_R8G8_SSCALED:
|
||||
case VK_FORMAT_R8G8_UINT:
|
||||
case VK_FORMAT_R8G8_SINT:
|
||||
case VK_FORMAT_R8G8_SRGB:
|
||||
return 16;
|
||||
case VK_FORMAT_R8G8B8_UNORM:
|
||||
case VK_FORMAT_R8G8B8_SNORM:
|
||||
case VK_FORMAT_R8G8B8_USCALED:
|
||||
case VK_FORMAT_R8G8B8_SSCALED:
|
||||
case VK_FORMAT_R8G8B8_UINT:
|
||||
case VK_FORMAT_R8G8B8_SINT:
|
||||
case VK_FORMAT_R8G8B8_SRGB:
|
||||
case VK_FORMAT_B8G8R8_UNORM:
|
||||
case VK_FORMAT_B8G8R8_SNORM:
|
||||
case VK_FORMAT_B8G8R8_USCALED:
|
||||
case VK_FORMAT_B8G8R8_SSCALED:
|
||||
case VK_FORMAT_B8G8R8_UINT:
|
||||
case VK_FORMAT_B8G8R8_SINT:
|
||||
case VK_FORMAT_B8G8R8_SRGB:
|
||||
return 24;
|
||||
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||
case VK_FORMAT_R8G8B8A8_SNORM:
|
||||
case VK_FORMAT_R8G8B8A8_USCALED:
|
||||
case VK_FORMAT_R8G8B8A8_SSCALED:
|
||||
case VK_FORMAT_R8G8B8A8_UINT:
|
||||
case VK_FORMAT_R8G8B8A8_SINT:
|
||||
case VK_FORMAT_R8G8B8A8_SRGB:
|
||||
case VK_FORMAT_B8G8R8A8_UNORM:
|
||||
case VK_FORMAT_B8G8R8A8_SNORM:
|
||||
case VK_FORMAT_B8G8R8A8_USCALED:
|
||||
case VK_FORMAT_B8G8R8A8_SSCALED:
|
||||
case VK_FORMAT_B8G8R8A8_UINT:
|
||||
case VK_FORMAT_B8G8R8A8_SINT:
|
||||
case VK_FORMAT_B8G8R8A8_SRGB:
|
||||
case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
|
||||
case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
|
||||
case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
|
||||
case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
|
||||
case VK_FORMAT_A8B8G8R8_UINT_PACK32:
|
||||
case VK_FORMAT_A8B8G8R8_SINT_PACK32:
|
||||
case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
|
||||
return 32;
|
||||
case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
|
||||
case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
|
||||
case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
|
||||
case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
|
||||
case VK_FORMAT_A2R10G10B10_UINT_PACK32:
|
||||
case VK_FORMAT_A2R10G10B10_SINT_PACK32:
|
||||
case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
|
||||
case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
|
||||
case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
|
||||
case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
|
||||
case VK_FORMAT_A2B10G10R10_UINT_PACK32:
|
||||
case VK_FORMAT_A2B10G10R10_SINT_PACK32:
|
||||
return 32;
|
||||
case VK_FORMAT_R16_UNORM:
|
||||
case VK_FORMAT_R16_SNORM:
|
||||
case VK_FORMAT_R16_USCALED:
|
||||
case VK_FORMAT_R16_SSCALED:
|
||||
case VK_FORMAT_R16_UINT:
|
||||
case VK_FORMAT_R16_SINT:
|
||||
case VK_FORMAT_R16_SFLOAT:
|
||||
return 16;
|
||||
case VK_FORMAT_R16G16_UNORM:
|
||||
case VK_FORMAT_R16G16_SNORM:
|
||||
case VK_FORMAT_R16G16_USCALED:
|
||||
case VK_FORMAT_R16G16_SSCALED:
|
||||
case VK_FORMAT_R16G16_UINT:
|
||||
case VK_FORMAT_R16G16_SINT:
|
||||
case VK_FORMAT_R16G16_SFLOAT:
|
||||
return 32;
|
||||
case VK_FORMAT_R16G16B16_UNORM:
|
||||
case VK_FORMAT_R16G16B16_SNORM:
|
||||
case VK_FORMAT_R16G16B16_USCALED:
|
||||
case VK_FORMAT_R16G16B16_SSCALED:
|
||||
case VK_FORMAT_R16G16B16_UINT:
|
||||
case VK_FORMAT_R16G16B16_SINT:
|
||||
case VK_FORMAT_R16G16B16_SFLOAT:
|
||||
return 48;
|
||||
case VK_FORMAT_R16G16B16A16_UNORM:
|
||||
case VK_FORMAT_R16G16B16A16_SNORM:
|
||||
case VK_FORMAT_R16G16B16A16_USCALED:
|
||||
case VK_FORMAT_R16G16B16A16_SSCALED:
|
||||
case VK_FORMAT_R16G16B16A16_UINT:
|
||||
case VK_FORMAT_R16G16B16A16_SINT:
|
||||
case VK_FORMAT_R16G16B16A16_SFLOAT:
|
||||
return 64;
|
||||
case VK_FORMAT_R32_UINT:
|
||||
case VK_FORMAT_R32_SINT:
|
||||
case VK_FORMAT_R32_SFLOAT:
|
||||
return 32;
|
||||
case VK_FORMAT_R32G32_UINT:
|
||||
case VK_FORMAT_R32G32_SINT:
|
||||
case VK_FORMAT_R32G32_SFLOAT:
|
||||
return 64;
|
||||
case VK_FORMAT_R32G32B32_UINT:
|
||||
case VK_FORMAT_R32G32B32_SINT:
|
||||
case VK_FORMAT_R32G32B32_SFLOAT:
|
||||
return 96;
|
||||
case VK_FORMAT_R32G32B32A32_UINT:
|
||||
case VK_FORMAT_R32G32B32A32_SINT:
|
||||
case VK_FORMAT_R32G32B32A32_SFLOAT:
|
||||
return 128;
|
||||
case VK_FORMAT_R64_UINT:
|
||||
case VK_FORMAT_R64_SINT:
|
||||
case VK_FORMAT_R64_SFLOAT:
|
||||
return 64;
|
||||
case VK_FORMAT_R64G64_UINT:
|
||||
case VK_FORMAT_R64G64_SINT:
|
||||
case VK_FORMAT_R64G64_SFLOAT:
|
||||
return 128;
|
||||
case VK_FORMAT_R64G64B64_UINT:
|
||||
case VK_FORMAT_R64G64B64_SINT:
|
||||
case VK_FORMAT_R64G64B64_SFLOAT:
|
||||
return 192;
|
||||
case VK_FORMAT_R64G64B64A64_UINT:
|
||||
case VK_FORMAT_R64G64B64A64_SINT:
|
||||
case VK_FORMAT_R64G64B64A64_SFLOAT:
|
||||
return 256;
|
||||
case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
|
||||
return 32;
|
||||
case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
|
||||
return 32;
|
||||
case VK_FORMAT_D16_UNORM:
|
||||
return 16;
|
||||
case VK_FORMAT_X8_D24_UNORM_PACK32:
|
||||
return 32;
|
||||
case VK_FORMAT_D32_SFLOAT:
|
||||
return 32;
|
||||
case VK_FORMAT_S8_UINT:
|
||||
return 8;
|
||||
case VK_FORMAT_D16_UNORM_S8_UINT:
|
||||
return 24;
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT:
|
||||
return 32;
|
||||
case VK_FORMAT_D32_SFLOAT_S8_UINT:
|
||||
return 40;
|
||||
case VK_FORMAT_UNDEFINED:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
VkShaderModule load_shader(const std::string &filename, VkDevice device, VkShaderStageFlagBits stage)
|
||||
{
|
||||
auto spirv = vkb::fs::read_shader_binary_u32(filename);
|
||||
|
||||
VkShaderModule shader_module;
|
||||
VkShaderModuleCreateInfo module_create_info{};
|
||||
module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
module_create_info.codeSize = spirv.size() * sizeof(uint32_t);
|
||||
module_create_info.pCode = spirv.data();
|
||||
|
||||
VK_CHECK(vkCreateShaderModule(device, &module_create_info, NULL, &shader_module));
|
||||
|
||||
return shader_module;
|
||||
}
|
||||
|
||||
VkAccessFlags getAccessFlags(VkImageLayout layout)
|
||||
{
|
||||
switch (layout)
|
||||
{
|
||||
case VK_IMAGE_LAYOUT_UNDEFINED:
|
||||
case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
|
||||
return 0;
|
||||
case VK_IMAGE_LAYOUT_PREINITIALIZED:
|
||||
return VK_ACCESS_HOST_WRITE_BIT;
|
||||
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
|
||||
return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL:
|
||||
return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
case VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR:
|
||||
return VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR;
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
|
||||
return VK_ACCESS_TRANSFER_READ_BIT;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||
return VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
case VK_IMAGE_LAYOUT_GENERAL:
|
||||
assert(false && "Don't know how to get a meaningful VkAccessFlags for VK_IMAGE_LAYOUT_GENERAL! Don't use it!");
|
||||
return 0;
|
||||
default:
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
VkPipelineStageFlags getPipelineStageFlags(VkImageLayout layout)
|
||||
{
|
||||
switch (layout)
|
||||
{
|
||||
case VK_IMAGE_LAYOUT_UNDEFINED:
|
||||
return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
case VK_IMAGE_LAYOUT_PREINITIALIZED:
|
||||
return VK_PIPELINE_STAGE_HOST_BIT;
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
||||
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
|
||||
return VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
|
||||
return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL:
|
||||
return VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
case VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR:
|
||||
return VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
|
||||
return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
case VK_IMAGE_LAYOUT_GENERAL:
|
||||
assert(false && "Don't know how to get a meaningful VkPipelineStageFlags for VK_IMAGE_LAYOUT_GENERAL! Don't use it!");
|
||||
return 0;
|
||||
default:
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Create an image memory barrier for changing the layout of
|
||||
// an image and put it into an active command buffer
|
||||
// See chapter 12.4 "Image Layout" for details
|
||||
|
||||
void image_layout_transition(VkCommandBuffer command_buffer,
|
||||
VkImage image,
|
||||
VkPipelineStageFlags src_stage_mask,
|
||||
VkPipelineStageFlags dst_stage_mask,
|
||||
VkAccessFlags src_access_mask,
|
||||
VkAccessFlags dst_access_mask,
|
||||
VkImageLayout old_layout,
|
||||
VkImageLayout new_layout,
|
||||
VkImageSubresourceRange const &subresource_range)
|
||||
{
|
||||
// Create an image barrier object
|
||||
VkImageMemoryBarrier image_memory_barrier{};
|
||||
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
image_memory_barrier.srcAccessMask = src_access_mask;
|
||||
image_memory_barrier.dstAccessMask = dst_access_mask;
|
||||
image_memory_barrier.oldLayout = old_layout;
|
||||
image_memory_barrier.newLayout = new_layout;
|
||||
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
image_memory_barrier.image = image;
|
||||
image_memory_barrier.subresourceRange = subresource_range;
|
||||
|
||||
// Put barrier inside setup command buffer
|
||||
vkCmdPipelineBarrier(command_buffer, src_stage_mask, dst_stage_mask, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
|
||||
}
|
||||
|
||||
void image_layout_transition(VkCommandBuffer command_buffer,
|
||||
VkImage image,
|
||||
VkImageLayout old_layout,
|
||||
VkImageLayout new_layout,
|
||||
VkImageSubresourceRange const &subresource_range)
|
||||
{
|
||||
VkPipelineStageFlags src_stage_mask = getPipelineStageFlags(old_layout);
|
||||
VkPipelineStageFlags dst_stage_mask = getPipelineStageFlags(new_layout);
|
||||
VkAccessFlags src_access_mask = getAccessFlags(old_layout);
|
||||
VkAccessFlags dst_access_mask = getAccessFlags(new_layout);
|
||||
|
||||
image_layout_transition(command_buffer, image, src_stage_mask, dst_stage_mask, src_access_mask, dst_access_mask, old_layout, new_layout, subresource_range);
|
||||
}
|
||||
|
||||
// Fixed sub resource on first mip level and layer
|
||||
void image_layout_transition(VkCommandBuffer command_buffer,
|
||||
VkImage image,
|
||||
VkImageLayout old_layout,
|
||||
VkImageLayout new_layout)
|
||||
{
|
||||
VkImageSubresourceRange subresource_range = {};
|
||||
subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
subresource_range.baseMipLevel = 0;
|
||||
subresource_range.levelCount = 1;
|
||||
subresource_range.baseArrayLayer = 0;
|
||||
subresource_range.layerCount = 1;
|
||||
image_layout_transition(command_buffer, image, old_layout, new_layout, subresource_range);
|
||||
}
|
||||
|
||||
void image_layout_transition(VkCommandBuffer command_buffer,
|
||||
std::vector<std::pair<VkImage, VkImageSubresourceRange>> const &imagesAndRanges,
|
||||
VkImageLayout old_layout,
|
||||
VkImageLayout new_layout)
|
||||
{
|
||||
VkPipelineStageFlags src_stage_mask = getPipelineStageFlags(old_layout);
|
||||
VkPipelineStageFlags dst_stage_mask = getPipelineStageFlags(new_layout);
|
||||
VkAccessFlags src_access_mask = getAccessFlags(old_layout);
|
||||
VkAccessFlags dst_access_mask = getAccessFlags(new_layout);
|
||||
|
||||
// Create image barrier objects
|
||||
std::vector<VkImageMemoryBarrier> image_memory_barriers;
|
||||
image_memory_barriers.reserve(imagesAndRanges.size());
|
||||
for (size_t i = 0; i < imagesAndRanges.size(); i++)
|
||||
{
|
||||
image_memory_barriers.emplace_back(VkImageMemoryBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
nullptr,
|
||||
src_access_mask,
|
||||
dst_access_mask,
|
||||
old_layout,
|
||||
new_layout,
|
||||
VK_QUEUE_FAMILY_IGNORED,
|
||||
VK_QUEUE_FAMILY_IGNORED,
|
||||
imagesAndRanges[i].first,
|
||||
imagesAndRanges[i].second});
|
||||
}
|
||||
|
||||
// Put barriers inside setup command buffer
|
||||
vkCmdPipelineBarrier(command_buffer,
|
||||
src_stage_mask,
|
||||
dst_stage_mask,
|
||||
0,
|
||||
0,
|
||||
nullptr,
|
||||
0,
|
||||
nullptr,
|
||||
static_cast<uint32_t>(image_memory_barriers.size()),
|
||||
image_memory_barriers.data());
|
||||
}
|
||||
|
||||
std::vector<VkImageCompressionFixedRateFlagBitsEXT> fixed_rate_compression_flags_to_vector(VkImageCompressionFixedRateFlagsEXT flags)
|
||||
{
|
||||
const std::vector<VkImageCompressionFixedRateFlagBitsEXT> all_flags = {VK_IMAGE_COMPRESSION_FIXED_RATE_1BPC_BIT_EXT, VK_IMAGE_COMPRESSION_FIXED_RATE_2BPC_BIT_EXT,
|
||||
VK_IMAGE_COMPRESSION_FIXED_RATE_3BPC_BIT_EXT, VK_IMAGE_COMPRESSION_FIXED_RATE_4BPC_BIT_EXT,
|
||||
VK_IMAGE_COMPRESSION_FIXED_RATE_5BPC_BIT_EXT, VK_IMAGE_COMPRESSION_FIXED_RATE_6BPC_BIT_EXT,
|
||||
VK_IMAGE_COMPRESSION_FIXED_RATE_7BPC_BIT_EXT, VK_IMAGE_COMPRESSION_FIXED_RATE_8BPC_BIT_EXT,
|
||||
VK_IMAGE_COMPRESSION_FIXED_RATE_9BPC_BIT_EXT, VK_IMAGE_COMPRESSION_FIXED_RATE_10BPC_BIT_EXT,
|
||||
VK_IMAGE_COMPRESSION_FIXED_RATE_11BPC_BIT_EXT, VK_IMAGE_COMPRESSION_FIXED_RATE_12BPC_BIT_EXT,
|
||||
VK_IMAGE_COMPRESSION_FIXED_RATE_13BPC_BIT_EXT, VK_IMAGE_COMPRESSION_FIXED_RATE_14BPC_BIT_EXT,
|
||||
VK_IMAGE_COMPRESSION_FIXED_RATE_15BPC_BIT_EXT, VK_IMAGE_COMPRESSION_FIXED_RATE_16BPC_BIT_EXT,
|
||||
VK_IMAGE_COMPRESSION_FIXED_RATE_17BPC_BIT_EXT, VK_IMAGE_COMPRESSION_FIXED_RATE_18BPC_BIT_EXT,
|
||||
VK_IMAGE_COMPRESSION_FIXED_RATE_19BPC_BIT_EXT, VK_IMAGE_COMPRESSION_FIXED_RATE_20BPC_BIT_EXT,
|
||||
VK_IMAGE_COMPRESSION_FIXED_RATE_21BPC_BIT_EXT, VK_IMAGE_COMPRESSION_FIXED_RATE_22BPC_BIT_EXT,
|
||||
VK_IMAGE_COMPRESSION_FIXED_RATE_23BPC_BIT_EXT, VK_IMAGE_COMPRESSION_FIXED_RATE_24BPC_BIT_EXT};
|
||||
|
||||
std::vector<VkImageCompressionFixedRateFlagBitsEXT> flags_vector;
|
||||
|
||||
for (size_t i = 0; i < all_flags.size(); i++)
|
||||
{
|
||||
if (all_flags[i] & flags)
|
||||
{
|
||||
flags_vector.push_back(all_flags[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return flags_vector;
|
||||
}
|
||||
|
||||
VkImageCompressionPropertiesEXT query_supported_fixed_rate_compression(VkPhysicalDevice gpu, const VkImageCreateInfo &create_info)
|
||||
{
|
||||
VkImageCompressionPropertiesEXT supported_compression_properties{VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT};
|
||||
|
||||
VkImageCompressionControlEXT compression_control{VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT};
|
||||
compression_control.flags = VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT;
|
||||
|
||||
VkPhysicalDeviceImageFormatInfo2 image_format_info{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2};
|
||||
image_format_info.format = create_info.format;
|
||||
image_format_info.type = create_info.imageType;
|
||||
image_format_info.tiling = create_info.tiling;
|
||||
image_format_info.usage = create_info.usage;
|
||||
image_format_info.pNext = &compression_control;
|
||||
|
||||
VkImageFormatProperties2 image_format_properties{VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2};
|
||||
image_format_properties.pNext = &supported_compression_properties;
|
||||
|
||||
vkGetPhysicalDeviceImageFormatProperties2KHR(gpu, &image_format_info, &image_format_properties);
|
||||
|
||||
return supported_compression_properties;
|
||||
}
|
||||
|
||||
VkImageCompressionPropertiesEXT query_applied_compression(VkDevice device, VkImage image)
|
||||
{
|
||||
VkImageSubresource2EXT image_subresource{VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2_KHR};
|
||||
image_subresource.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
image_subresource.imageSubresource.mipLevel = 0;
|
||||
image_subresource.imageSubresource.arrayLayer = 0;
|
||||
|
||||
VkImageCompressionPropertiesEXT compression_properties{VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT};
|
||||
VkSubresourceLayout2EXT subresource_layout{VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2_KHR};
|
||||
subresource_layout.pNext = &compression_properties;
|
||||
|
||||
vkGetImageSubresourceLayout2EXT(device, image, &image_subresource, &subresource_layout);
|
||||
|
||||
return compression_properties;
|
||||
}
|
||||
|
||||
VkSurfaceFormatKHR select_surface_format(VkPhysicalDevice gpu, VkSurfaceKHR surface, std::vector<VkFormat> const &preferred_formats)
|
||||
{
|
||||
uint32_t surface_format_count;
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &surface_format_count, nullptr);
|
||||
assert(0 < surface_format_count);
|
||||
std::vector<VkSurfaceFormatKHR> supported_surface_formats(surface_format_count);
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &surface_format_count, supported_surface_formats.data());
|
||||
|
||||
auto it = std::ranges::find_if(supported_surface_formats,
|
||||
[&preferred_formats](VkSurfaceFormatKHR surface_format) {
|
||||
return std::ranges::any_of(preferred_formats,
|
||||
[&surface_format](VkFormat format) { return format == surface_format.format; });
|
||||
});
|
||||
|
||||
// We use the first supported format as a fallback in case none of the preferred formats is available
|
||||
return it != supported_surface_formats.end() ? *it : supported_surface_formats[0];
|
||||
}
|
||||
|
||||
namespace gbuffer
|
||||
{
|
||||
std::vector<LoadStoreInfo> get_load_all_store_swapchain()
|
||||
{
|
||||
// Load every attachment and store only swapchain
|
||||
std::vector<LoadStoreInfo> load_store{4};
|
||||
|
||||
// Swapchain
|
||||
load_store[0].load_op = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
load_store[0].store_op = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
// Depth
|
||||
load_store[1].load_op = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
load_store[1].store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
|
||||
// Albedo
|
||||
load_store[2].load_op = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
load_store[2].store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
|
||||
// Normal
|
||||
load_store[3].load_op = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
load_store[3].store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
|
||||
return load_store;
|
||||
}
|
||||
|
||||
std::vector<LoadStoreInfo> get_clear_all_store_swapchain()
|
||||
{
|
||||
// Clear every attachment and store only swapchain
|
||||
std::vector<LoadStoreInfo> load_store{4};
|
||||
|
||||
// Swapchain
|
||||
load_store[0].load_op = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
load_store[0].store_op = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
// Depth
|
||||
load_store[1].load_op = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
load_store[1].store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
|
||||
// Albedo
|
||||
load_store[2].load_op = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
load_store[2].store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
|
||||
// Normal
|
||||
load_store[3].load_op = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
load_store[3].store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
|
||||
return load_store;
|
||||
}
|
||||
|
||||
std::vector<LoadStoreInfo> get_clear_store_all()
|
||||
{
|
||||
// Clear and store every attachment
|
||||
std::vector<LoadStoreInfo> load_store{4};
|
||||
|
||||
// Swapchain
|
||||
load_store[0].load_op = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
load_store[0].store_op = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
// Depth
|
||||
load_store[1].load_op = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
load_store[1].store_op = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
// Albedo
|
||||
load_store[2].load_op = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
load_store[2].store_op = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
// Normal
|
||||
load_store[3].load_op = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
load_store[3].store_op = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
return load_store;
|
||||
}
|
||||
|
||||
std::vector<VkClearValue> get_clear_value()
|
||||
{
|
||||
// Clear values
|
||||
std::vector<VkClearValue> clear_value{4};
|
||||
clear_value[0].color = {{0.0f, 0.0f, 0.0f, 1.0f}};
|
||||
clear_value[1].depthStencil = {0.0f, ~0U};
|
||||
clear_value[2].color = {{0.0f, 0.0f, 0.0f, 1.0f}};
|
||||
clear_value[3].color = {{0.0f, 0.0f, 0.0f, 1.0f}};
|
||||
|
||||
return clear_value;
|
||||
}
|
||||
} // namespace gbuffer
|
||||
|
||||
uint32_t get_queue_family_index(std::vector<VkQueueFamilyProperties> const &queue_family_properties, VkQueueFlagBits queue_flag)
|
||||
{
|
||||
// Dedicated queue for compute
|
||||
// Try to find a queue family index that supports compute but not graphics
|
||||
if (queue_flag & VK_QUEUE_COMPUTE_BIT)
|
||||
{
|
||||
auto propertyIt = std::ranges::find_if(queue_family_properties,
|
||||
[queue_flag](const VkQueueFamilyProperties &property) { return (property.queueFlags & queue_flag) && !(property.queueFlags & VK_QUEUE_GRAPHICS_BIT); });
|
||||
if (propertyIt != queue_family_properties.end())
|
||||
{
|
||||
return static_cast<uint32_t>(std::distance(queue_family_properties.begin(), propertyIt));
|
||||
}
|
||||
}
|
||||
|
||||
// Dedicated queue for transfer
|
||||
// Try to find a queue family index that supports transfer but not graphics and compute
|
||||
if (queue_flag & VK_QUEUE_TRANSFER_BIT)
|
||||
{
|
||||
auto propertyIt = std::ranges::find_if(queue_family_properties,
|
||||
[queue_flag](const VkQueueFamilyProperties &property) {
|
||||
return (property.queueFlags & queue_flag) && !(property.queueFlags & VK_QUEUE_GRAPHICS_BIT) &&
|
||||
!(property.queueFlags & VK_QUEUE_COMPUTE_BIT);
|
||||
});
|
||||
if (propertyIt != queue_family_properties.end())
|
||||
{
|
||||
return static_cast<uint32_t>(std::distance(queue_family_properties.begin(), propertyIt));
|
||||
}
|
||||
}
|
||||
|
||||
// For other queue types or if no separate compute queue is present, return the first one to support the requested flags
|
||||
auto propertyIt = std::ranges::find_if(
|
||||
queue_family_properties, [queue_flag](const VkQueueFamilyProperties &property) { return (property.queueFlags & queue_flag) == queue_flag; });
|
||||
if (propertyIt != queue_family_properties.end())
|
||||
{
|
||||
return static_cast<uint32_t>(std::distance(queue_family_properties.begin(), propertyIt));
|
||||
}
|
||||
|
||||
throw std::runtime_error("Could not find a matching queue family index");
|
||||
}
|
||||
|
||||
} // namespace vkb
|
||||
@@ -0,0 +1,311 @@
|
||||
/* Copyright (c) 2018-2025, Arm Limited and Contributors
|
||||
* Copyright (c) 2019-2025, Sascha Willems
|
||||
* Copyright (c) 2024-2025, Mobica Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "common/error.h"
|
||||
#include <vk_mem_alloc.h>
|
||||
#include <volk.h>
|
||||
|
||||
#define VK_FLAGS_NONE 0 // Custom define for better code readability
|
||||
|
||||
#define DEFAULT_FENCE_TIMEOUT 100000000000 // Default fence timeout in nanoseconds
|
||||
|
||||
template <class T>
|
||||
using ShaderStageMap = std::map<VkShaderStageFlagBits, T>;
|
||||
|
||||
template <class T>
|
||||
using BindingMap = std::map<uint32_t, std::map<uint32_t, T>>;
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
enum class BindingType
|
||||
{
|
||||
C,
|
||||
Cpp
|
||||
};
|
||||
|
||||
enum class CommandBufferResetMode
|
||||
{
|
||||
ResetPool,
|
||||
ResetIndividually,
|
||||
AlwaysAllocate,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper function to determine if a Vulkan format is depth only.
|
||||
* @param format Vulkan format to check.
|
||||
* @return True if format is a depth only, false otherwise.
|
||||
*/
|
||||
bool is_depth_only_format(VkFormat format);
|
||||
|
||||
/**
|
||||
* @brief Helper function to determine if a Vulkan format is depth with stencil.
|
||||
* @param format Vulkan format to check.
|
||||
* @return True if format is a depth with stencil, false otherwise.
|
||||
*/
|
||||
bool is_depth_stencil_format(VkFormat format);
|
||||
|
||||
/**
|
||||
* @brief Helper function to determine if a Vulkan format is depth.
|
||||
* @param format Vulkan format to check.
|
||||
* @return True if format is a depth, false otherwise.
|
||||
*/
|
||||
bool is_depth_format(VkFormat format);
|
||||
|
||||
/**
|
||||
* @brief Helper function to determine a suitable supported depth format based on a priority list
|
||||
* @param physical_device The physical device to check the depth formats against
|
||||
* @param depth_only (Optional) Wether to include the stencil component in the format or not
|
||||
* @param depth_format_priority_list (Optional) The list of depth formats to prefer over one another
|
||||
* By default we start with the highest precision packed format
|
||||
* @return The valid suited depth format
|
||||
*/
|
||||
VkFormat get_suitable_depth_format(VkPhysicalDevice physical_device,
|
||||
bool depth_only = false,
|
||||
const std::vector<VkFormat> &depth_format_priority_list = {
|
||||
VK_FORMAT_D32_SFLOAT,
|
||||
VK_FORMAT_D24_UNORM_S8_UINT,
|
||||
VK_FORMAT_D16_UNORM});
|
||||
|
||||
/**
|
||||
* @brief Helper function to pick a blendable format from a priority ordered list
|
||||
* @param physical_device The physical device to check the formats against
|
||||
* @param format_priority_list List of formats in order of priority
|
||||
* @return The selected format
|
||||
*/
|
||||
VkFormat choose_blendable_format(VkPhysicalDevice physical_device, const std::vector<VkFormat> &format_priority_list);
|
||||
|
||||
/**
|
||||
* @brief Helper function to check support for linear filtering and adjust its parameters if required
|
||||
* @param physical_device The physical device to check the depth formats against
|
||||
* @param format The format to check against
|
||||
* @param filter The preferred filter to adjust
|
||||
* @param mipmapMode (Optional) The preferred mipmap mode to adjust
|
||||
*/
|
||||
void make_filters_valid(VkPhysicalDevice physical_device, VkFormat format, VkFilter *filter, VkSamplerMipmapMode *mipmapMode = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Helper function to determine if a Vulkan descriptor type is a dynamic storage buffer or dynamic uniform buffer.
|
||||
* @param descriptor_type Vulkan descriptor type to check.
|
||||
* @return True if type is dynamic buffer, false otherwise.
|
||||
*/
|
||||
bool is_dynamic_buffer_descriptor_type(VkDescriptorType descriptor_type);
|
||||
|
||||
/**
|
||||
* @brief Helper function to determine if a Vulkan descriptor type is a buffer (either uniform or storage buffer, dynamic or not).
|
||||
* @param descriptor_type Vulkan descriptor type to check.
|
||||
* @return True if type is buffer, false otherwise.
|
||||
*/
|
||||
bool is_buffer_descriptor_type(VkDescriptorType descriptor_type);
|
||||
|
||||
/**
|
||||
* @brief Helper function to get the bits per pixel of a Vulkan format.
|
||||
* @param format Vulkan format to check.
|
||||
* @return The bits per pixel of the given format, -1 for invalid formats.
|
||||
*/
|
||||
int32_t get_bits_per_pixel(VkFormat format);
|
||||
|
||||
enum class ShadingLanguage
|
||||
{
|
||||
GLSL,
|
||||
HLSL,
|
||||
SLANG,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper function to create a VkShaderModule from a SPIR-V shader file
|
||||
* @param filename The shader location
|
||||
* @param device The logical device
|
||||
* @param stage The shader stage
|
||||
* @return The shader module containing the loaded shader
|
||||
*/
|
||||
VkShaderModule load_shader(const std::string &filename, VkDevice device, VkShaderStageFlagBits stage);
|
||||
|
||||
/**
|
||||
* @brief Helper function to select a VkSurfaceFormatKHR
|
||||
* @param gpu The VkPhysicalDevice to select a format for.
|
||||
* @param surface The VkSurfaceKHR to select a format for.
|
||||
* @param preferred_formats List of preferred VkFormats to use.
|
||||
* @return The preferred VkSurfaceFormatKHR.
|
||||
*/
|
||||
VkSurfaceFormatKHR select_surface_format(VkPhysicalDevice gpu,
|
||||
VkSurfaceKHR surface,
|
||||
std::vector<VkFormat> const &preferred_formats = {
|
||||
VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_A8B8G8R8_SRGB_PACK32});
|
||||
|
||||
/**
|
||||
* @brief Image memory barrier structure used to define
|
||||
* memory access for an image view during command recording.
|
||||
*/
|
||||
struct ImageMemoryBarrier
|
||||
{
|
||||
VkPipelineStageFlags src_stage_mask{VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT};
|
||||
|
||||
VkPipelineStageFlags dst_stage_mask{VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT};
|
||||
|
||||
VkAccessFlags src_access_mask{0};
|
||||
|
||||
VkAccessFlags dst_access_mask{0};
|
||||
|
||||
VkImageLayout old_layout{VK_IMAGE_LAYOUT_UNDEFINED};
|
||||
|
||||
VkImageLayout new_layout{VK_IMAGE_LAYOUT_UNDEFINED};
|
||||
|
||||
uint32_t src_queue_family{VK_QUEUE_FAMILY_IGNORED};
|
||||
|
||||
uint32_t dst_queue_family{VK_QUEUE_FAMILY_IGNORED};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Buffer memory barrier structure used to define
|
||||
* memory access for a buffer during command recording.
|
||||
*/
|
||||
struct BufferMemoryBarrier
|
||||
{
|
||||
VkPipelineStageFlags src_stage_mask{VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT};
|
||||
|
||||
VkPipelineStageFlags dst_stage_mask{VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT};
|
||||
|
||||
VkAccessFlags src_access_mask{0};
|
||||
|
||||
VkAccessFlags dst_access_mask{0};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Put an image memory barrier for a layout transition of an image, using explicitly give transition parameters.
|
||||
* @param command_buffer The VkCommandBuffer to record the barrier.
|
||||
* @param image The VkImage to transition.
|
||||
* @param src_stage_mask The VkPipelineStageFlags to use as source.
|
||||
* @param dst_stage_mask The VkPipelineStageFlags to use as destination.
|
||||
* @param src_access_mask The VkAccessFlags to use as source.
|
||||
* @param dst_access_mask The VkAccessFlags to use as destination.
|
||||
* @param old_layout The VkImageLayout to transition from.
|
||||
* @param new_layout The VkImageLayout to transition to.
|
||||
* @param subresource_range The VkImageSubresourceRange to use with the transition.
|
||||
*/
|
||||
void image_layout_transition(VkCommandBuffer command_buffer,
|
||||
VkImage image,
|
||||
VkPipelineStageFlags src_stage_mask,
|
||||
VkPipelineStageFlags dst_stage_mask,
|
||||
VkAccessFlags src_access_mask,
|
||||
VkAccessFlags dst_access_mask,
|
||||
VkImageLayout old_layout,
|
||||
VkImageLayout new_layout,
|
||||
VkImageSubresourceRange const &subresource_range);
|
||||
|
||||
/**
|
||||
* @brief Put an image memory barrier for a layout transition of an image, on a given subresource range.
|
||||
*
|
||||
* The src_stage_mask, dst_stage_mask, src_access_mask, and dst_access_mask used are determined from old_layout and new_layout.
|
||||
*
|
||||
* @param command_buffer The VkCommandBuffer to record the barrier.
|
||||
* @param image The VkImage to transition.
|
||||
* @param old_layout The VkImageLayout to transition from.
|
||||
* @param new_layout The VkImageLayout to transition to.
|
||||
* @param subresource_range The VkImageSubresourceRange to use with the transition.
|
||||
*/
|
||||
void image_layout_transition(VkCommandBuffer command_buffer,
|
||||
VkImage image,
|
||||
VkImageLayout old_layout,
|
||||
VkImageLayout new_layout,
|
||||
VkImageSubresourceRange const &subresource_range);
|
||||
|
||||
/**
|
||||
* @brief Put an image memory barrier for a layout transition of an image, on a fixed subresource with first mip level and layer.
|
||||
*
|
||||
* The src_stage_mask, dst_stage_mask, src_access_mask, and dst_access_mask used are determined from old_layout and new_layout.
|
||||
*
|
||||
* @param command_buffer The VkCommandBuffer to record the barrier.
|
||||
* @param image The VkImage to transition.
|
||||
* @param old_layout The VkImageLayout to transition from.
|
||||
* @param new_layout The VkImageLayout to transition to.
|
||||
*/
|
||||
void image_layout_transition(VkCommandBuffer command_buffer,
|
||||
VkImage image,
|
||||
VkImageLayout old_layout,
|
||||
VkImageLayout new_layout);
|
||||
|
||||
/**
|
||||
* @brief Put an image memory barrier for a layout transition of a vector of images, with a given subresource range per image.
|
||||
*
|
||||
* The src_stage_mask, dst_stage_mask, src_access_mask, and dst_access_mask used are determined from old_layout and new_layout.
|
||||
*
|
||||
* @param command_buffer The VkCommandBuffer to record the barrier.
|
||||
* @param imagesAndRanges The images to transition, with accompanying subresource ranges.
|
||||
* @param old_layout The VkImageLayout to transition from.
|
||||
* @param new_layout The VkImageLayout to transition to.
|
||||
*/
|
||||
void image_layout_transition(VkCommandBuffer command_buffer,
|
||||
std::vector<std::pair<VkImage, VkImageSubresourceRange>> const &imagesAndRanges,
|
||||
VkImageLayout old_layout,
|
||||
VkImageLayout new_layout);
|
||||
|
||||
/**
|
||||
* @brief Helper functions for compression controls
|
||||
*/
|
||||
std::vector<VkImageCompressionFixedRateFlagBitsEXT> fixed_rate_compression_flags_to_vector(VkImageCompressionFixedRateFlagsEXT flags);
|
||||
|
||||
VkImageCompressionPropertiesEXT query_supported_fixed_rate_compression(VkPhysicalDevice gpu, const VkImageCreateInfo &create_info);
|
||||
|
||||
VkImageCompressionPropertiesEXT query_applied_compression(VkDevice device, VkImage image);
|
||||
|
||||
/**
|
||||
* @brief Load and store info for a render pass attachment.
|
||||
*/
|
||||
struct LoadStoreInfo
|
||||
{
|
||||
VkAttachmentLoadOp load_op = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
|
||||
VkAttachmentStoreOp store_op = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
};
|
||||
|
||||
namespace gbuffer
|
||||
{
|
||||
/**
|
||||
* @return Load store info to load all and store only the swapchain
|
||||
*/
|
||||
std::vector<LoadStoreInfo> get_load_all_store_swapchain();
|
||||
|
||||
/**
|
||||
* @return Load store info to clear all and store only the swapchain
|
||||
*/
|
||||
std::vector<LoadStoreInfo> get_clear_all_store_swapchain();
|
||||
|
||||
/**
|
||||
* @return Load store info to clear and store all images
|
||||
*/
|
||||
std::vector<LoadStoreInfo> get_clear_store_all();
|
||||
|
||||
/**
|
||||
* @return Default clear values for the G-buffer
|
||||
*/
|
||||
std::vector<VkClearValue> get_clear_value();
|
||||
} // namespace gbuffer
|
||||
|
||||
uint32_t get_queue_family_index(std::vector<VkQueueFamilyProperties> const &queue_family_properties, VkQueueFlagBits queue_flag);
|
||||
|
||||
} // namespace vkb
|
||||
@@ -0,0 +1,667 @@
|
||||
/* Copyright (c) 2019-2024, Sascha Willems
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "volk.h"
|
||||
#include <vector>
|
||||
|
||||
namespace vkb
|
||||
{
|
||||
namespace initializers
|
||||
{
|
||||
inline VkMemoryAllocateInfo memory_allocate_info()
|
||||
{
|
||||
VkMemoryAllocateInfo memory_allocation{};
|
||||
memory_allocation.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
return memory_allocation;
|
||||
}
|
||||
|
||||
inline VkMappedMemoryRange mapped_memory_range()
|
||||
{
|
||||
VkMappedMemoryRange mapped_memory_range{};
|
||||
mapped_memory_range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
||||
return mapped_memory_range;
|
||||
}
|
||||
|
||||
inline VkCommandBufferAllocateInfo command_buffer_allocate_info(
|
||||
VkCommandPool command_pool,
|
||||
VkCommandBufferLevel level,
|
||||
uint32_t buffer_count)
|
||||
{
|
||||
VkCommandBufferAllocateInfo command_buffer_allocate_info{};
|
||||
command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
command_buffer_allocate_info.commandPool = command_pool;
|
||||
command_buffer_allocate_info.level = level;
|
||||
command_buffer_allocate_info.commandBufferCount = buffer_count;
|
||||
return command_buffer_allocate_info;
|
||||
}
|
||||
|
||||
inline VkCommandPoolCreateInfo command_pool_create_info()
|
||||
{
|
||||
VkCommandPoolCreateInfo command_pool_create_info{};
|
||||
command_pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
return command_pool_create_info;
|
||||
}
|
||||
|
||||
inline VkCommandBufferBeginInfo command_buffer_begin_info()
|
||||
{
|
||||
VkCommandBufferBeginInfo cmdBufferBeginInfo{};
|
||||
cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
return cmdBufferBeginInfo;
|
||||
}
|
||||
|
||||
inline VkCommandBufferInheritanceInfo command_buffer_inheritance_info()
|
||||
{
|
||||
VkCommandBufferInheritanceInfo command_buffer_inheritance_info{};
|
||||
command_buffer_inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
|
||||
return command_buffer_inheritance_info;
|
||||
}
|
||||
|
||||
inline VkRenderPassBeginInfo render_pass_begin_info()
|
||||
{
|
||||
VkRenderPassBeginInfo render_pass_begin_info{};
|
||||
render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
return render_pass_begin_info;
|
||||
}
|
||||
|
||||
inline VkRenderPassCreateInfo render_pass_create_info()
|
||||
{
|
||||
VkRenderPassCreateInfo render_pass_create_info{};
|
||||
render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
return render_pass_create_info;
|
||||
}
|
||||
|
||||
/** @brief Initialize rendering_attachment_info */
|
||||
inline VkRenderingAttachmentInfoKHR rendering_attachment_info()
|
||||
{
|
||||
VkRenderingAttachmentInfoKHR attachment_info{};
|
||||
attachment_info.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
|
||||
attachment_info.pNext = VK_NULL_HANDLE;
|
||||
return attachment_info;
|
||||
}
|
||||
|
||||
/** @brief Initialize VkRenderingInfoKHR, e.g. for use with dynamic rendering extension */
|
||||
inline VkRenderingInfoKHR rendering_info(VkRect2D render_area = {},
|
||||
uint32_t color_attachment_count = 0,
|
||||
const VkRenderingAttachmentInfoKHR *pColorAttachments = VK_NULL_HANDLE,
|
||||
VkRenderingFlagsKHR flags = 0)
|
||||
{
|
||||
VkRenderingInfoKHR rendering_info = {};
|
||||
rendering_info.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR;
|
||||
rendering_info.pNext = VK_NULL_HANDLE;
|
||||
rendering_info.flags = flags;
|
||||
rendering_info.renderArea = render_area;
|
||||
rendering_info.layerCount = 0;
|
||||
rendering_info.viewMask = 0;
|
||||
rendering_info.colorAttachmentCount = color_attachment_count;
|
||||
rendering_info.pColorAttachments = pColorAttachments;
|
||||
rendering_info.pDepthAttachment = VK_NULL_HANDLE;
|
||||
rendering_info.pStencilAttachment = VK_NULL_HANDLE;
|
||||
return rendering_info;
|
||||
}
|
||||
|
||||
/** @brief Initialize an image memory barrier with no image transfer ownership */
|
||||
inline VkImageMemoryBarrier image_memory_barrier()
|
||||
{
|
||||
VkImageMemoryBarrier image_memory_barrier{};
|
||||
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
return image_memory_barrier;
|
||||
}
|
||||
|
||||
/** @brief Initialize a buffer memory barrier with no image transfer ownership */
|
||||
inline VkBufferMemoryBarrier buffer_memory_barrier()
|
||||
{
|
||||
VkBufferMemoryBarrier buffer_memory_barrier{};
|
||||
buffer_memory_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
|
||||
buffer_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
buffer_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
return buffer_memory_barrier;
|
||||
}
|
||||
|
||||
inline VkMemoryBarrier memory_barrier()
|
||||
{
|
||||
VkMemoryBarrier memory_barrier{};
|
||||
memory_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
|
||||
return memory_barrier;
|
||||
}
|
||||
|
||||
inline VkImageCreateInfo image_create_info()
|
||||
{
|
||||
VkImageCreateInfo image_create_info{};
|
||||
image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
return image_create_info;
|
||||
}
|
||||
|
||||
inline VkSamplerCreateInfo sampler_create_info()
|
||||
{
|
||||
VkSamplerCreateInfo sampler_create_info{};
|
||||
sampler_create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||
sampler_create_info.maxAnisotropy = 1.0f;
|
||||
return sampler_create_info;
|
||||
}
|
||||
|
||||
inline VkImageViewCreateInfo image_view_create_info()
|
||||
{
|
||||
VkImageViewCreateInfo image_view_create_info{};
|
||||
image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
return image_view_create_info;
|
||||
}
|
||||
|
||||
inline VkFramebufferCreateInfo framebuffer_create_info()
|
||||
{
|
||||
VkFramebufferCreateInfo framebuffer_create_info{};
|
||||
framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
return framebuffer_create_info;
|
||||
}
|
||||
|
||||
inline VkSemaphoreCreateInfo semaphore_create_info()
|
||||
{
|
||||
VkSemaphoreCreateInfo semaphore_create_info{};
|
||||
semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
return semaphore_create_info;
|
||||
}
|
||||
|
||||
inline VkFenceCreateInfo fence_create_info(VkFenceCreateFlags flags = 0)
|
||||
{
|
||||
VkFenceCreateInfo fence_create_info{};
|
||||
fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fence_create_info.flags = flags;
|
||||
return fence_create_info;
|
||||
}
|
||||
|
||||
inline VkEventCreateInfo event_create_info()
|
||||
{
|
||||
VkEventCreateInfo event_create_info{};
|
||||
event_create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
|
||||
return event_create_info;
|
||||
}
|
||||
|
||||
inline VkSubmitInfo submit_info()
|
||||
{
|
||||
VkSubmitInfo submit_info{};
|
||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
return submit_info;
|
||||
}
|
||||
|
||||
inline VkViewport viewport(
|
||||
float width,
|
||||
float height,
|
||||
float min_depth,
|
||||
float max_depth)
|
||||
{
|
||||
VkViewport viewport{};
|
||||
viewport.width = width;
|
||||
viewport.height = height;
|
||||
viewport.minDepth = min_depth;
|
||||
viewport.maxDepth = max_depth;
|
||||
return viewport;
|
||||
}
|
||||
|
||||
inline VkRect2D rect2D(
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
int32_t offset_x,
|
||||
int32_t offset_y)
|
||||
{
|
||||
VkRect2D rect2D{};
|
||||
rect2D.extent.width = width;
|
||||
rect2D.extent.height = height;
|
||||
rect2D.offset.x = offset_x;
|
||||
rect2D.offset.y = offset_y;
|
||||
return rect2D;
|
||||
}
|
||||
|
||||
inline VkBufferCreateInfo buffer_create_info()
|
||||
{
|
||||
VkBufferCreateInfo buffer_create_info{};
|
||||
buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
return buffer_create_info;
|
||||
}
|
||||
|
||||
inline VkBufferCreateInfo buffer_create_info(
|
||||
VkBufferUsageFlags usage,
|
||||
VkDeviceSize size)
|
||||
{
|
||||
VkBufferCreateInfo buffer_create_info{};
|
||||
buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
buffer_create_info.usage = usage;
|
||||
buffer_create_info.size = size;
|
||||
return buffer_create_info;
|
||||
}
|
||||
|
||||
inline VkDescriptorPoolCreateInfo descriptor_pool_create_info(
|
||||
uint32_t count,
|
||||
VkDescriptorPoolSize *pool_sizes,
|
||||
uint32_t max_sets)
|
||||
{
|
||||
VkDescriptorPoolCreateInfo descriptor_pool_info{};
|
||||
descriptor_pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
descriptor_pool_info.poolSizeCount = count;
|
||||
descriptor_pool_info.pPoolSizes = pool_sizes;
|
||||
descriptor_pool_info.maxSets = max_sets;
|
||||
return descriptor_pool_info;
|
||||
}
|
||||
|
||||
inline VkDescriptorPoolCreateInfo descriptor_pool_create_info(
|
||||
const std::vector<VkDescriptorPoolSize> &pool_sizes,
|
||||
uint32_t max_sets)
|
||||
{
|
||||
VkDescriptorPoolCreateInfo descriptor_pool_info{};
|
||||
descriptor_pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
descriptor_pool_info.poolSizeCount = static_cast<uint32_t>(pool_sizes.size());
|
||||
descriptor_pool_info.pPoolSizes = pool_sizes.data();
|
||||
descriptor_pool_info.maxSets = max_sets;
|
||||
return descriptor_pool_info;
|
||||
}
|
||||
|
||||
inline VkDescriptorPoolSize descriptor_pool_size(
|
||||
VkDescriptorType type,
|
||||
uint32_t count)
|
||||
{
|
||||
VkDescriptorPoolSize descriptor_pool_size{};
|
||||
descriptor_pool_size.type = type;
|
||||
descriptor_pool_size.descriptorCount = count;
|
||||
return descriptor_pool_size;
|
||||
}
|
||||
|
||||
inline VkDescriptorSetLayoutBinding descriptor_set_layout_binding(
|
||||
VkDescriptorType type,
|
||||
VkShaderStageFlags flags,
|
||||
uint32_t binding,
|
||||
uint32_t count = 1)
|
||||
{
|
||||
VkDescriptorSetLayoutBinding set_layout_binding{};
|
||||
set_layout_binding.descriptorType = type;
|
||||
set_layout_binding.stageFlags = flags;
|
||||
set_layout_binding.binding = binding;
|
||||
set_layout_binding.descriptorCount = count;
|
||||
return set_layout_binding;
|
||||
}
|
||||
|
||||
inline VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_info(
|
||||
const VkDescriptorSetLayoutBinding *bindings,
|
||||
uint32_t binding_count)
|
||||
{
|
||||
VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_info{};
|
||||
descriptor_set_layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
descriptor_set_layout_create_info.pBindings = bindings;
|
||||
descriptor_set_layout_create_info.bindingCount = binding_count;
|
||||
return descriptor_set_layout_create_info;
|
||||
}
|
||||
|
||||
inline VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_info(
|
||||
const std::vector<VkDescriptorSetLayoutBinding> &bindings)
|
||||
{
|
||||
VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_info{};
|
||||
descriptor_set_layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
descriptor_set_layout_create_info.pBindings = bindings.data();
|
||||
descriptor_set_layout_create_info.bindingCount = static_cast<uint32_t>(bindings.size());
|
||||
return descriptor_set_layout_create_info;
|
||||
}
|
||||
|
||||
inline VkPipelineLayoutCreateInfo pipeline_layout_create_info(
|
||||
const VkDescriptorSetLayout *set_layouts,
|
||||
uint32_t set_layout_count = 1)
|
||||
{
|
||||
VkPipelineLayoutCreateInfo pipeline_layout_create_info{};
|
||||
pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
pipeline_layout_create_info.setLayoutCount = set_layout_count;
|
||||
pipeline_layout_create_info.pSetLayouts = set_layouts;
|
||||
return pipeline_layout_create_info;
|
||||
}
|
||||
|
||||
inline VkPipelineLayoutCreateInfo pipeline_layout_create_info(
|
||||
uint32_t set_layout_count = 1)
|
||||
{
|
||||
VkPipelineLayoutCreateInfo pipeline_layout_create_info{};
|
||||
pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
pipeline_layout_create_info.setLayoutCount = set_layout_count;
|
||||
return pipeline_layout_create_info;
|
||||
}
|
||||
|
||||
inline VkDescriptorSetAllocateInfo descriptor_set_allocate_info(
|
||||
VkDescriptorPool descriptor_pool,
|
||||
const VkDescriptorSetLayout *set_layouts,
|
||||
uint32_t descriptor_set_count)
|
||||
{
|
||||
VkDescriptorSetAllocateInfo descriptor_set_allocate_info{};
|
||||
descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
descriptor_set_allocate_info.descriptorPool = descriptor_pool;
|
||||
descriptor_set_allocate_info.pSetLayouts = set_layouts;
|
||||
descriptor_set_allocate_info.descriptorSetCount = descriptor_set_count;
|
||||
return descriptor_set_allocate_info;
|
||||
}
|
||||
|
||||
inline VkDescriptorImageInfo descriptor_image_info(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout)
|
||||
{
|
||||
VkDescriptorImageInfo descriptor_image_info{};
|
||||
descriptor_image_info.sampler = sampler;
|
||||
descriptor_image_info.imageView = image_view;
|
||||
descriptor_image_info.imageLayout = image_layout;
|
||||
return descriptor_image_info;
|
||||
}
|
||||
|
||||
inline VkWriteDescriptorSet write_descriptor_set(
|
||||
VkDescriptorSet dst_set,
|
||||
VkDescriptorType type,
|
||||
uint32_t binding,
|
||||
VkDescriptorBufferInfo *buffer_info,
|
||||
uint32_t descriptor_count = 1)
|
||||
{
|
||||
VkWriteDescriptorSet write_descriptor_set{};
|
||||
write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write_descriptor_set.dstSet = dst_set;
|
||||
write_descriptor_set.descriptorType = type;
|
||||
write_descriptor_set.dstBinding = binding;
|
||||
write_descriptor_set.pBufferInfo = buffer_info;
|
||||
write_descriptor_set.descriptorCount = descriptor_count;
|
||||
return write_descriptor_set;
|
||||
}
|
||||
|
||||
inline VkWriteDescriptorSet write_descriptor_set(
|
||||
VkDescriptorSet dst_set,
|
||||
VkDescriptorType type,
|
||||
uint32_t binding,
|
||||
VkDescriptorImageInfo *image_info,
|
||||
uint32_t descriptor_count = 1)
|
||||
{
|
||||
VkWriteDescriptorSet write_descriptor_set{};
|
||||
write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write_descriptor_set.dstSet = dst_set;
|
||||
write_descriptor_set.descriptorType = type;
|
||||
write_descriptor_set.dstBinding = binding;
|
||||
write_descriptor_set.pImageInfo = image_info;
|
||||
write_descriptor_set.descriptorCount = descriptor_count;
|
||||
return write_descriptor_set;
|
||||
}
|
||||
|
||||
inline VkVertexInputBindingDescription vertex_input_binding_description(
|
||||
uint32_t binding,
|
||||
uint32_t stride,
|
||||
VkVertexInputRate input_rate)
|
||||
{
|
||||
VkVertexInputBindingDescription vertex_input_binding_description{};
|
||||
vertex_input_binding_description.binding = binding;
|
||||
vertex_input_binding_description.stride = stride;
|
||||
vertex_input_binding_description.inputRate = input_rate;
|
||||
return vertex_input_binding_description;
|
||||
}
|
||||
|
||||
inline VkVertexInputBindingDescription2EXT vertex_input_binding_description2ext(
|
||||
uint32_t binding,
|
||||
uint32_t stride,
|
||||
VkVertexInputRate input_rate,
|
||||
uint32_t divisor)
|
||||
{
|
||||
VkVertexInputBindingDescription2EXT vertex_input_binding_description2ext{};
|
||||
vertex_input_binding_description2ext.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT;
|
||||
vertex_input_binding_description2ext.binding = binding;
|
||||
vertex_input_binding_description2ext.stride = stride;
|
||||
vertex_input_binding_description2ext.inputRate = input_rate;
|
||||
vertex_input_binding_description2ext.divisor = divisor;
|
||||
return vertex_input_binding_description2ext;
|
||||
}
|
||||
|
||||
inline VkVertexInputAttributeDescription vertex_input_attribute_description(
|
||||
uint32_t binding,
|
||||
uint32_t location,
|
||||
VkFormat format,
|
||||
uint32_t offset)
|
||||
{
|
||||
VkVertexInputAttributeDescription vertex_input_attribute_description{};
|
||||
vertex_input_attribute_description.location = location;
|
||||
vertex_input_attribute_description.binding = binding;
|
||||
vertex_input_attribute_description.format = format;
|
||||
vertex_input_attribute_description.offset = offset;
|
||||
return vertex_input_attribute_description;
|
||||
}
|
||||
|
||||
inline VkVertexInputAttributeDescription2EXT vertex_input_attribute_description2ext(
|
||||
uint32_t binding,
|
||||
uint32_t location,
|
||||
VkFormat format,
|
||||
uint32_t offset)
|
||||
{
|
||||
VkVertexInputAttributeDescription2EXT vertex_input_attribute_description2ext{};
|
||||
vertex_input_attribute_description2ext.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT;
|
||||
vertex_input_attribute_description2ext.location = location;
|
||||
vertex_input_attribute_description2ext.binding = binding;
|
||||
vertex_input_attribute_description2ext.format = format;
|
||||
vertex_input_attribute_description2ext.offset = offset;
|
||||
return vertex_input_attribute_description2ext;
|
||||
}
|
||||
|
||||
inline VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_state_create_info()
|
||||
{
|
||||
VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_state_create_info{};
|
||||
pipeline_vertex_input_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
return pipeline_vertex_input_state_create_info;
|
||||
}
|
||||
|
||||
inline VkPipelineInputAssemblyStateCreateInfo pipeline_input_assembly_state_create_info(
|
||||
VkPrimitiveTopology topology,
|
||||
VkPipelineInputAssemblyStateCreateFlags flags,
|
||||
VkBool32 primitive_restart_enable)
|
||||
{
|
||||
VkPipelineInputAssemblyStateCreateInfo pipeline_input_assembly_state_create_info{};
|
||||
pipeline_input_assembly_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||
pipeline_input_assembly_state_create_info.topology = topology;
|
||||
pipeline_input_assembly_state_create_info.flags = flags;
|
||||
pipeline_input_assembly_state_create_info.primitiveRestartEnable = primitive_restart_enable;
|
||||
return pipeline_input_assembly_state_create_info;
|
||||
}
|
||||
|
||||
inline VkPipelineRasterizationStateCreateInfo pipeline_rasterization_state_create_info(
|
||||
VkPolygonMode polygon_mode,
|
||||
VkCullModeFlags cull_mode,
|
||||
VkFrontFace front_face,
|
||||
VkPipelineRasterizationStateCreateFlags flags = 0)
|
||||
{
|
||||
VkPipelineRasterizationStateCreateInfo pipeline_rasterization_state_create_info{};
|
||||
pipeline_rasterization_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
pipeline_rasterization_state_create_info.polygonMode = polygon_mode;
|
||||
pipeline_rasterization_state_create_info.cullMode = cull_mode;
|
||||
pipeline_rasterization_state_create_info.frontFace = front_face;
|
||||
pipeline_rasterization_state_create_info.flags = flags;
|
||||
pipeline_rasterization_state_create_info.depthClampEnable = VK_FALSE;
|
||||
pipeline_rasterization_state_create_info.lineWidth = 1.0f;
|
||||
return pipeline_rasterization_state_create_info;
|
||||
}
|
||||
|
||||
inline VkPipelineColorBlendAttachmentState pipeline_color_blend_attachment_state(
|
||||
VkColorComponentFlags color_write_mask,
|
||||
VkBool32 blend_enable)
|
||||
{
|
||||
VkPipelineColorBlendAttachmentState pipeline_color_blend_attachment_state{};
|
||||
pipeline_color_blend_attachment_state.colorWriteMask = color_write_mask;
|
||||
pipeline_color_blend_attachment_state.blendEnable = blend_enable;
|
||||
return pipeline_color_blend_attachment_state;
|
||||
}
|
||||
|
||||
inline VkPipelineColorBlendStateCreateInfo pipeline_color_blend_state_create_info(
|
||||
uint32_t attachment_count,
|
||||
const VkPipelineColorBlendAttachmentState *attachments)
|
||||
{
|
||||
VkPipelineColorBlendStateCreateInfo pipeline_color_blend_state_create_info{};
|
||||
pipeline_color_blend_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||
pipeline_color_blend_state_create_info.attachmentCount = attachment_count;
|
||||
pipeline_color_blend_state_create_info.pAttachments = attachments;
|
||||
return pipeline_color_blend_state_create_info;
|
||||
}
|
||||
|
||||
inline VkPipelineDepthStencilStateCreateInfo pipeline_depth_stencil_state_create_info(
|
||||
VkBool32 depth_test_enable,
|
||||
VkBool32 depth_write_enable,
|
||||
VkCompareOp depth_compare_op)
|
||||
{
|
||||
VkPipelineDepthStencilStateCreateInfo pipeline_depth_stencil_state_create_info{};
|
||||
pipeline_depth_stencil_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||
pipeline_depth_stencil_state_create_info.depthTestEnable = depth_test_enable;
|
||||
pipeline_depth_stencil_state_create_info.depthWriteEnable = depth_write_enable;
|
||||
pipeline_depth_stencil_state_create_info.depthCompareOp = depth_compare_op;
|
||||
pipeline_depth_stencil_state_create_info.front = pipeline_depth_stencil_state_create_info.back;
|
||||
pipeline_depth_stencil_state_create_info.back.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||
return pipeline_depth_stencil_state_create_info;
|
||||
}
|
||||
|
||||
inline VkPipelineViewportStateCreateInfo pipeline_viewport_state_create_info(
|
||||
uint32_t viewport_count,
|
||||
uint32_t scissor_count,
|
||||
VkPipelineViewportStateCreateFlags flags = 0)
|
||||
{
|
||||
VkPipelineViewportStateCreateInfo pipeline_viewport_state_create_info{};
|
||||
pipeline_viewport_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||
pipeline_viewport_state_create_info.viewportCount = viewport_count;
|
||||
pipeline_viewport_state_create_info.scissorCount = scissor_count;
|
||||
pipeline_viewport_state_create_info.flags = flags;
|
||||
return pipeline_viewport_state_create_info;
|
||||
}
|
||||
|
||||
inline VkPipelineMultisampleStateCreateInfo pipeline_multisample_state_create_info(
|
||||
VkSampleCountFlagBits rasterization_samples,
|
||||
VkPipelineMultisampleStateCreateFlags flags = 0)
|
||||
{
|
||||
VkPipelineMultisampleStateCreateInfo pipeline_multisample_state_create_info{};
|
||||
pipeline_multisample_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||
pipeline_multisample_state_create_info.rasterizationSamples = rasterization_samples;
|
||||
pipeline_multisample_state_create_info.flags = flags;
|
||||
return pipeline_multisample_state_create_info;
|
||||
}
|
||||
|
||||
inline VkPipelineDynamicStateCreateInfo pipeline_dynamic_state_create_info(
|
||||
const VkDynamicState *dynamic_states,
|
||||
uint32_t dynamicStateCount,
|
||||
VkPipelineDynamicStateCreateFlags flags = 0)
|
||||
{
|
||||
VkPipelineDynamicStateCreateInfo pipeline_dynamic_state_create_info{};
|
||||
pipeline_dynamic_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||
pipeline_dynamic_state_create_info.pDynamicStates = dynamic_states;
|
||||
pipeline_dynamic_state_create_info.dynamicStateCount = dynamicStateCount;
|
||||
pipeline_dynamic_state_create_info.flags = flags;
|
||||
return pipeline_dynamic_state_create_info;
|
||||
}
|
||||
|
||||
inline VkPipelineDynamicStateCreateInfo pipeline_dynamic_state_create_info(
|
||||
const std::vector<VkDynamicState> &dynamic_states,
|
||||
VkPipelineDynamicStateCreateFlags flags = 0)
|
||||
{
|
||||
VkPipelineDynamicStateCreateInfo pipeline_dynamic_state_create_info{};
|
||||
pipeline_dynamic_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||
pipeline_dynamic_state_create_info.pDynamicStates = dynamic_states.data();
|
||||
pipeline_dynamic_state_create_info.dynamicStateCount = static_cast<uint32_t>(dynamic_states.size());
|
||||
pipeline_dynamic_state_create_info.flags = flags;
|
||||
return pipeline_dynamic_state_create_info;
|
||||
}
|
||||
|
||||
inline VkPipelineTessellationStateCreateInfo pipeline_tessellation_state_create_info(uint32_t patch_control_points)
|
||||
{
|
||||
VkPipelineTessellationStateCreateInfo pipeline_tessellation_state_create_info{};
|
||||
pipeline_tessellation_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
|
||||
pipeline_tessellation_state_create_info.patchControlPoints = patch_control_points;
|
||||
return pipeline_tessellation_state_create_info;
|
||||
}
|
||||
|
||||
inline VkGraphicsPipelineCreateInfo pipeline_create_info(
|
||||
VkPipelineLayout layout,
|
||||
VkRenderPass render_pass,
|
||||
VkPipelineCreateFlags flags = 0)
|
||||
{
|
||||
VkGraphicsPipelineCreateInfo pipeline_create_info{};
|
||||
pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||
pipeline_create_info.layout = layout;
|
||||
pipeline_create_info.renderPass = render_pass;
|
||||
pipeline_create_info.flags = flags;
|
||||
pipeline_create_info.basePipelineIndex = -1;
|
||||
pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE;
|
||||
return pipeline_create_info;
|
||||
}
|
||||
|
||||
inline VkGraphicsPipelineCreateInfo pipeline_create_info()
|
||||
{
|
||||
VkGraphicsPipelineCreateInfo pipeline_create_info{};
|
||||
pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||
pipeline_create_info.basePipelineIndex = -1;
|
||||
pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE;
|
||||
return pipeline_create_info;
|
||||
}
|
||||
|
||||
inline VkComputePipelineCreateInfo compute_pipeline_create_info(
|
||||
VkPipelineLayout layout,
|
||||
VkPipelineCreateFlags flags = 0)
|
||||
{
|
||||
VkComputePipelineCreateInfo compute_pipeline_create_info{};
|
||||
compute_pipeline_create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
|
||||
compute_pipeline_create_info.layout = layout;
|
||||
compute_pipeline_create_info.flags = flags;
|
||||
return compute_pipeline_create_info;
|
||||
}
|
||||
|
||||
inline VkPushConstantRange push_constant_range(
|
||||
VkShaderStageFlags stage_flags,
|
||||
uint32_t size,
|
||||
uint32_t offset)
|
||||
{
|
||||
VkPushConstantRange push_constant_range{};
|
||||
push_constant_range.stageFlags = stage_flags;
|
||||
push_constant_range.offset = offset;
|
||||
push_constant_range.size = size;
|
||||
return push_constant_range;
|
||||
}
|
||||
|
||||
inline VkBindSparseInfo bind_sparse_info()
|
||||
{
|
||||
VkBindSparseInfo bind_sparse_info{};
|
||||
bind_sparse_info.sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO;
|
||||
return bind_sparse_info;
|
||||
}
|
||||
|
||||
/** @brief Initialize a map entry for a shader specialization constant */
|
||||
inline VkSpecializationMapEntry specialization_map_entry(uint32_t constant_id, uint32_t offset, size_t size)
|
||||
{
|
||||
VkSpecializationMapEntry specialization_map_entry{};
|
||||
specialization_map_entry.constantID = constant_id;
|
||||
specialization_map_entry.offset = offset;
|
||||
specialization_map_entry.size = size;
|
||||
return specialization_map_entry;
|
||||
}
|
||||
|
||||
/** @brief Initialize a specialization constant info structure to pass to a shader stage */
|
||||
inline VkSpecializationInfo specialization_info(uint32_t map_entry_count, const VkSpecializationMapEntry *map_entries, size_t data_size, const void *data)
|
||||
{
|
||||
VkSpecializationInfo specialization_info{};
|
||||
specialization_info.mapEntryCount = map_entry_count;
|
||||
specialization_info.pMapEntries = map_entries;
|
||||
specialization_info.dataSize = data_size;
|
||||
specialization_info.pData = data;
|
||||
return specialization_info;
|
||||
}
|
||||
|
||||
inline VkTimelineSemaphoreSubmitInfo timeline_semaphore_submit_info(uint32_t wait_value_count, uint64_t *wait_values, uint32_t signal_value_count, uint64_t *signal_values)
|
||||
{
|
||||
return VkTimelineSemaphoreSubmitInfo{
|
||||
VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
|
||||
NULL,
|
||||
wait_value_count,
|
||||
wait_values,
|
||||
signal_value_count,
|
||||
signal_values};
|
||||
}
|
||||
} // namespace initializers
|
||||
} // namespace vkb
|
||||
Reference in New Issue
Block a user