Vulkan: Move SpecializationInfo to own file.

This will also be used by the pipelines for dynamic recompilation.

Bug: b/154158882
Change-Id: I0fe16dbc3bc4eed8ffdd90afcd62f255ca8e4505
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/43848
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Vulkan/BUILD.gn b/src/Vulkan/BUILD.gn
index 19b7e79..830a39c 100644
--- a/src/Vulkan/BUILD.gn
+++ b/src/Vulkan/BUILD.gn
@@ -91,6 +91,7 @@
     "VkSampler.hpp",
     "VkSemaphore.hpp",
     "VkShaderModule.hpp",
+    "VkSpecializationInfo.hpp",
     "VkStringify.hpp",
     "VulkanPlatform.h",
   ]
@@ -133,6 +134,7 @@
     "VkSampler.cpp",
     "VkSemaphore.cpp",
     "VkShaderModule.cpp",
+    "VkSpecializationInfo.cpp",
     "VkStringify.cpp",
     "Vulkan.rc",
     "libVulkan.cpp",
diff --git a/src/Vulkan/CMakeLists.txt b/src/Vulkan/CMakeLists.txt
index bc334b0..65e29ad 100644
--- a/src/Vulkan/CMakeLists.txt
+++ b/src/Vulkan/CMakeLists.txt
@@ -68,6 +68,8 @@
     VkPipeline.hpp
     VkPipelineCache.cpp
     VkPipelineCache.hpp
+    VkSpecializationInfo.cpp
+    VkSpecializationInfo.hpp
     VkPipelineLayout.cpp
     VkPipelineLayout.hpp
     VkPromotedExtensions.cpp
diff --git a/src/Vulkan/VkPipelineCache.cpp b/src/Vulkan/VkPipelineCache.cpp
index c725b3f..8c4c894 100644
--- a/src/Vulkan/VkPipelineCache.cpp
+++ b/src/Vulkan/VkPipelineCache.cpp
@@ -17,100 +17,12 @@
 
 namespace vk {
 
-PipelineCache::SpirvShaderKey::SpecializationInfo::SpecializationInfo(const VkSpecializationInfo *specializationInfo)
-{
-	if(specializationInfo)
-	{
-		auto ptr = reinterpret_cast<VkSpecializationInfo *>(
-		    allocate(sizeof(VkSpecializationInfo), REQUIRED_MEMORY_ALIGNMENT, DEVICE_MEMORY));
-
-		info = std::shared_ptr<VkSpecializationInfo>(ptr, Deleter());
-
-		info->mapEntryCount = specializationInfo->mapEntryCount;
-		if(specializationInfo->mapEntryCount > 0)
-		{
-			size_t entriesSize = specializationInfo->mapEntryCount * sizeof(VkSpecializationMapEntry);
-			VkSpecializationMapEntry *mapEntries = reinterpret_cast<VkSpecializationMapEntry *>(
-			    allocate(entriesSize, REQUIRED_MEMORY_ALIGNMENT, DEVICE_MEMORY));
-			memcpy(mapEntries, specializationInfo->pMapEntries, entriesSize);
-			info->pMapEntries = mapEntries;
-		}
-
-		info->dataSize = specializationInfo->dataSize;
-		if(specializationInfo->dataSize > 0)
-		{
-			void *data = allocate(specializationInfo->dataSize, REQUIRED_MEMORY_ALIGNMENT, DEVICE_MEMORY);
-			memcpy(data, specializationInfo->pData, specializationInfo->dataSize);
-			info->pData = data;
-		}
-		else
-		{
-			info->pData = nullptr;
-		}
-	}
-}
-
-void PipelineCache::SpirvShaderKey::SpecializationInfo::Deleter::operator()(VkSpecializationInfo *info) const
-{
-	if(info)
-	{
-		deallocate(const_cast<VkSpecializationMapEntry *>(info->pMapEntries), DEVICE_MEMORY);
-		deallocate(const_cast<void *>(info->pData), DEVICE_MEMORY);
-		deallocate(info, DEVICE_MEMORY);
-	}
-}
-
-bool PipelineCache::SpirvShaderKey::SpecializationInfo::operator<(const SpecializationInfo &specializationInfo) const
-{
-	// Check that either both or neither keys have specialization info.
-	if((info.get() == nullptr) != (specializationInfo.info.get() == nullptr))
-	{
-		return info.get() == nullptr;
-	}
-
-	if(!info)
-	{
-		ASSERT(!specializationInfo.info);
-		return false;
-	}
-
-	if(info->mapEntryCount != specializationInfo.info->mapEntryCount)
-	{
-		return info->mapEntryCount < specializationInfo.info->mapEntryCount;
-	}
-
-	if(info->dataSize != specializationInfo.info->dataSize)
-	{
-		return info->dataSize < specializationInfo.info->dataSize;
-	}
-
-	if(info->mapEntryCount > 0)
-	{
-		int cmp = memcmp(info->pMapEntries, specializationInfo.info->pMapEntries, info->mapEntryCount * sizeof(VkSpecializationMapEntry));
-		if(cmp != 0)
-		{
-			return cmp < 0;
-		}
-	}
-
-	if(info->dataSize > 0)
-	{
-		int cmp = memcmp(info->pData, specializationInfo.info->pData, info->dataSize);
-		if(cmp != 0)
-		{
-			return cmp < 0;
-		}
-	}
-
-	return false;
-}
-
 PipelineCache::SpirvShaderKey::SpirvShaderKey(const VkShaderStageFlagBits pipelineStage,
                                               const std::string &entryPointName,
                                               const std::vector<uint32_t> &insns,
                                               const vk::RenderPass *renderPass,
                                               const uint32_t subpassIndex,
-                                              const VkSpecializationInfo *specializationInfo)
+                                              const vk::SpecializationInfo &specializationInfo)
     : pipelineStage(pipelineStage)
     , entryPointName(entryPointName)
     , insns(insns)
diff --git a/src/Vulkan/VkPipelineCache.hpp b/src/Vulkan/VkPipelineCache.hpp
index 85c5836..5e89e60 100644
--- a/src/Vulkan/VkPipelineCache.hpp
+++ b/src/Vulkan/VkPipelineCache.hpp
@@ -16,6 +16,7 @@
 #define VK_PIPELINE_CACHE_HPP_
 
 #include "VkObject.hpp"
+#include "VkSpecializationInfo.hpp"
 
 #include <cstring>
 #include <functional>
@@ -51,29 +52,12 @@
 
 	struct SpirvShaderKey
 	{
-		struct SpecializationInfo
-		{
-			SpecializationInfo(const VkSpecializationInfo *specializationInfo);
-
-			bool operator<(const SpecializationInfo &specializationInfo) const;
-
-			const VkSpecializationInfo *get() const { return info.get(); }
-
-		private:
-			struct Deleter
-			{
-				void operator()(VkSpecializationInfo *) const;
-			};
-
-			std::shared_ptr<VkSpecializationInfo> info;
-		};
-
 		SpirvShaderKey(const VkShaderStageFlagBits pipelineStage,
 		               const std::string &entryPointName,
 		               const std::vector<uint32_t> &insns,
 		               const vk::RenderPass *renderPass,
 		               const uint32_t subpassIndex,
-		               const VkSpecializationInfo *specializationInfo);
+		               const vk::SpecializationInfo &specializationInfo);
 
 		bool operator<(const SpirvShaderKey &other) const;
 
@@ -90,7 +74,7 @@
 		const std::vector<uint32_t> insns;
 		const vk::RenderPass *renderPass;
 		const uint32_t subpassIndex;
-		const SpecializationInfo specializationInfo;
+		const vk::SpecializationInfo specializationInfo;
 	};
 
 	// getOrCreateShader() queries the cache for a shader with the given key.
diff --git a/src/Vulkan/VkSpecializationInfo.cpp b/src/Vulkan/VkSpecializationInfo.cpp
new file mode 100644
index 0000000..bda5f43
--- /dev/null
+++ b/src/Vulkan/VkSpecializationInfo.cpp
@@ -0,0 +1,108 @@
+// Copyright 2020 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.
+
+#include "VkPipelineCache.hpp"
+#include <cstring>
+
+namespace vk {
+
+SpecializationInfo::SpecializationInfo(const VkSpecializationInfo *specializationInfo)
+{
+	if(specializationInfo)
+	{
+		auto ptr = reinterpret_cast<VkSpecializationInfo *>(
+		    allocate(sizeof(VkSpecializationInfo), REQUIRED_MEMORY_ALIGNMENT, DEVICE_MEMORY));
+
+		info = std::shared_ptr<VkSpecializationInfo>(ptr, Deleter());
+
+		info->mapEntryCount = specializationInfo->mapEntryCount;
+		if(specializationInfo->mapEntryCount > 0)
+		{
+			size_t entriesSize = specializationInfo->mapEntryCount * sizeof(VkSpecializationMapEntry);
+			VkSpecializationMapEntry *mapEntries = reinterpret_cast<VkSpecializationMapEntry *>(
+			    allocate(entriesSize, REQUIRED_MEMORY_ALIGNMENT, DEVICE_MEMORY));
+			memcpy(mapEntries, specializationInfo->pMapEntries, entriesSize);
+			info->pMapEntries = mapEntries;
+		}
+
+		info->dataSize = specializationInfo->dataSize;
+		if(specializationInfo->dataSize > 0)
+		{
+			void *data = allocate(specializationInfo->dataSize, REQUIRED_MEMORY_ALIGNMENT, DEVICE_MEMORY);
+			memcpy(data, specializationInfo->pData, specializationInfo->dataSize);
+			info->pData = data;
+		}
+		else
+		{
+			info->pData = nullptr;
+		}
+	}
+}
+
+void SpecializationInfo::Deleter::operator()(VkSpecializationInfo *info) const
+{
+	if(info)
+	{
+		deallocate(const_cast<VkSpecializationMapEntry *>(info->pMapEntries), DEVICE_MEMORY);
+		deallocate(const_cast<void *>(info->pData), DEVICE_MEMORY);
+		deallocate(info, DEVICE_MEMORY);
+	}
+}
+
+bool SpecializationInfo::operator<(const SpecializationInfo &specializationInfo) const
+{
+	// Check that either both or neither keys have specialization info.
+	if((info.get() == nullptr) != (specializationInfo.info.get() == nullptr))
+	{
+		return info.get() == nullptr;
+	}
+
+	if(!info)
+	{
+		ASSERT(!specializationInfo.info);
+		return false;
+	}
+
+	if(info->mapEntryCount != specializationInfo.info->mapEntryCount)
+	{
+		return info->mapEntryCount < specializationInfo.info->mapEntryCount;
+	}
+
+	if(info->dataSize != specializationInfo.info->dataSize)
+	{
+		return info->dataSize < specializationInfo.info->dataSize;
+	}
+
+	if(info->mapEntryCount > 0)
+	{
+		int cmp = memcmp(info->pMapEntries, specializationInfo.info->pMapEntries, info->mapEntryCount * sizeof(VkSpecializationMapEntry));
+		if(cmp != 0)
+		{
+			return cmp < 0;
+		}
+	}
+
+	if(info->dataSize > 0)
+	{
+		int cmp = memcmp(info->pData, specializationInfo.info->pData, info->dataSize);
+		if(cmp != 0)
+		{
+			return cmp < 0;
+		}
+	}
+
+	return false;
+}
+
+}  // namespace vk
diff --git a/src/Vulkan/VkSpecializationInfo.hpp b/src/Vulkan/VkSpecializationInfo.hpp
new file mode 100644
index 0000000..0fdd43d
--- /dev/null
+++ b/src/Vulkan/VkSpecializationInfo.hpp
@@ -0,0 +1,43 @@
+// Copyright 2020 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_SPECIALIZATION_INFO_HPP_
+#define VK_SPECIALIZATION_INFO_HPP_
+
+#include "VkObject.hpp"
+
+#include <memory>
+
+namespace vk {
+
+struct SpecializationInfo
+{
+	SpecializationInfo(const VkSpecializationInfo *specializationInfo);
+
+	bool operator<(const SpecializationInfo &specializationInfo) const;
+
+	const VkSpecializationInfo *get() const { return info.get(); }
+
+private:
+	struct Deleter
+	{
+		void operator()(VkSpecializationInfo *) const;
+	};
+
+	std::shared_ptr<VkSpecializationInfo> info;
+};
+
+}  // namespace vk
+
+#endif  // VK_SPECIALIZATION_INFO_HPP_