PipelineCache basic operations support

After this cl, pipeline caches remain unused at pipeline creation
time, but some basic functionalities of the pipeline cache itself
have been added:
- Initial data is copied at pipeline cache creation time
- PipelineCache objects must store a header at the beginning of the
  cache
- Providing a bad size to vkGetPipelineCacheData will now return
  VK_INCOMPLETE

Also fixed a few tracing strings in libVulkan.cpp.

Bug b/123588002

Change-Id: Icc0aadbe6a60bf3d2b9d3a43132d26671f60c728
Tests: dEQP-VK.pipeline.cache.*
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/28430
Presubmit-Ready: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Tested-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Vulkan/VkPipelineCache.cpp b/src/Vulkan/VkPipelineCache.cpp
new file mode 100644
index 0000000..e0890f1
--- /dev/null
+++ b/src/Vulkan/VkPipelineCache.cpp
@@ -0,0 +1,79 @@
+// Copyright 2019 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
+{
+
+PipelineCache::PipelineCache(const VkPipelineCacheCreateInfo* pCreateInfo, void* mem) :
+	dataSize(ComputeRequiredAllocationSize(pCreateInfo)), data(reinterpret_cast<uint8_t*>(mem))
+{
+	CacheHeader* header = reinterpret_cast<CacheHeader*>(mem);
+	header->headerLength = sizeof(CacheHeader);
+	header->headerVersion = VK_PIPELINE_CACHE_HEADER_VERSION_ONE;
+	header->vendorID = VENDOR_ID;
+	header->deviceID = DEVICE_ID;
+	memcpy(header->pipelineCacheUUID, SWIFTSHADER_UUID, VK_UUID_SIZE);
+
+	if(pCreateInfo->pInitialData && (pCreateInfo->initialDataSize > 0))
+	{
+		memcpy(data + sizeof(CacheHeader), pCreateInfo->pInitialData, pCreateInfo->initialDataSize);
+	}
+}
+
+void PipelineCache::destroy(const VkAllocationCallbacks* pAllocator)
+{
+	vk::deallocate(data, pAllocator);
+}
+
+size_t PipelineCache::ComputeRequiredAllocationSize(const VkPipelineCacheCreateInfo* pCreateInfo)
+{
+	return pCreateInfo->initialDataSize + sizeof(CacheHeader);
+}
+
+VkResult PipelineCache::getData(size_t* pDataSize, void* pData)
+{
+	if(!pData)
+	{
+		*pDataSize = dataSize;
+		return VK_SUCCESS;
+	}
+
+	if(*pDataSize != dataSize)
+	{
+		*pDataSize = 0;
+		return VK_INCOMPLETE;
+	}
+
+	if(*pDataSize > 0)
+	{
+		memcpy(pData, data, *pDataSize);
+	}
+
+	return VK_SUCCESS;
+}
+
+VkResult PipelineCache::merge(uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches)
+{
+	for(uint32_t i = 0; i < srcCacheCount; i++)
+	{
+		// TODO (b/123588002): merge pSrcCaches[i];
+	}
+
+	return VK_SUCCESS;
+}
+
+} // namespace vk
diff --git a/src/Vulkan/VkPipelineCache.hpp b/src/Vulkan/VkPipelineCache.hpp
index 6218394..927c7a2 100644
--- a/src/Vulkan/VkPipelineCache.hpp
+++ b/src/Vulkan/VkPipelineCache.hpp
@@ -23,18 +23,27 @@
 class PipelineCache : public Object<PipelineCache, VkPipelineCache>
 {
 public:
-	PipelineCache(const VkPipelineCacheCreateInfo* pCreateInfo, void* mem)
-	{
-	}
-
+	PipelineCache(const VkPipelineCacheCreateInfo* pCreateInfo, void* mem);
 	~PipelineCache() = delete;
+	void destroy(const VkAllocationCallbacks* pAllocator);
 
-	static size_t ComputeRequiredAllocationSize(const VkPipelineCacheCreateInfo* pCreateInfo)
-	{
-		return 0;
-	}
+	static size_t ComputeRequiredAllocationSize(const VkPipelineCacheCreateInfo* pCreateInfo);
+
+	VkResult getData(size_t* pDataSize, void* pData);
+	VkResult merge(uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches);
 
 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;
 };
 
 static inline PipelineCache* Cast(VkPipelineCache object)
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index 10d0048..c5b9939 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -676,8 +676,8 @@
 
 VKAPI_ATTR void VKAPI_CALL vkGetImageSparseMemoryRequirements(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements)
 {
-	TRACE("(VkDevice device, VkImage image, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements* pSparseMemoryRequirements)",
-	      device, image, pSparseMemoryRequirementCount, pSparseMemoryRequirements);
+	TRACE("(VkDevice device = 0x%X, VkImage image = 0x%X, uint32_t* pSparseMemoryRequirementCount = 0x%X, VkSparseImageMemoryRequirements* pSparseMemoryRequirements = 0x%X)",
+	        device, image, pSparseMemoryRequirementCount, pSparseMemoryRequirements);
 
 	// The 'sparseBinding' feature is not supported, so images can not be created with the VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT flag.
 	// "If the image was not created with VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT then pSparseMemoryRequirementCount will be set to zero and pSparseMemoryRequirements will not be written to."
@@ -686,7 +686,7 @@
 
 VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties)
 {
-	TRACE("(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties)",
+	TRACE("(VkPhysicalDevice physicalDevice = 0x%X, VkFormat format = %d, VkImageType type = %d, VkSampleCountFlagBits samples = %d, VkImageUsageFlags usage = %d, VkImageTiling tiling = %d, uint32_t* pPropertyCount = 0x%X, VkSparseImageFormatProperties* pProperties = 0x%X)",
 			physicalDevice, format, type, samples, usage, tiling, pPropertyCount, pProperties);
 
 	// We do not support sparse images.
@@ -873,8 +873,8 @@
 
 VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView)
 {
-	TRACE("(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView)",
-		device, pCreateInfo, pAllocator, pView);
+	TRACE("(VkDevice device = 0x%X, const VkBufferViewCreateInfo* pCreateInfo = 0x%X, const VkAllocationCallbacks* pAllocator = 0x%X, VkBufferView* pView = 0x%X)",
+	        device, pCreateInfo, pAllocator, pView);
 
 	if(pCreateInfo->pNext || pCreateInfo->flags)
 	{
@@ -886,8 +886,8 @@
 
 VKAPI_ATTR void VKAPI_CALL vkDestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator)
 {
-	TRACE("(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks* pAllocator)",
-	      device, bufferView, pAllocator);
+	TRACE("(VkDevice device = 0x%X, VkBufferView bufferView = 0x%X, const VkAllocationCallbacks* pAllocator = 0x%X)",
+	        device, bufferView, pAllocator);
 
 	vk::destroy(bufferView, pAllocator);
 }
@@ -921,8 +921,8 @@
 
 VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout)
 {
-	TRACE("(VkDevice device, VkImage image, const VkImageSubresource* pSubresource, VkSubresourceLayout* pLayout)",
-		device, image, pSubresource, pLayout);
+	TRACE("(VkDevice device = 0x%X, VkImage image = 0x%X, const VkImageSubresource* pSubresource = 0x%X, VkSubresourceLayout* pLayout = 0x%X)",
+	        device, image, pSubresource, pLayout);
 
 	vk::Cast(image)->getSubresourceLayout(pSubresource, pLayout);
 }
@@ -1003,8 +1003,8 @@
 
 VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache)
 {
-	TRACE("(VkDevice device, const VkPipelineCacheCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkPipelineCache* pPipelineCache)",
-	      device, pCreateInfo, pAllocator, pPipelineCache);
+	TRACE("(VkDevice device = 0x%X, const VkPipelineCacheCreateInfo* pCreateInfo = 0x%X, const VkAllocationCallbacks* pAllocator = 0x%X, VkPipelineCache* pPipelineCache = 0x%X)",
+	        device, pCreateInfo, pAllocator, pPipelineCache);
 
 	if(pCreateInfo->pNext || pCreateInfo->flags)
 	{
@@ -1016,24 +1016,26 @@
 
 VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator)
 {
-	TRACE("(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks* pAllocator)",
-	      device, pipelineCache, pAllocator);
+	TRACE("(VkDevice device = 0x%X, VkPipelineCache pipelineCache = 0x%X, const VkAllocationCallbacks* pAllocator = 0x%X)",
+	        device, pipelineCache, pAllocator);
 
 	vk::destroy(pipelineCache, pAllocator);
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t* pDataSize, void* pData)
 {
-	TRACE("()");
-	UNIMPLEMENTED("vkGetPipelineCacheData");
-	return VK_SUCCESS;
+	TRACE("(VkDevice device = 0x%X, VkPipelineCache pipelineCache = 0x%X, size_t* pDataSize = 0x%X, void* pData = 0x%X)",
+	        device, pipelineCache, pDataSize, pData);
+
+	return vk::Cast(pipelineCache)->getData(pDataSize, pData);
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL vkMergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache* pSrcCaches)
 {
-	TRACE("()");
-	UNIMPLEMENTED("vkMergePipelineCaches");
-	return VK_SUCCESS;
+	TRACE("(VkDevice device = 0x%X, VkPipelineCache dstCache = 0x%X, uint32_t srcCacheCount = %d, const VkPipelineCache* pSrcCaches = 0x%X)",
+	        device, dstCache, srcCacheCount, pSrcCaches);
+
+	return vk::Cast(dstCache)->merge(srcCacheCount, pSrcCaches);
 }
 
 VKAPI_ATTR VkResult VKAPI_CALL vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines)
@@ -2251,8 +2253,8 @@
 
 VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport)
 {
-	TRACE("(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport)",
-	      device, pCreateInfo, pSupport);
+	TRACE("(VkDevice device = 0x%X, const VkDescriptorSetLayoutCreateInfo* pCreateInfo = 0x%X, VkDescriptorSetLayoutSupport* pSupport = 0x%X)",
+	        device, pCreateInfo, pSupport);
 
 	vk::Cast(device)->getDescriptorSetLayoutSupport(pCreateInfo, pSupport);
 }
diff --git a/src/Vulkan/vulkan.vcxproj b/src/Vulkan/vulkan.vcxproj
index c60dd20..f8e95ad 100644
--- a/src/Vulkan/vulkan.vcxproj
+++ b/src/Vulkan/vulkan.vcxproj
@@ -125,6 +125,7 @@
     <ClCompile Include="VkMemory.cpp" />

     <ClCompile Include="VkPhysicalDevice.cpp" />

     <ClCompile Include="VkPipeline.cpp" />

+    <ClCompile Include="VkPipelineCache.cpp" />

     <ClCompile Include="VkPipelineLayout.cpp" />

     <ClCompile Include="VkPromotedExtensions.cpp" />

     <ClCompile Include="VkQueryPool.cpp" />

diff --git a/src/Vulkan/vulkan.vcxproj.filters b/src/Vulkan/vulkan.vcxproj.filters
index aaa9bf6..3b95e02 100644
--- a/src/Vulkan/vulkan.vcxproj.filters
+++ b/src/Vulkan/vulkan.vcxproj.filters
@@ -225,6 +225,9 @@
     <ClCompile Include="VkPipeline.cpp">

       <Filter>Source Files\Vulkan</Filter>

     </ClCompile>

+    <ClCompile Include="VkPipelineCache.cpp">

+      <Filter>Source Files\Vulkan</Filter>

+    </ClCompile>

     <ClCompile Include="VkPipelineLayout.cpp">

       <Filter>Source Files\Vulkan</Filter>

     </ClCompile>