/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#include "MetalBackedTexture.h"
#include <vulkan/vulkan.hpp>
#import <Metal/MTLTexture.h>

namespace OpenVulkano::Vulkan
{
	void MetalBackedTexture::Init(ResourceManager* resManager, MTLTexture_id mtlTexture, bool ownsTexture)
	{
		auto binding = Texture::DESCRIPTOR_SET_LAYOUT_BINDING;
		
		m_metalTexture = mtlTexture;

		resolution = { static_cast<uint32_t>(mtlTexture.width), static_cast<uint32_t>(mtlTexture.height), static_cast<uint32_t>(mtlTexture.depth) };
		format = DataFormat::GetFromMetalPixelFormat(static_cast<int>(mtlTexture.pixelFormat));

		m_vulkanTexture.device = resManager->GetDevice();
		m_vulkanTexture.format = format;
		m_vulkanTexture.extent = reinterpret_cast<vk::Extent3D&>(resolution);
		
		VkImportMetalTextureInfoEXT importInfo;
		importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_METAL_TEXTURE_INFO_EXT;
		importInfo.pNext = nullptr;
		importInfo.plane = VK_IMAGE_ASPECT_COLOR_BIT;
		importInfo.mtlTexture = mtlTexture;
		
		vk::ImageCreateInfo imgCreateInfo { {}, vk::ImageType::e2D, m_vulkanTexture.format, m_vulkanTexture.extent, 1, 1 };

		imgCreateInfo.sharingMode = vk::SharingMode::eExclusive;
		imgCreateInfo.usage = vk::ImageUsageFlagBits::eSampled;
		imgCreateInfo.tiling = vk::ImageTiling::eLinear;
		imgCreateInfo.pNext = &importInfo;
		
		m_vulkanTexture.image = m_vulkanTexture.device.createImage(imgCreateInfo);
		
		vk::ImageViewCreateInfo imgViewCreateInfo { {}, m_vulkanTexture.image, vk::ImageViewType::e2D, imgCreateInfo.format };
		imgViewCreateInfo.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
		imgViewCreateInfo.subresourceRange.baseMipLevel = 0;
		imgViewCreateInfo.subresourceRange.levelCount = 1;
		imgViewCreateInfo.subresourceRange.baseArrayLayer = 0;
		imgViewCreateInfo.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
		if (format == DataFormat::R8_UNORM)
		{
			imgViewCreateInfo.components.r = vk::ComponentSwizzle::eR;
			imgViewCreateInfo.components.g = vk::ComponentSwizzle::eR;
			imgViewCreateInfo.components.b = vk::ComponentSwizzle::eR;
			imgViewCreateInfo.components.a = vk::ComponentSwizzle::eOne;
		}
		m_vulkanTexture.view = m_vulkanTexture.device.createImageView(imgViewCreateInfo);

		m_vulkanTexture.m_sampler = resManager->CreateSampler(reinterpret_cast<const vk::SamplerCreateInfo&>(Scene::SamplerConfig::DEFAULT));
		m_vulkanTexture.SetDescriptorSet(resManager, resManager->GetDescriptorLayoutSet(binding), binding);

		GetRenderResource().renderObject = &m_vulkanTexture;
		m_vulkanTexture.UpdateAddress(this);
		
		if (!ownsTexture) m_metalTexture = nullptr;
	}

	void MetalBackedTexture::Close()
	{
		if (m_vulkanTexture) m_vulkanTexture.Close();
		if (m_metalTexture)
		{
			[m_metalTexture release];
			m_metalTexture = nullptr;
		}
	}
}
