Просмотр исходного кода

Vulkan: Add support for on-disk pipeline cache

Panagiotis Christopoulos Charitos 8 лет назад
Родитель
Сommit
3b730c3530

+ 7 - 7
src/anki/core/App.cpp

@@ -183,8 +183,8 @@ Error App::initInternal(const ConfigSet& config_, AllocAlignedCallback allocCb,
 #if ANKI_SIMD == ANKI_SIMD_SSE
 #if ANKI_SIMD == ANKI_SIMD_SSE
 	if(!__builtin_cpu_supports("sse4.2"))
 	if(!__builtin_cpu_supports("sse4.2"))
 	{
 	{
-		ANKI_CORE_LOGF("AnKi is built with sse4.2 support but your CPU doesn't "
-					   "support it. Try bulding without SSE support");
+		ANKI_CORE_LOGF(
+			"AnKi is built with sse4.2 support but your CPU doesn't support it. Try bulding without SSE support");
 	}
 	}
 #endif
 #endif
 
 
@@ -324,12 +324,12 @@ Error App::initDirs()
 	// Cache
 	// Cache
 	m_cacheDir.sprintf(m_heapAlloc, "%s/cache", &m_settingsDir[0]);
 	m_cacheDir.sprintf(m_heapAlloc, "%s/cache", &m_settingsDir[0]);
 
 
-	if(directoryExists(m_cacheDir.toCString()))
-	{
-		ANKI_CHECK(removeDirectory(m_cacheDir.toCString()));
-	}
-
+/*if(directoryExists(m_cacheDir.toCString()))
+{
+	ANKI_CHECK(removeDirectory(m_cacheDir.toCString()));
 	ANKI_CHECK(createDirectory(m_cacheDir.toCString()));
 	ANKI_CHECK(createDirectory(m_cacheDir.toCString()));
+}*/
+
 #else
 #else
 	// ANKI_ASSERT(gAndroidApp);
 	// ANKI_ASSERT(gAndroidApp);
 	// ANativeActivity* activity = gAndroidApp->activity;
 	// ANativeActivity* activity = gAndroidApp->activity;

+ 3 - 0
src/anki/core/Config.cpp

@@ -79,6 +79,9 @@ Config::Config()
 	newOption("vsync", false);
 	newOption("vsync", false);
 	newOption("debugMarkers", false);
 	newOption("debugMarkers", false);
 
 
+	// GR
+	newOption("gr.diskShaderCacheMaxSize", 10 * 1024 * 1024);
+
 	// Core
 	// Core
 	newOption("core.uniformPerFrameMemorySize", 1024 * 1024 * 16);
 	newOption("core.uniformPerFrameMemorySize", 1024 * 1024 * 16);
 	newOption("core.storagePerFrameMemorySize", 1024 * 1024 * 16);
 	newOption("core.storagePerFrameMemorySize", 1024 * 1024 * 16);

+ 2 - 9
src/anki/gr/vulkan/GrManagerImpl.cpp

@@ -66,10 +66,7 @@ GrManagerImpl::~GrManagerImpl()
 		vkDestroySwapchainKHR(m_device, m_swapchain, nullptr);
 		vkDestroySwapchainKHR(m_device, m_swapchain, nullptr);
 	}
 	}
 
 
-	if(m_pplineCache)
-	{
-		vkDestroyPipelineCache(m_device, m_pplineCache, nullptr);
-	}
+	m_pplineCache.destroy(m_device, m_physicalDevice, getAllocator());
 
 
 	if(m_device)
 	if(m_device)
 	{
 	{
@@ -119,11 +116,7 @@ Error GrManagerImpl::initInternal(const GrManagerInitInfo& init)
 	vkGetDeviceQueue(m_device, m_queueIdx, 0, &m_queue);
 	vkGetDeviceQueue(m_device, m_queueIdx, 0, &m_queue);
 	ANKI_CHECK(initSwapchain(init));
 	ANKI_CHECK(initSwapchain(init));
 
 
-	{
-		VkPipelineCacheCreateInfo ci = {};
-		ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
-		vkCreatePipelineCache(m_device, &ci, nullptr, &m_pplineCache);
-	}
+	ANKI_CHECK(m_pplineCache.init(m_device, m_physicalDevice, init.m_cacheDirectory, *init.m_config, getAllocator()));
 
 
 	ANKI_CHECK(initMemory(*init.m_config));
 	ANKI_CHECK(initMemory(*init.m_config));
 
 

+ 4 - 3
src/anki/gr/vulkan/GrManagerImpl.h

@@ -13,6 +13,7 @@
 #include <anki/gr/vulkan/DescriptorSet.h>
 #include <anki/gr/vulkan/DescriptorSet.h>
 #include <anki/gr/vulkan/CommandBufferExtra.h>
 #include <anki/gr/vulkan/CommandBufferExtra.h>
 #include <anki/gr/vulkan/PipelineLayout.h>
 #include <anki/gr/vulkan/PipelineLayout.h>
+#include <anki/gr/vulkan/PipelineCache.h>
 #include <anki/util/HashMap.h>
 #include <anki/util/HashMap.h>
 
 
 namespace anki
 namespace anki
@@ -174,8 +175,8 @@ public:
 
 
 	VkPipelineCache getPipelineCache() const
 	VkPipelineCache getPipelineCache() const
 	{
 	{
-		ANKI_ASSERT(m_pplineCache);
-		return m_pplineCache;
+		ANKI_ASSERT(m_pplineCache.m_cacheHandle);
+		return m_pplineCache.m_cacheHandle;
 	}
 	}
 
 
 	PipelineLayoutFactory& getPipelineLayoutFactory()
 	PipelineLayoutFactory& getPipelineLayoutFactory()
@@ -301,7 +302,7 @@ private:
 
 
 	QueryAllocator m_queryAlloc;
 	QueryAllocator m_queryAlloc;
 
 
-	VkPipelineCache m_pplineCache = VK_NULL_HANDLE;
+	PipelineCache m_pplineCache;
 
 
 	Bool8 m_r8g8b8ImagesSupported = false;
 	Bool8 m_r8g8b8ImagesSupported = false;
 	Bool8 m_s8ImagesSupported = false;
 	Bool8 m_s8ImagesSupported = false;

+ 122 - 0
src/anki/gr/vulkan/PipelineCache.cpp

@@ -0,0 +1,122 @@
+// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/gr/vulkan/PipelineCache.h>
+#include <anki/core/Config.h>
+#include <anki/util/Filesystem.h>
+#include <anki/util/File.h>
+
+namespace anki
+{
+
+Error PipelineCache::init(
+	VkDevice dev, VkPhysicalDevice pdev, CString cacheDir, const ConfigSet& cfg, GrAllocator<U8> alloc)
+{
+	ANKI_ASSERT(cacheDir && dev && pdev);
+	m_dumpSize = cfg.getNumber("gr.diskShaderCacheMaxSize");
+	m_dumpFilename.sprintf(alloc, "%s/vk_pipeline_cache", &cacheDir[0]);
+
+	// Try read the pipeline cache file.
+	DynamicArrayAuto<U8> diskDump(alloc);
+	if(fileExists(m_dumpFilename.toCString()))
+	{
+		File file;
+		ANKI_CHECK(file.open(m_dumpFilename.toCString(), FileOpenFlag::BINARY | FileOpenFlag::READ));
+
+		PtrSize diskDumpSize = file.getSize();
+		if(diskDumpSize <= sizeof(U8) * VK_UUID_SIZE)
+		{
+			ANKI_VK_LOGI("Pipeline cache dump appears to be empty: %s", &m_dumpFilename[0]);
+		}
+		else
+		{
+			// Get current pipeline UUID and compare it with the cache's
+			VkPhysicalDeviceProperties props;
+			vkGetPhysicalDeviceProperties(pdev, &props);
+
+			Array<U8, VK_UUID_SIZE> cacheUuid;
+			ANKI_CHECK(file.read(&cacheUuid[0], VK_UUID_SIZE));
+
+			if(memcmp(&cacheUuid[0], &props.pipelineCacheUUID[0], VK_UUID_SIZE) != 0)
+			{
+				ANKI_VK_LOGI("Pipeline cache dump is not compatible with the current device: %s", &m_dumpFilename[0]);
+			}
+			else
+			{
+				diskDump.create(diskDumpSize - VK_UUID_SIZE);
+				ANKI_CHECK(file.read(&diskDump[0], diskDumpSize - VK_UUID_SIZE));
+			}
+		}
+	}
+	else
+	{
+		ANKI_VK_LOGI("Pipeline cache dump not found: %s", &m_dumpFilename[0]);
+	}
+
+	// Create the cache
+	VkPipelineCacheCreateInfo ci = {};
+	ci.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
+	if(diskDump.getSize())
+	{
+		ANKI_VK_LOGI("Will load %zu bytes of pipeline cache", diskDump.getSize());
+		ci.initialDataSize = diskDump.getSize();
+		ci.pInitialData = &diskDump[0];
+	}
+
+	ANKI_VK_CHECK(vkCreatePipelineCache(dev, &ci, nullptr, &m_cacheHandle));
+
+	return ErrorCode::NONE;
+}
+
+void PipelineCache::destroy(VkDevice dev, VkPhysicalDevice pdev, GrAllocator<U8> alloc)
+{
+	ANKI_ASSERT(dev && pdev);
+	Error err = destroyInternal(dev, pdev, alloc);
+	if(err)
+	{
+		ANKI_VK_LOGE("An error occurred while storing the pipeline cache to disk. Will ignore");
+	}
+}
+
+Error PipelineCache::destroyInternal(VkDevice dev, VkPhysicalDevice pdev, GrAllocator<U8> alloc)
+{
+	if(m_cacheHandle)
+	{
+		// Get size of cache
+		size_t size = 0;
+		ANKI_VK_CHECK(vkGetPipelineCacheData(dev, m_cacheHandle, &size, nullptr));
+		size = min(size, m_dumpSize);
+
+		if(size > 0)
+		{
+			// Read cache
+			DynamicArrayAuto<U8> cacheData(alloc);
+			cacheData.create(size);
+			ANKI_VK_CHECK(vkGetPipelineCacheData(dev, m_cacheHandle, &size, &cacheData[0]));
+
+			// Write file
+			File file;
+			ANKI_CHECK(file.open(&m_dumpFilename[0], FileOpenFlag::BINARY | FileOpenFlag::WRITE));
+
+			VkPhysicalDeviceProperties props;
+			vkGetPhysicalDeviceProperties(pdev, &props);
+
+			ANKI_CHECK(file.write(&props.pipelineCacheUUID[0], VK_UUID_SIZE));
+			ANKI_CHECK(file.write(&cacheData[0], size));
+
+			ANKI_VK_LOGI("Dumped %zu bytes of the pipeline cache", size);
+		}
+
+		// Destroy cache
+		vkDestroyPipelineCache(dev, m_cacheHandle, nullptr);
+		m_cacheHandle = VK_NULL_HANDLE;
+	}
+
+	m_dumpFilename.destroy(alloc);
+
+	return ErrorCode::NONE;
+}
+
+} // end namespace anki

+ 38 - 0
src/anki/gr/vulkan/PipelineCache.h

@@ -0,0 +1,38 @@
+// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/gr/vulkan/Common.h>
+
+namespace anki
+{
+
+// Forward
+class ConfigSet;
+
+/// @addtogroup vulkan
+/// @{
+
+/// On disk pipeline cache.
+class PipelineCache
+{
+public:
+	VkPipelineCache m_cacheHandle = VK_NULL_HANDLE;
+
+	ANKI_USE_RESULT Error init(
+		VkDevice dev, VkPhysicalDevice pdev, CString cacheDir, const ConfigSet& cfg, GrAllocator<U8> alloc);
+
+	void destroy(VkDevice dev, VkPhysicalDevice pdev, GrAllocator<U8> alloc);
+
+private:
+	String m_dumpFilename;
+	PtrSize m_dumpSize = 0;
+
+	ANKI_USE_RESULT Error destroyInternal(VkDevice dev, VkPhysicalDevice pdev, GrAllocator<U8> alloc);
+};
+/// @}
+
+} // end namespace anki