Uniquely identify sampler state
To avoid re-generating sampling routines for sampler with identical
state, keep a map of sampler state to 32-bit integer identifiers.
Bug: b/151235334
Change-Id: I105151675afbf29bd29585e866b8cd976f66fb49
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/42468
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Vulkan/VkDevice.cpp b/src/Vulkan/VkDevice.cpp
index 7f9bcc0..33c9731 100644
--- a/src/Vulkan/VkDevice.cpp
+++ b/src/Vulkan/VkDevice.cpp
@@ -59,6 +59,44 @@
cache.updateConstCache();
}
+Device::SamplerIndexer::~SamplerIndexer()
+{
+ ASSERT(map.empty());
+}
+
+uint32_t Device::SamplerIndexer::index(const SamplerState &samplerState)
+{
+ std::lock_guard<std::mutex> lock(mutex);
+
+ auto it = map.find(samplerState);
+
+ if(it != map.end())
+ {
+ it->second.count++;
+ return it->second.id;
+ }
+
+ nextID++;
+
+ map.emplace(samplerState, Identifier{ nextID, 1 });
+
+ return nextID;
+}
+
+void Device::SamplerIndexer::remove(const SamplerState &samplerState)
+{
+ std::lock_guard<std::mutex> lock(mutex);
+
+ auto it = map.find(samplerState);
+ ASSERT(it != map.end());
+
+ auto count = --it->second.count;
+ if(count == 0)
+ {
+ map.erase(it);
+ }
+}
+
Device::Device(const VkDeviceCreateInfo *pCreateInfo, void *mem, PhysicalDevice *physicalDevice, const VkPhysicalDeviceFeatures *enabledFeatures, const std::shared_ptr<marl::Scheduler> &scheduler)
: physicalDevice(physicalDevice)
, queues(reinterpret_cast<Queue *>(mem))
@@ -99,6 +137,7 @@
// FIXME (b/119409619): use an allocator here so we can control all memory allocations
blitter.reset(new sw::Blitter());
samplingRoutineCache.reset(new SamplingRoutineCache());
+ samplerIndexer.reset(new SamplerIndexer());
#ifdef ENABLE_VK_DEBUGGER
static auto port = getenv("VK_DEBUGGER_PORT");
@@ -279,4 +318,14 @@
return samplingRoutineCacheMutex;
}
+uint32_t Device::indexSampler(const SamplerState &samplerState)
+{
+ return samplerIndexer->index(samplerState);
+}
+
+void Device::removeSampler(const SamplerState &samplerState)
+{
+ samplerIndexer->remove(samplerState);
+}
+
} // namespace vk
diff --git a/src/Vulkan/VkDevice.hpp b/src/Vulkan/VkDevice.hpp
index 0a19f50..c2ba927 100644
--- a/src/Vulkan/VkDevice.hpp
+++ b/src/Vulkan/VkDevice.hpp
@@ -16,8 +16,11 @@
#define VK_DEVICE_HPP_
#include "VkObject.hpp"
+#include "VkSampler.hpp"
#include "Device/LRUCache.hpp"
#include "Reactor/Routine.hpp"
+
+#include <map>
#include <memory>
#include <mutex>
@@ -98,6 +101,30 @@
rr::Routine *findInConstCache(const SamplingRoutineCache::Key &key) const;
void updateSamplingRoutineConstCache();
+ class SamplerIndexer
+ {
+ public:
+ ~SamplerIndexer();
+
+ uint32_t index(const SamplerState &samplerState);
+ void remove(const SamplerState &samplerState);
+
+ private:
+ struct Identifier
+ {
+ uint32_t id;
+ uint32_t count; // Number of samplers sharing this state identifier.
+ };
+
+ std::map<SamplerState, Identifier> map; // guarded by mutex
+ std::mutex mutex;
+
+ uint32_t nextID = 0;
+ };
+
+ uint32_t indexSampler(const SamplerState &samplerState);
+ void removeSampler(const SamplerState &samplerState);
+
std::shared_ptr<vk::dbg::Context> getDebuggerContext() const
{
#ifdef ENABLE_VK_DEBUGGER
@@ -118,7 +145,9 @@
typedef char ExtensionName[VK_MAX_EXTENSION_NAME_SIZE];
ExtensionName *extensions = nullptr;
const VkPhysicalDeviceFeatures enabledFeatures = {};
+
std::shared_ptr<marl::Scheduler> scheduler;
+ std::unique_ptr<SamplerIndexer> samplerIndexer;
#ifdef ENABLE_VK_DEBUGGER
struct
diff --git a/src/Vulkan/VkSampler.cpp b/src/Vulkan/VkSampler.cpp
index e5adb19..11cb00e 100644
--- a/src/Vulkan/VkSampler.cpp
+++ b/src/Vulkan/VkSampler.cpp
@@ -16,8 +16,6 @@
namespace vk {
-std::atomic<uint32_t> Sampler::nextID(1);
-
SamplerState::SamplerState(const VkSamplerCreateInfo *pCreateInfo, const vk::SamplerYcbcrConversion *ycbcrConversion)
: Memset(this, 0)
, magFilter(pCreateInfo->magFilter)
@@ -44,8 +42,9 @@
}
}
-Sampler::Sampler(const VkSamplerCreateInfo *pCreateInfo, void *mem, const vk::SamplerYcbcrConversion *ycbcrConversion)
- : SamplerState(pCreateInfo, ycbcrConversion)
+Sampler::Sampler(const VkSamplerCreateInfo *pCreateInfo, void *mem, const SamplerState &samplerState, uint32_t samplerID)
+ : SamplerState(samplerState)
+ , id(samplerID)
{
}
diff --git a/src/Vulkan/VkSampler.hpp b/src/Vulkan/VkSampler.hpp
index 84d3373..d2f51ac 100644
--- a/src/Vulkan/VkSampler.hpp
+++ b/src/Vulkan/VkSampler.hpp
@@ -58,17 +58,14 @@
class Sampler : public Object<Sampler, VkSampler>, public SamplerState
{
public:
- Sampler(const VkSamplerCreateInfo *pCreateInfo, void *mem, const vk::SamplerYcbcrConversion *ycbcrConversion);
+ Sampler(const VkSamplerCreateInfo *pCreateInfo, void *mem, const SamplerState &samplerState, uint32_t samplerID);
static size_t ComputeRequiredAllocationSize(const VkSamplerCreateInfo *pCreateInfo)
{
return 0;
}
- const uint32_t id = nextID++;
-
-private:
- static std::atomic<uint32_t> nextID;
+ const uint32_t id = 0;
};
class SamplerYcbcrConversion : public Object<SamplerYcbcrConversion, VkSamplerYcbcrConversion>
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index c583748..3e3e648 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -1857,7 +1857,18 @@
extensionCreateInfo = extensionCreateInfo->pNext;
}
- return vk::Sampler::Create(pAllocator, pCreateInfo, pSampler, ycbcrConversion);
+ vk::SamplerState samplerState(pCreateInfo, ycbcrConversion);
+ uint32_t samplerID = vk::Cast(device)->indexSampler(samplerState);
+
+ VkResult result = vk::Sampler::Create(pAllocator, pCreateInfo, pSampler, samplerState, samplerID);
+
+ if(*pSampler == VK_NULL_HANDLE)
+ {
+ ASSERT(result != VK_SUCCESS);
+ vk::Cast(device)->removeSampler(samplerState);
+ }
+
+ return result;
}
VKAPI_ATTR void VKAPI_CALL vkDestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator)
@@ -1865,7 +1876,12 @@
TRACE("(VkDevice device = %p, VkSampler sampler = %p, const VkAllocationCallbacks* pAllocator = %p)",
device, static_cast<void *>(sampler), pAllocator);
- vk::destroy(sampler, pAllocator);
+ if(sampler != VK_NULL_HANDLE)
+ {
+ vk::Cast(device)->removeSampler(*vk::Cast(sampler));
+
+ vk::destroy(sampler, pAllocator);
+ }
}
VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout)