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 #include <vulkan/vulkan.h>
22 #include <vulkan/vk_icd.h>
23
24 namespace vk
25 {
26 // For use in the placement new to make it verbose that we're allocating an object using device memory
27 static constexpr VkAllocationCallbacks* DEVICE_MEMORY = nullptr;
28
29 template<typename T, typename VkT, typename CreateInfo>
Create(const VkAllocationCallbacks * pAllocator,const CreateInfo * pCreateInfo,VkT * outObject)30 static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject)
31 {
32 *outObject = VK_NULL_HANDLE;
33
34 size_t size = T::ComputeRequiredAllocationSize(pCreateInfo);
35 void* memory = nullptr;
36 if(size)
37 {
38 memory = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, pAllocator, T::GetAllocationScope());
39 if(!memory)
40 {
41 return VK_ERROR_OUT_OF_HOST_MEMORY;
42 }
43 }
44
45 auto object = new (pAllocator) T(pCreateInfo, memory);
46
47 if(!object)
48 {
49 vk::deallocate(memory, pAllocator);
50 return VK_ERROR_OUT_OF_HOST_MEMORY;
51 }
52
53 *outObject = *object;
54
55 return VK_SUCCESS;
56 }
57
58 template<typename T, typename VkT>
59 class ObjectBase
60 {
61 public:
62 using VkType = VkT;
63
destroy(const VkAllocationCallbacks * pAllocator)64 void destroy(const VkAllocationCallbacks* pAllocator) {} // Method defined by objects to delete their content, if necessary
65
operator new(size_t count,const VkAllocationCallbacks * pAllocator)66 void* operator new(size_t count, const VkAllocationCallbacks* pAllocator)
67 {
68 return vk::allocate(count, alignof(T), pAllocator, T::GetAllocationScope());
69 }
70
operator delete(void * ptr,const VkAllocationCallbacks * pAllocator)71 void operator delete(void* ptr, const VkAllocationCallbacks* pAllocator)
72 {
73 // Should never happen
74 ASSERT(false);
75 }
76
77 template<typename CreateInfo>
Create(const VkAllocationCallbacks * pAllocator,const CreateInfo * pCreateInfo,VkT * outObject)78 static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject)
79 {
80 return vk::Create<T, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject);
81 }
82
GetAllocationScope()83 static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_OBJECT; }
84
85 protected:
86 // All derived classes should have deleted destructors
~ObjectBase()87 ~ObjectBase() {}
88 };
89
90 template<typename T, typename VkT>
91 class Object : public ObjectBase<T, VkT>
92 {
93 public:
operator VkT()94 operator VkT()
95 {
96 return reinterpret_cast<VkT>(this);
97 }
98 };
99
100 template<typename T, typename VkT>
101 class DispatchableObject
102 {
103 VK_LOADER_DATA loaderData = { ICD_LOADER_MAGIC };
104
105 T object;
106 public:
GetAllocationScope()107 static constexpr VkSystemAllocationScope GetAllocationScope() { return T::GetAllocationScope(); }
108
109 template<typename ...Args>
DispatchableObject(Args...args)110 DispatchableObject(Args... args) : object(args...)
111 {
112 }
113
114 ~DispatchableObject() = delete;
115
destroy(const VkAllocationCallbacks * pAllocator)116 void destroy(const VkAllocationCallbacks* pAllocator)
117 {
118 object.destroy(pAllocator);
119 }
120
operator new(size_t count,const VkAllocationCallbacks * pAllocator)121 void* operator new(size_t count, const VkAllocationCallbacks* pAllocator)
122 {
123 return vk::allocate(count, alignof(T), pAllocator, T::GetAllocationScope());
124 }
125
operator delete(void * ptr,const VkAllocationCallbacks * pAllocator)126 void operator delete(void* ptr, const VkAllocationCallbacks* pAllocator)
127 {
128 // Should never happen
129 ASSERT(false);
130 }
131
132 template<typename CreateInfo>
Create(const VkAllocationCallbacks * pAllocator,const CreateInfo * pCreateInfo,VkT * outObject)133 static VkResult Create(const VkAllocationCallbacks* pAllocator, const CreateInfo* pCreateInfo, VkT* outObject)
134 {
135 return vk::Create<DispatchableObject<T, VkT>, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject);
136 }
137
138 template<typename CreateInfo>
ComputeRequiredAllocationSize(const CreateInfo * pCreateInfo)139 static size_t ComputeRequiredAllocationSize(const CreateInfo* pCreateInfo)
140 {
141 return T::ComputeRequiredAllocationSize(pCreateInfo);
142 }
143
Cast(VkT vkObject)144 static inline T* Cast(VkT vkObject)
145 {
146 return &(reinterpret_cast<DispatchableObject<T, VkT>*>(vkObject)->object);
147 }
148
operator VkT()149 operator VkT()
150 {
151 return reinterpret_cast<VkT>(this);
152 }
153 };
154
155 } // namespace vk
156
157 #endif // VK_OBJECT_HPP_
158