Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 1 | // Copyright 2018 The SwiftShader Authors. All Rights Reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | #ifndef VK_OBJECT_HPP_ |
| 16 | #define VK_OBJECT_HPP_ |
| 17 | |
Antonio Maiorano | 42fd159 | 2020-04-27 11:30:40 -0400 | [diff] [blame] | 18 | #include "VkConfig.hpp" |
| 19 | #include "VkMemory.hpp" |
Nicolas Capens | de16f32 | 2019-02-12 00:32:31 -0500 | [diff] [blame] | 20 | |
Ben Clayton | 25e06e0 | 2020-02-07 11:19:08 +0000 | [diff] [blame] | 21 | #include "System/Debug.hpp" |
| 22 | |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 23 | #include <vulkan/vk_icd.h> |
Nicolas Capens | 2490b1a | 2020-07-13 14:33:01 -0400 | [diff] [blame] | 24 | #undef None |
| 25 | #undef Bool |
| 26 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 27 | #include <new> |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 28 | |
Nicolas Capens | 157ba26 | 2019-12-10 17:49:14 -0500 | [diff] [blame] | 29 | namespace vk { |
Alexis Hetu | bd4cf81 | 2019-06-14 15:14:07 -0400 | [diff] [blame] | 30 | |
| 31 | template<typename T, typename VkT> |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 32 | static inline T *VkTtoT(VkT vkObject) |
Alexis Hetu | bd4cf81 | 2019-06-14 15:14:07 -0400 | [diff] [blame] | 33 | { |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 34 | return static_cast<T *>(static_cast<void *>(vkObject)); |
Alexis Hetu | bd4cf81 | 2019-06-14 15:14:07 -0400 | [diff] [blame] | 35 | } |
| 36 | |
| 37 | template<typename T, typename VkT> |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 38 | static inline VkT TtoVkT(T *object) |
Alexis Hetu | bd4cf81 | 2019-06-14 15:14:07 -0400 | [diff] [blame] | 39 | { |
Alexis Hetu | 2d77aea | 2019-06-17 13:43:50 -0400 | [diff] [blame] | 40 | return { static_cast<uint64_t>(reinterpret_cast<uintptr_t>(object)) }; |
Alexis Hetu | bd4cf81 | 2019-06-14 15:14:07 -0400 | [diff] [blame] | 41 | } |
| 42 | |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 43 | // For use in the placement new to make it verbose that we're allocating an object using device memory |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 44 | static constexpr VkAllocationCallbacks *DEVICE_MEMORY = nullptr; |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 45 | |
Nicolas Capens | 0c73680 | 2019-05-27 12:53:31 -0400 | [diff] [blame] | 46 | template<typename T, typename VkT, typename CreateInfo, typename... ExtendedInfo> |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 47 | static VkResult Create(const VkAllocationCallbacks *pAllocator, const CreateInfo *pCreateInfo, VkT *outObject, ExtendedInfo... extendedInfo) |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 48 | { |
| 49 | *outObject = VK_NULL_HANDLE; |
| 50 | |
| 51 | size_t size = T::ComputeRequiredAllocationSize(pCreateInfo); |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 52 | void *memory = nullptr; |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 53 | if(size) |
| 54 | { |
| 55 | memory = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, pAllocator, T::GetAllocationScope()); |
| 56 | if(!memory) |
| 57 | { |
| 58 | return VK_ERROR_OUT_OF_HOST_MEMORY; |
| 59 | } |
| 60 | } |
| 61 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 62 | void *objectMemory = vk::allocate(sizeof(T), alignof(T), pAllocator, T::GetAllocationScope()); |
Alexis Hetu | 1a9714a | 2019-04-12 11:48:12 -0400 | [diff] [blame] | 63 | if(!objectMemory) |
| 64 | { |
| 65 | vk::deallocate(memory, pAllocator); |
| 66 | return VK_ERROR_OUT_OF_HOST_MEMORY; |
| 67 | } |
| 68 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 69 | auto object = new(objectMemory) T(pCreateInfo, memory, extendedInfo...); |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 70 | |
| 71 | if(!object) |
| 72 | { |
| 73 | vk::deallocate(memory, pAllocator); |
| 74 | return VK_ERROR_OUT_OF_HOST_MEMORY; |
| 75 | } |
| 76 | |
| 77 | *outObject = *object; |
| 78 | |
Alexis Hetu | 42232ab | 2019-05-27 13:09:05 -0400 | [diff] [blame] | 79 | // Assert that potential v-table offsets from multiple inheritance aren't causing an offset on the handle |
| 80 | ASSERT(*outObject == objectMemory); |
| 81 | |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 82 | return VK_SUCCESS; |
| 83 | } |
| 84 | |
| 85 | template<typename T, typename VkT> |
| 86 | class ObjectBase |
| 87 | { |
| 88 | public: |
| 89 | using VkType = VkT; |
| 90 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 91 | void destroy(const VkAllocationCallbacks *pAllocator) {} // Method defined by objects to delete their content, if necessary |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 92 | |
Nicolas Capens | 0c73680 | 2019-05-27 12:53:31 -0400 | [diff] [blame] | 93 | template<typename CreateInfo, typename... ExtendedInfo> |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 94 | static VkResult Create(const VkAllocationCallbacks *pAllocator, const CreateInfo *pCreateInfo, VkT *outObject, ExtendedInfo... extendedInfo) |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 95 | { |
Nicolas Capens | 0c73680 | 2019-05-27 12:53:31 -0400 | [diff] [blame] | 96 | return vk::Create<T, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject, extendedInfo...); |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 97 | } |
| 98 | |
| 99 | static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_OBJECT; } |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 100 | }; |
| 101 | |
| 102 | template<typename T, typename VkT> |
| 103 | class Object : public ObjectBase<T, VkT> |
| 104 | { |
| 105 | public: |
| 106 | operator VkT() |
| 107 | { |
Alexis Hetu | 42232ab | 2019-05-27 13:09:05 -0400 | [diff] [blame] | 108 | // The static_cast<T*> is used to make sure the returned pointer points to the |
| 109 | // beginning of the object, even if the derived class uses multiple inheritance |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 110 | return vk::TtoVkT<T, VkT>(static_cast<T *>(this)); |
Alexis Hetu | bd4cf81 | 2019-06-14 15:14:07 -0400 | [diff] [blame] | 111 | } |
| 112 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 113 | static inline T *Cast(VkT vkObject) |
Alexis Hetu | bd4cf81 | 2019-06-14 15:14:07 -0400 | [diff] [blame] | 114 | { |
| 115 | return vk::VkTtoT<T, VkT>(vkObject); |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 116 | } |
| 117 | }; |
| 118 | |
| 119 | template<typename T, typename VkT> |
| 120 | class DispatchableObject |
| 121 | { |
| 122 | VK_LOADER_DATA loaderData = { ICD_LOADER_MAGIC }; |
| 123 | |
| 124 | T object; |
Nicolas Capens | 0c73680 | 2019-05-27 12:53:31 -0400 | [diff] [blame] | 125 | |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 126 | public: |
| 127 | static constexpr VkSystemAllocationScope GetAllocationScope() { return T::GetAllocationScope(); } |
| 128 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 129 | template<typename... Args> |
| 130 | DispatchableObject(Args... args) |
| 131 | : object(args...) |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 132 | { |
| 133 | } |
| 134 | |
Nicolas Capens | 0c73680 | 2019-05-27 12:53:31 -0400 | [diff] [blame] | 135 | ~DispatchableObject() = delete; |
| 136 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 137 | void destroy(const VkAllocationCallbacks *pAllocator) |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 138 | { |
| 139 | object.destroy(pAllocator); |
| 140 | } |
| 141 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 142 | void operator delete(void *ptr, const VkAllocationCallbacks *pAllocator) |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 143 | { |
| 144 | // Should never happen |
| 145 | ASSERT(false); |
| 146 | } |
| 147 | |
Nicolas Capens | 0c73680 | 2019-05-27 12:53:31 -0400 | [diff] [blame] | 148 | template<typename CreateInfo, typename... ExtendedInfo> |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 149 | static VkResult Create(const VkAllocationCallbacks *pAllocator, const CreateInfo *pCreateInfo, VkT *outObject, ExtendedInfo... extendedInfo) |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 150 | { |
Nicolas Capens | 0c73680 | 2019-05-27 12:53:31 -0400 | [diff] [blame] | 151 | return vk::Create<DispatchableObject<T, VkT>, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject, extendedInfo...); |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 152 | } |
| 153 | |
| 154 | template<typename CreateInfo> |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 155 | static size_t ComputeRequiredAllocationSize(const CreateInfo *pCreateInfo) |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 156 | { |
| 157 | return T::ComputeRequiredAllocationSize(pCreateInfo); |
| 158 | } |
| 159 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 160 | static inline T *Cast(VkT vkObject) |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 161 | { |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 162 | return (vkObject == VK_NULL_HANDLE) ? nullptr : &(reinterpret_cast<DispatchableObject<T, VkT> *>(vkObject)->object); |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 163 | } |
| 164 | |
| 165 | operator VkT() |
| 166 | { |
| 167 | return reinterpret_cast<VkT>(this); |
| 168 | } |
| 169 | }; |
| 170 | |
Nicolas Capens | 157ba26 | 2019-12-10 17:49:14 -0500 | [diff] [blame] | 171 | } // namespace vk |
Alexis Hetu | 767b41b | 2018-09-26 11:25:46 -0400 | [diff] [blame] | 172 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 173 | #endif // VK_OBJECT_HPP_ |