// 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_PIPELINE_CACHE_HPP_
#define VK_PIPELINE_CACHE_HPP_

#include "VkObject.hpp"
#include "VkSpecializationInfo.hpp"
#include "Pipeline/SpirvBinary.hpp"

#include "marl/mutex.h"
#include "marl/tsa.h"

#include <cstring>
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <vector>

namespace sw {

class ComputeProgram;
class SpirvShader;

}  // namespace sw

namespace vk {

class PipelineLayout;
class RenderPass;

class PipelineCache : public Object<PipelineCache, VkPipelineCache>
{
public:
	static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_CACHE; }

	PipelineCache(const VkPipelineCacheCreateInfo *pCreateInfo, void *mem);
	virtual ~PipelineCache();
	void destroy(const VkAllocationCallbacks *pAllocator);

	static size_t ComputeRequiredAllocationSize(const VkPipelineCacheCreateInfo *pCreateInfo);

	VkResult getData(size_t *pDataSize, void *pData);
	VkResult merge(uint32_t srcCacheCount, const VkPipelineCache *pSrcCaches);

	struct SpirvBinaryKey
	{
		SpirvBinaryKey(const sw::SpirvBinary &insns,
		               const VkSpecializationInfo *specializationInfo,
		               bool optimize);

		bool operator<(const SpirvBinaryKey &other) const;

		const sw::SpirvBinary &getInsns() const { return insns; }
		const VkSpecializationInfo *getSpecializationInfo() const { return specializationInfo.get(); }
		bool getOptimization() const { return optimize; }

	private:
		const sw::SpirvBinary insns;
		const vk::SpecializationInfo specializationInfo;
		const bool optimize;
	};

	// getOrOptimizeSpirv() queries the cache for a shader with the given key.
	// If one is found, it is returned, otherwise create() is called, the
	// returned SPIR-V binary is added to the cache, and it is returned.
	// Function must be a function of the signature:
	//     sw::ShaderBinary()
	template<typename Function>
	inline sw::SpirvBinary getOrOptimizeSpirv(const PipelineCache::SpirvBinaryKey &key, Function &&create);

	struct ComputeProgramKey
	{
		ComputeProgramKey(uint64_t shaderIdentifier, uint32_t pipelineLayoutIdentifier);

		bool operator<(const ComputeProgramKey &other) const;

	private:
		const uint64_t shaderIdentifier;
		const uint32_t pipelineLayoutIdentifier;
	};

	// getOrCreateComputeProgram() queries the cache for a compute program with
	// the given key.
	// If one is found, it is returned, otherwise create() is called, the
	// returned program is added to the cache, and it is returned.
	// Function must be a function of the signature:
	//     std::shared_ptr<sw::ComputeProgram>()
	template<typename Function>
	inline std::shared_ptr<sw::ComputeProgram> getOrCreateComputeProgram(const PipelineCache::ComputeProgramKey &key, Function &&create);

private:
	struct CacheHeader
	{
		uint32_t headerLength;
		uint32_t headerVersion;
		uint32_t vendorID;
		uint32_t deviceID;
		uint8_t pipelineCacheUUID[VK_UUID_SIZE];
	};

	size_t dataSize = 0;
	uint8_t *data = nullptr;

	marl::mutex spirvShadersMutex;
	std::map<SpirvBinaryKey, sw::SpirvBinary> spirvShaders GUARDED_BY(spirvShadersMutex);

	marl::mutex computeProgramsMutex;
	std::map<ComputeProgramKey, std::shared_ptr<sw::ComputeProgram>> computePrograms GUARDED_BY(computeProgramsMutex);
};

static inline PipelineCache *Cast(VkPipelineCache object)
{
	return PipelineCache::Cast(object);
}

template<typename Function>
std::shared_ptr<sw::ComputeProgram> PipelineCache::getOrCreateComputeProgram(const PipelineCache::ComputeProgramKey &key, Function &&create)
{
	marl::lock lock(computeProgramsMutex);

	auto it = computePrograms.find(key);
	if(it != computePrograms.end())
	{
		return it->second;
	}

	auto created = create();
	computePrograms.emplace(key, created);

	return created;
}

template<typename Function>
sw::SpirvBinary PipelineCache::getOrOptimizeSpirv(const PipelineCache::SpirvBinaryKey &key, Function &&create)
{
	marl::lock lock(spirvShadersMutex);

	auto it = spirvShaders.find(key);
	if(it != spirvShaders.end())
	{
		return it->second;
	}

	auto created = create();
	spirvShaders.emplace(key, created);

	return created;
}

}  // namespace vk

#endif  // VK_PIPELINE_CACHE_HPP_
