Files
Vulkan-Samples/framework/core/vulkan_resource.h
T
2025-09-04 10:54:47 +08:00

236 lines
7.4 KiB
C++

/* Copyright (c) 2021-2025, Arm Limited and Contributors
* Copyright (c) 2024-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/debug.h"
#include "vulkan_type_mapping.h"
#include <utility>
#include <vulkan/vulkan.hpp>
namespace vkb
{
namespace core
{
template <vkb::BindingType bindingType>
class Device;
using DeviceC = Device<vkb::BindingType::C>;
using DeviceCpp = Device<vkb::BindingType::Cpp>;
/// Inherit this for any Vulkan object with a handle of type `Handle`.
///
/// This allows the derived class to store a Vulkan handle, and also a pointer to the parent vkb::Device.
/// It also allows to set a debug name for any Vulkan object.
template <vkb::BindingType bindingType, typename Handle>
class VulkanResource
{
public:
// we always want to store a vk::Handle as a resource, so we have to figure out that type, depending on the BindingType!
using ResourceType = typename vkb::VulkanTypeMapping<bindingType, Handle>::Type;
public:
using ObjectType = typename std::conditional<bindingType == vkb::BindingType::Cpp, vk::ObjectType, VkObjectType>::type;
VulkanResource(Handle handle = nullptr, Device<bindingType> *device_ = nullptr);
VulkanResource(const VulkanResource &) = delete;
VulkanResource &operator=(const VulkanResource &) = delete;
VulkanResource(VulkanResource &&other);
VulkanResource &operator=(VulkanResource &&other);
virtual ~VulkanResource() = default;
const std::string &get_debug_name() const;
vkb::core::Device<bindingType> &get_device();
vkb::core::Device<bindingType> const &get_device() const;
Handle &get_handle();
const Handle &get_handle() const;
uint64_t get_handle_u64() const;
ObjectType get_object_type() const;
ResourceType const &get_resource() const;
bool has_device() const;
bool has_handle() const;
void set_debug_name(const std::string &name);
void set_handle(Handle hdl);
private:
std::string debug_name;
vkb::core::DeviceCpp *device;
ResourceType handle;
};
template <typename Handle>
using VulkanResourceC = VulkanResource<vkb::BindingType::C, Handle>;
template <typename Handle>
using VulkanResourceCpp = VulkanResource<vkb::BindingType::Cpp, Handle>;
template <vkb::BindingType bindingType, typename Handle>
inline VulkanResource<bindingType, Handle>::VulkanResource(Handle handle_, Device<bindingType> *device_) :
handle{handle_}
{
if constexpr (bindingType == vkb::BindingType::Cpp)
{
device = device_;
}
else
{
device = reinterpret_cast<vkb::core::DeviceCpp *>(device_);
}
}
template <vkb::BindingType bindingType, typename Handle>
inline VulkanResource<bindingType, Handle>::VulkanResource(VulkanResource &&other) :
handle(std::exchange(other.handle, {})),
device(std::exchange(other.device, {})),
debug_name(std::exchange(other.debug_name, {}))
{}
template <vkb::BindingType bindingType, typename Handle>
inline VulkanResource<bindingType, Handle> &VulkanResource<bindingType, Handle>::operator=(VulkanResource &&other)
{
handle = std::exchange(other.handle, {});
device = std::exchange(other.device, {});
debug_name = std::exchange(other.debug_name, {});
return *this;
}
template <vkb::BindingType bindingType, typename Handle>
inline const std::string &VulkanResource<bindingType, Handle>::get_debug_name() const
{
return debug_name;
}
template <vkb::BindingType bindingType, typename Handle>
inline Device<bindingType> &VulkanResource<bindingType, Handle>::get_device()
{
assert(device && "VKBDevice handle not set");
if constexpr (bindingType == vkb::BindingType::Cpp)
{
return *device;
}
else
{
return *reinterpret_cast<vkb::core::DeviceC *>(device);
}
}
template <vkb::BindingType bindingType, typename Handle>
inline Device<bindingType> const &VulkanResource<bindingType, Handle>::get_device() const
{
assert(device && "VKBDevice handle not set");
if constexpr (bindingType == vkb::BindingType::Cpp)
{
return *device;
}
else
{
return *reinterpret_cast<vkb::core::DeviceC const *>(device);
}
}
template <vkb::BindingType bindingType, typename Handle>
inline Handle &VulkanResource<bindingType, Handle>::get_handle()
{
if constexpr (bindingType == vkb::BindingType::Cpp)
{
return handle;
}
else
{
return *reinterpret_cast<typename ResourceType::NativeType *>(&handle);
}
}
template <vkb::BindingType bindingType, typename Handle>
inline const Handle &VulkanResource<bindingType, Handle>::get_handle() const
{
if constexpr (bindingType == vkb::BindingType::Cpp)
{
return handle;
}
else
{
return *reinterpret_cast<typename ResourceType::NativeType const *>(&handle);
}
}
template <vkb::BindingType bindingType, typename Handle>
inline uint64_t VulkanResource<bindingType, Handle>::get_handle_u64() const
{
// See https://github.com/KhronosGroup/Vulkan-Docs/issues/368 .
// Dispatchable and non-dispatchable handle types are *not* necessarily binary-compatible!
// Non-dispatchable handles _might_ be only 32-bit long. This is because, on 32-bit machines, they might be a typedef to a 32-bit pointer.
using UintHandle = typename std::conditional<sizeof(ResourceType) == sizeof(uint32_t), uint32_t, uint64_t>::type;
return static_cast<uint64_t>(*reinterpret_cast<UintHandle const *>(&handle));
}
template <vkb::BindingType bindingType, typename Handle>
inline typename VulkanResource<bindingType, Handle>::ObjectType VulkanResource<bindingType, Handle>::get_object_type() const
{
if constexpr (bindingType == vkb::BindingType::Cpp)
{
return ResourceType::objectType;
}
else
{
return static_cast<VkObjectType>(ResourceType::objectType);
}
}
template <vkb::BindingType bindingType, typename Handle>
inline typename VulkanResource<bindingType, Handle>::ResourceType const &VulkanResource<bindingType, Handle>::get_resource() const
{
return handle;
}
template <vkb::BindingType bindingType, typename Handle>
inline bool VulkanResource<bindingType, Handle>::has_device() const
{
return device != nullptr;
}
template <vkb::BindingType bindingType, typename Handle>
inline bool VulkanResource<bindingType, Handle>::has_handle() const
{
return handle != nullptr;
}
template <vkb::BindingType bindingType, typename Handle>
inline void VulkanResource<bindingType, Handle>::set_debug_name(const std::string &name)
{
debug_name = name;
if (device && !debug_name.empty())
{
get_device().get_debug_utils().set_debug_name(get_device().get_handle(), get_object_type(), get_handle_u64(), debug_name.c_str());
}
}
template <vkb::BindingType bindingType, typename Handle>
inline void VulkanResource<bindingType, Handle>::set_handle(Handle hdl)
{
handle = hdl;
}
} // namespace core
} // namespace vkb