mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-18 13:54:16 +01:00
[dxvk] Removed on-disk pipeline cache
Drivers from both major vendors implement their own shader cache already, and storing a cache per game causes more issues than it solves. Should fix #261.
This commit is contained in:
parent
8a4e1d11b7
commit
d68d62f837
@ -107,8 +107,6 @@ namespace dxvk {
|
||||
auto t1 = std::chrono::high_resolution_clock::now();
|
||||
auto td = std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0);
|
||||
Logger::debug(str::format("DxvkComputePipeline: Finished in ", td.count(), " ms"));
|
||||
|
||||
m_cache->update();
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
|
@ -184,7 +184,6 @@ namespace dxvk {
|
||||
DxvkStatCounters result;
|
||||
result.setCtr(DxvkStatCounter::MemoryAllocated, mem.memoryAllocated);
|
||||
result.setCtr(DxvkStatCounter::MemoryUsed, mem.memoryUsed);
|
||||
result.setCtr(DxvkStatCounter::PipeCacheSize, m_pipelineCache->getCacheSize());
|
||||
|
||||
std::lock_guard<sync::Spinlock> lock(m_statLock);
|
||||
result.merge(m_statCounters);
|
||||
|
@ -265,8 +265,6 @@ namespace dxvk {
|
||||
auto t1 = std::chrono::high_resolution_clock::now();
|
||||
auto td = std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0);
|
||||
Logger::debug(str::format("DxvkGraphicsPipeline: Finished in ", td.count(), " ms"));
|
||||
|
||||
m_cache->update();
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
|
@ -4,19 +4,13 @@ namespace dxvk {
|
||||
|
||||
DxvkPipelineCache::DxvkPipelineCache(
|
||||
const Rc<vk::DeviceFn>& vkd)
|
||||
: m_vkd (vkd),
|
||||
m_fileName (getFileName()),
|
||||
m_updateStop (0),
|
||||
m_updateCounter (0),
|
||||
m_updateThread ([this] { this->runThread(); }) {
|
||||
auto initialData = this->loadPipelineCache();
|
||||
|
||||
: m_vkd(vkd) {
|
||||
VkPipelineCacheCreateInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
info.initialDataSize = initialData.size();
|
||||
info.pInitialData = initialData.data();
|
||||
info.initialDataSize = 0;
|
||||
info.pInitialData = nullptr;
|
||||
|
||||
if (m_vkd->vkCreatePipelineCache(m_vkd->device(),
|
||||
&info, nullptr, &m_handle) != VK_SUCCESS)
|
||||
@ -25,167 +19,8 @@ namespace dxvk {
|
||||
|
||||
|
||||
DxvkPipelineCache::~DxvkPipelineCache() {
|
||||
// Stop the shader cache update thread
|
||||
{ std::unique_lock<std::mutex> lock(m_updateMutex);
|
||||
m_updateStop = -1;
|
||||
m_updateCond.notify_one();
|
||||
}
|
||||
|
||||
m_updateThread.join();
|
||||
|
||||
// Make sure we store the full cache again
|
||||
this->storePipelineCache(
|
||||
this->getPipelineCache());
|
||||
|
||||
m_vkd->vkDestroyPipelineCache(
|
||||
m_vkd->device(), m_handle, nullptr);
|
||||
}
|
||||
|
||||
|
||||
void DxvkPipelineCache::update() {
|
||||
m_updateCounter += 1;
|
||||
}
|
||||
|
||||
|
||||
size_t DxvkPipelineCache::getCacheSize() const {
|
||||
size_t cacheSize = 0;
|
||||
|
||||
m_vkd->vkGetPipelineCacheData(
|
||||
m_vkd->device(), m_handle, &cacheSize, nullptr);
|
||||
|
||||
return cacheSize;
|
||||
}
|
||||
|
||||
|
||||
void DxvkPipelineCache::runThread() {
|
||||
uint32_t prevUpdateCounter = 0;
|
||||
uint32_t currUpdateCounter = 0;
|
||||
|
||||
while (true) {
|
||||
// Periodically check whether we need to update once a minute.
|
||||
// We don't want to write the full pipeline cache with every
|
||||
// single update because that would cause unnecessary load.
|
||||
{ std::unique_lock<std::mutex> lock(m_updateMutex);
|
||||
|
||||
bool exit = m_updateCond.wait_for(lock,
|
||||
std::chrono::seconds(60),
|
||||
[this] { return m_updateStop != 0; });
|
||||
|
||||
if (exit)
|
||||
return;
|
||||
}
|
||||
|
||||
// Only update the cache if new pipelines
|
||||
// have been created in the meantime
|
||||
currUpdateCounter = m_updateCounter.load();
|
||||
|
||||
if (currUpdateCounter != prevUpdateCounter) {
|
||||
prevUpdateCounter = currUpdateCounter;
|
||||
this->storePipelineCache(this->getPipelineCache());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<char> DxvkPipelineCache::getPipelineCache() const {
|
||||
std::vector<char> cacheData;
|
||||
|
||||
VkResult status = VK_INCOMPLETE;
|
||||
|
||||
while (status == VK_INCOMPLETE) {
|
||||
size_t cacheSize = 0;
|
||||
|
||||
if (m_vkd->vkGetPipelineCacheData(m_vkd->device(),
|
||||
m_handle, &cacheSize, nullptr) != VK_SUCCESS) {
|
||||
Logger::warn("DxvkPipelineCache: Failed to retrieve cache size");
|
||||
break;
|
||||
}
|
||||
|
||||
cacheData.resize(cacheSize);
|
||||
|
||||
status = m_vkd->vkGetPipelineCacheData(m_vkd->device(),
|
||||
m_handle, &cacheSize, cacheData.data());
|
||||
}
|
||||
|
||||
if (status != VK_SUCCESS) {
|
||||
Logger::warn("DxvkPipelineCache: Failed to retrieve cache data");
|
||||
cacheData.resize(0);
|
||||
}
|
||||
|
||||
return cacheData;
|
||||
}
|
||||
|
||||
|
||||
std::vector<char> DxvkPipelineCache::loadPipelineCache() const {
|
||||
std::vector<char> cacheData;
|
||||
|
||||
if (m_fileName.size() == 0) {
|
||||
Logger::warn("DxvkPipelineCache: Failed to locate cache file");
|
||||
return cacheData;
|
||||
}
|
||||
|
||||
auto cacheFile = std::ifstream(m_fileName,
|
||||
std::ios_base::binary | std::ios_base::ate);
|
||||
|
||||
if (!cacheFile.good()) {
|
||||
Logger::warn("DxvkPipelineCache: Failed to read cache file");
|
||||
return cacheData;
|
||||
}
|
||||
|
||||
std::streamsize cacheSize = cacheFile.tellg();
|
||||
cacheFile.seekg(0, std::ios_base::beg);
|
||||
cacheData.resize(cacheSize);
|
||||
|
||||
if (!cacheFile.read(cacheData.data(), cacheData.size())) {
|
||||
Logger::warn("DxvkPipelineCache: Failed to read cache file");
|
||||
cacheData.resize(0);
|
||||
}
|
||||
|
||||
Logger::debug(str::format(
|
||||
"DxvkPipelineCache: Read ", cacheData.size(),
|
||||
" bytes from ", m_fileName));
|
||||
return cacheData;
|
||||
}
|
||||
|
||||
|
||||
void DxvkPipelineCache::storePipelineCache(const std::vector<char>& cacheData) const {
|
||||
if (m_fileName.size() == 0) {
|
||||
Logger::warn("DxvkPipelineCache: Failed to locate cache file");
|
||||
return;
|
||||
}
|
||||
|
||||
auto cacheFile = std::ofstream(m_fileName,
|
||||
std::ios_base::binary | std::ios_base::trunc);
|
||||
|
||||
if (!cacheFile.good()) {
|
||||
Logger::warn("DxvkPipelineCache: Failed to open cache file");
|
||||
return;
|
||||
}
|
||||
|
||||
cacheFile.write(cacheData.data(), cacheData.size());
|
||||
|
||||
if (!cacheFile.good()) {
|
||||
Logger::warn("DxvkPipelineCache: Failed to write shader cache file");
|
||||
return;
|
||||
}
|
||||
|
||||
Logger::debug(str::format(
|
||||
"DxvkPipelineCache: Wrote ", cacheData.size(),
|
||||
" bytes to ", m_fileName));
|
||||
}
|
||||
|
||||
|
||||
std::string DxvkPipelineCache::getFileName() {
|
||||
const auto exeName = env::getExeName();
|
||||
const auto filename = Sha1Hash::compute(
|
||||
reinterpret_cast<const uint8_t*>(exeName.c_str()), exeName.size());
|
||||
|
||||
const auto temp = env::getTempDirectory();
|
||||
|
||||
if (temp.size() != 0)
|
||||
return str::format(temp, filename.toString(), ".pipecache");
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -34,45 +34,11 @@ namespace dxvk {
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sends an update signal
|
||||
*
|
||||
* Notifies the update thread that the
|
||||
* pipeline cache should be updated.
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* \brief Queries pipeline cache size
|
||||
* \returns Cache size, in bytes
|
||||
*/
|
||||
size_t getCacheSize() const;
|
||||
|
||||
private:
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
VkPipelineCache m_handle;
|
||||
|
||||
std::string m_fileName;
|
||||
|
||||
std::atomic<uint32_t> m_updateStop;
|
||||
std::atomic<uint32_t> m_updateCounter;
|
||||
|
||||
std::mutex m_updateMutex;
|
||||
std::condition_variable m_updateCond;
|
||||
std::thread m_updateThread;
|
||||
|
||||
void runThread();
|
||||
|
||||
std::vector<char> getPipelineCache() const;
|
||||
|
||||
std::vector<char> loadPipelineCache() const;
|
||||
|
||||
void storePipelineCache(
|
||||
const std::vector<char>& cacheData) const;
|
||||
|
||||
static std::string getFileName();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ namespace dxvk {
|
||||
MemoryUsed, ///< Amount of memory used
|
||||
PipeCountGraphics, ///< Number of graphics pipelines
|
||||
PipeCountCompute, ///< Number of compute pipelines
|
||||
PipeCacheSize, ///< Pipeline cache size
|
||||
QueueSubmitCount, ///< Number of command buffer submissions
|
||||
QueuePresentCount, ///< Number of present calls / frames
|
||||
NumCounters, ///< Number of counters available
|
||||
|
@ -98,20 +98,12 @@ namespace dxvk::hud {
|
||||
const Rc<DxvkContext>& context,
|
||||
HudTextRenderer& renderer,
|
||||
HudPos position) {
|
||||
constexpr uint64_t kib = 1024;
|
||||
constexpr uint64_t mib = 1024 * 1024;
|
||||
|
||||
const uint64_t gpCount = m_prevCounters.getCtr(DxvkStatCounter::PipeCountGraphics);
|
||||
const uint64_t cpCount = m_prevCounters.getCtr(DxvkStatCounter::PipeCountCompute);
|
||||
const uint64_t pcSize = m_prevCounters.getCtr(DxvkStatCounter::PipeCacheSize);
|
||||
|
||||
const std::string strGpCount = str::format("Graphics pipelines: ", gpCount);
|
||||
const std::string strCpCount = str::format("Compute pipelines: ", cpCount);
|
||||
|
||||
const std::string strPcSize = str::format("Pipeline cache: ", pcSize >= mib
|
||||
? str::format(pcSize / mib, ".", ((10 * pcSize) / mib) % 10, " MB")
|
||||
: str::format(pcSize / kib, " kB"));
|
||||
|
||||
renderer.drawText(context, 16.0f,
|
||||
{ position.x, position.y },
|
||||
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||
@ -122,12 +114,7 @@ namespace dxvk::hud {
|
||||
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||
strCpCount);
|
||||
|
||||
renderer.drawText(context, 16.0f,
|
||||
{ position.x, position.y + 40.0f },
|
||||
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||
strPcSize);
|
||||
|
||||
return { position.x, position.y + 64.0f };
|
||||
return { position.x, position.y + 44.0f };
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user