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
18#include "VkConfig.h"
19#include "VkDebug.hpp"
20#include "VkMemory.h"
21
22#include <new>
23#include <Vulkan/VulkanPlatform.h>
24#include <vulkan/vk_icd.h>
25
26namespace vk
27{
28
29template<typename T, typename VkT>
30static inline T* VkTtoT(VkT vkObject)
31{
32 return static_cast<T*>(static_cast<void*>(vkObject));
33}
34
35template<typename T, typename VkT>
36static inline VkT TtoVkT(T* object)
37{
38 return { static_cast<uint64_t>(reinterpret_cast<uintptr_t>(object)) };
39}
40
41// For use in the placement new to make it verbose that we're allocating an object using device memory
42static constexpr VkAllocationCallbacks* DEVICE_MEMORY = nullptr;
43
44template<typename T, typename VkT, typename CreateInfo, typename... ExtendedInfo>
45static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject, ExtendedInfo... extendedInfo)
46{
47 *outObject = VK_NULL_HANDLE;
48
49 size_t size = T::ComputeRequiredAllocationSize(pCreateInfo);
50 void* memory = nullptr;
51 if(size)
52 {
53 memory = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, pAllocator, T::GetAllocationScope());
54 if(!memory)
55 {
56 return VK_ERROR_OUT_OF_HOST_MEMORY;
57 }
58 }
59
60 void* objectMemory = vk::allocate(sizeof(T), alignof(T), pAllocator, T::GetAllocationScope());
61 if(!objectMemory)
62 {
63 vk::deallocate(memory, pAllocator);
64 return VK_ERROR_OUT_OF_HOST_MEMORY;
65 }
66
67 auto object = new (objectMemory) T(pCreateInfo, memory, extendedInfo...);
68
69 if(!object)
70 {
71 vk::deallocate(memory, pAllocator);
72 return VK_ERROR_OUT_OF_HOST_MEMORY;
73 }
74
75 *outObject = *object;
76
77 // Assert that potential v-table offsets from multiple inheritance aren't causing an offset on the handle
78 ASSERT(*outObject == objectMemory);
79
80 return VK_SUCCESS;
81}
82
83template<typename T, typename VkT>
84class ObjectBase
85{
86public:
87 using VkType = VkT;
88
89 void destroy(const VkAllocationCallbacks* pAllocator) {} // Method defined by objects to delete their content, if necessary
90
91 template<typename CreateInfo, typename... ExtendedInfo>
92 static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject, ExtendedInfo... extendedInfo)
93 {
94 return vk::Create<T, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject, extendedInfo...);
95 }
96
97 static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_OBJECT; }
98};
99
100template<typename T, typename VkT>
101class Object : public ObjectBase<T, VkT>
102{
103public:
104 operator VkT()
105 {
106 // The static_cast<T*> is used to make sure the returned pointer points to the
107 // beginning of the object, even if the derived class uses multiple inheritance
108 return vk::TtoVkT<T, VkT>(static_cast<T*>(this));
109 }
110
111 static inline T* Cast(VkT vkObject)
112 {
113 return vk::VkTtoT<T, VkT>(vkObject);
114 }
115};
116
117template<typename T, typename VkT>
118class DispatchableObject
119{
120 VK_LOADER_DATA loaderData = { ICD_LOADER_MAGIC };
121
122 T object;
123
124public:
125 static constexpr VkSystemAllocationScope GetAllocationScope() { return T::GetAllocationScope(); }
126
127 template<typename ...Args>
128 DispatchableObject(Args... args) : object(args...)
129 {
130 }
131
132 ~DispatchableObject() = delete;
133
134 void destroy(const VkAllocationCallbacks* pAllocator)
135 {
136 object.destroy(pAllocator);
137 }
138
139 void operator delete(void* ptr, const VkAllocationCallbacks* pAllocator)
140 {
141 // Should never happen
142 ASSERT(false);
143 }
144
145 template<typename CreateInfo, typename... ExtendedInfo>
146 static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject, ExtendedInfo... extendedInfo)
147 {
148 return vk::Create<DispatchableObject<T, VkT>, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject, extendedInfo...);
149 }
150
151 template<typename CreateInfo>
152 static size_t ComputeRequiredAllocationSize(const CreateInfo* pCreateInfo)
153 {
154 return T::ComputeRequiredAllocationSize(pCreateInfo);
155 }
156
157 static inline T* Cast(VkT vkObject)
158 {
159 return (vkObject == VK_NULL_HANDLE) ? nullptr :
160 &(reinterpret_cast<DispatchableObject<T, VkT>*>(vkObject)->object);
161 }
162
163 operator VkT()
164 {
165 return reinterpret_cast<VkT>(this);
166 }
167};
168
169} // namespace vk
170
171#endif // VK_OBJECT_HPP_
172