/* 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 #include namespace vkb { namespace core { template class Device; using DeviceC = Device; using DeviceCpp = Device; /// 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 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::Type; public: using ObjectType = typename std::conditional::type; VulkanResource(Handle handle = nullptr, Device *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 &get_device(); vkb::core::Device 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 using VulkanResourceC = VulkanResource; template using VulkanResourceCpp = VulkanResource; template inline VulkanResource::VulkanResource(Handle handle_, Device *device_) : handle{handle_} { if constexpr (bindingType == vkb::BindingType::Cpp) { device = device_; } else { device = reinterpret_cast(device_); } } template inline VulkanResource::VulkanResource(VulkanResource &&other) : handle(std::exchange(other.handle, {})), device(std::exchange(other.device, {})), debug_name(std::exchange(other.debug_name, {})) {} template inline VulkanResource &VulkanResource::operator=(VulkanResource &&other) { handle = std::exchange(other.handle, {}); device = std::exchange(other.device, {}); debug_name = std::exchange(other.debug_name, {}); return *this; } template inline const std::string &VulkanResource::get_debug_name() const { return debug_name; } template inline Device &VulkanResource::get_device() { assert(device && "VKBDevice handle not set"); if constexpr (bindingType == vkb::BindingType::Cpp) { return *device; } else { return *reinterpret_cast(device); } } template inline Device const &VulkanResource::get_device() const { assert(device && "VKBDevice handle not set"); if constexpr (bindingType == vkb::BindingType::Cpp) { return *device; } else { return *reinterpret_cast(device); } } template inline Handle &VulkanResource::get_handle() { if constexpr (bindingType == vkb::BindingType::Cpp) { return handle; } else { return *reinterpret_cast(&handle); } } template inline const Handle &VulkanResource::get_handle() const { if constexpr (bindingType == vkb::BindingType::Cpp) { return handle; } else { return *reinterpret_cast(&handle); } } template inline uint64_t VulkanResource::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::type; return static_cast(*reinterpret_cast(&handle)); } template inline typename VulkanResource::ObjectType VulkanResource::get_object_type() const { if constexpr (bindingType == vkb::BindingType::Cpp) { return ResourceType::objectType; } else { return static_cast(ResourceType::objectType); } } template inline typename VulkanResource::ResourceType const &VulkanResource::get_resource() const { return handle; } template inline bool VulkanResource::has_device() const { return device != nullptr; } template inline bool VulkanResource::has_handle() const { return handle != nullptr; } template inline void VulkanResource::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 inline void VulkanResource::set_handle(Handle hdl) { handle = hdl; } } // namespace core } // namespace vkb