blob: d0fcba6159486d0bf9b1d82f9a1ca564edf7a0c8 [file] [log] [blame]
// Copyright 2018 The SwiftShader Authors. All Rights Reserved.
//
// 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.
#ifndef VK_OBJECT_HPP_
#define VK_OBJECT_HPP_
#include "VkConfig.h"
#include "VkMemory.h"
#include "System/Debug.hpp"
#include <Vulkan/VulkanPlatform.h>
#include <vulkan/vk_icd.h>
#include <new>
namespace vk {
template<typename T, typename VkT>
static inline T *VkTtoT(VkT vkObject)
{
return static_cast<T *>(static_cast<void *>(vkObject));
}
template<typename T, typename VkT>
static inline VkT TtoVkT(T *object)
{
return { static_cast<uint64_t>(reinterpret_cast<uintptr_t>(object)) };
}
// For use in the placement new to make it verbose that we're allocating an object using device memory
static constexpr VkAllocationCallbacks *DEVICE_MEMORY = nullptr;
template<typename T, typename VkT, typename CreateInfo, typename... ExtendedInfo>
static VkResult Create(const VkAllocationCallbacks *pAllocator, const CreateInfo *pCreateInfo, VkT *outObject, ExtendedInfo... extendedInfo)
{
*outObject = VK_NULL_HANDLE;
size_t size = T::ComputeRequiredAllocationSize(pCreateInfo);
void *memory = nullptr;
if(size)
{
memory = vk::allocate(size, REQUIRED_MEMORY_ALIGNMENT, pAllocator, T::GetAllocationScope());
if(!memory)
{
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
}
void *objectMemory = vk::allocate(sizeof(T), alignof(T), pAllocator, T::GetAllocationScope());
if(!objectMemory)
{
vk::deallocate(memory, pAllocator);
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
auto object = new(objectMemory) T(pCreateInfo, memory, extendedInfo...);
if(!object)
{
vk::deallocate(memory, pAllocator);
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
*outObject = *object;
// Assert that potential v-table offsets from multiple inheritance aren't causing an offset on the handle
ASSERT(*outObject == objectMemory);
return VK_SUCCESS;
}
template<typename T, typename VkT>
class ObjectBase
{
public:
using VkType = VkT;
void destroy(const VkAllocationCallbacks *pAllocator) {} // Method defined by objects to delete their content, if necessary
template<typename CreateInfo, typename... ExtendedInfo>
static VkResult Create(const VkAllocationCallbacks *pAllocator, const CreateInfo *pCreateInfo, VkT *outObject, ExtendedInfo... extendedInfo)
{
return vk::Create<T, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject, extendedInfo...);
}
static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_OBJECT; }
};
template<typename T, typename VkT>
class Object : public ObjectBase<T, VkT>
{
public:
operator VkT()
{
// The static_cast<T*> is used to make sure the returned pointer points to the
// beginning of the object, even if the derived class uses multiple inheritance
return vk::TtoVkT<T, VkT>(static_cast<T *>(this));
}
static inline T *Cast(VkT vkObject)
{
return vk::VkTtoT<T, VkT>(vkObject);
}
};
template<typename T, typename VkT>
class DispatchableObject
{
VK_LOADER_DATA loaderData = { ICD_LOADER_MAGIC };
T object;
public:
static constexpr VkSystemAllocationScope GetAllocationScope() { return T::GetAllocationScope(); }
template<typename... Args>
DispatchableObject(Args... args)
: object(args...)
{
}
~DispatchableObject() = delete;
void destroy(const VkAllocationCallbacks *pAllocator)
{
object.destroy(pAllocator);
}
void operator delete(void *ptr, const VkAllocationCallbacks *pAllocator)
{
// Should never happen
ASSERT(false);
}
template<typename CreateInfo, typename... ExtendedInfo>
static VkResult Create(const VkAllocationCallbacks *pAllocator, const CreateInfo *pCreateInfo, VkT *outObject, ExtendedInfo... extendedInfo)
{
return vk::Create<DispatchableObject<T, VkT>, VkT, CreateInfo>(pAllocator, pCreateInfo, outObject, extendedInfo...);
}
template<typename CreateInfo>
static size_t ComputeRequiredAllocationSize(const CreateInfo *pCreateInfo)
{
return T::ComputeRequiredAllocationSize(pCreateInfo);
}
static inline T *Cast(VkT vkObject)
{
return (vkObject == VK_NULL_HANDLE) ? nullptr : &(reinterpret_cast<DispatchableObject<T, VkT> *>(vkObject)->object);
}
operator VkT()
{
return reinterpret_cast<VkT>(this);
}
};
} // namespace vk
#endif // VK_OBJECT_HPP_