Use raw pointers for the routine const cache.

As these are touched by pixel shaders, this is extraordinarily hot code, and the cost of ref-counting by shared_ptr can really impact performance.

As the const cache is updated at well known sync points, the queryConstCache method is safe to return a raw pointer to the routine.

Bug: b/137524292
Bug: b/137649247
Change-Id: I2ae1f159467eb27b918344714cef1963f3b24a45
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/34453
Presubmit-Ready: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Device/LRUCache.hpp b/src/Device/LRUCache.hpp
index 9f6c120..083861e 100644
--- a/src/Device/LRUCache.hpp
+++ b/src/Device/LRUCache.hpp
@@ -63,7 +63,7 @@
 		}
 
 		void updateConstCache();
-		Data queryConstCache(const Key &key) const;
+		const Data& queryConstCache(const Key &key) const;
 
 	private:
 		void clearConstCache();
@@ -215,10 +215,11 @@
 	}
 
 	template<class Key, class Data>
-	Data LRUConstCache<Key, Data>::queryConstCache(const Key &key) const
+	const Data& LRUConstCache<Key, Data>::queryConstCache(const Key &key) const
 	{
 		auto it = constCache.find(key);
-		return (it != constCache.end()) ? it->second : nullptr;
+		static Data null = {};
+		return (it != constCache.end()) ? it->second : null;
 	}
 }
 
diff --git a/src/Pipeline/SpirvShaderSampling.cpp b/src/Pipeline/SpirvShaderSampling.cpp
index 5e56977..6a232fd 100644
--- a/src/Pipeline/SpirvShaderSampling.cpp
+++ b/src/Pipeline/SpirvShaderSampling.cpp
@@ -40,8 +40,7 @@
 
 	ASSERT(imageDescriptor->device);
 
-	auto routine = imageDescriptor->device->findInConstCache(key);
-	if(routine)
+	if(auto routine = imageDescriptor->device->findInConstCache(key))
 	{
 		return (ImageSampler*)(routine->getEntry());
 	}
@@ -49,7 +48,7 @@
 	std::unique_lock<std::mutex> lock(imageDescriptor->device->getSamplingRoutineCacheMutex());
 	vk::Device::SamplingRoutineCache* cache = imageDescriptor->device->getSamplingRoutineCache();
 
-	routine = cache->query(key);
+	auto routine = cache->query(key);
 	if(routine)
 	{
 		return (ImageSampler*)(routine->getEntry());
diff --git a/src/Vulkan/VkDevice.cpp b/src/Vulkan/VkDevice.cpp
index 230d2d0..bceb001 100644
--- a/src/Vulkan/VkDevice.cpp
+++ b/src/Vulkan/VkDevice.cpp
@@ -47,9 +47,9 @@
 	cache.add(hash(key), routine);
 }
 
-std::shared_ptr<rr::Routine> Device::SamplingRoutineCache::queryConst(const vk::Device::SamplingRoutineCache::Key& key) const
+rr::Routine* Device::SamplingRoutineCache::queryConst(const vk::Device::SamplingRoutineCache::Key& key) const
 {
-	return cache.queryConstCache(hash(key));
+	return cache.queryConstCache(hash(key)).get();
 }
 
 void Device::SamplingRoutineCache::updateConstCache()
@@ -251,7 +251,7 @@
 	return samplingRoutineCache.get();
 }
 
-std::shared_ptr<rr::Routine> Device::findInConstCache(const SamplingRoutineCache::Key& key) const
+rr::Routine* Device::findInConstCache(const SamplingRoutineCache::Key& key) const
 {
 	return samplingRoutineCache->queryConst(key);
 }
diff --git a/src/Vulkan/VkDevice.hpp b/src/Vulkan/VkDevice.hpp
index 721dda2..742d662 100644
--- a/src/Vulkan/VkDevice.hpp
+++ b/src/Vulkan/VkDevice.hpp
@@ -70,7 +70,7 @@
 		std::shared_ptr<rr::Routine> query(const Key& key) const;
 		void add(const Key& key, const std::shared_ptr<rr::Routine>& routine);
 
-		std::shared_ptr<rr::Routine> queryConst(const Key& key) const;
+		rr::Routine* queryConst(const Key& key) const;
 		void updateConstCache();
 
 		static std::size_t hash(const Key &key);
@@ -81,7 +81,7 @@
 
 	SamplingRoutineCache* getSamplingRoutineCache() const;
 	std::mutex& getSamplingRoutineCacheMutex();
-	std::shared_ptr<rr::Routine> findInConstCache(const SamplingRoutineCache::Key& key) const;
+	rr::Routine* findInConstCache(const SamplingRoutineCache::Key& key) const;
 	void updateSamplingRoutineConstCache();
 
 private: