// 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.hpp"
#include "VkMemory.hpp"

#include "System/Debug.hpp"

#include <vulkan/vk_icd.h>
#undef None
#undef Bool

#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_
