mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +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 t1 = std::chrono::high_resolution_clock::now();
|
||||||
auto td = std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0);
|
auto td = std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0);
|
||||||
Logger::debug(str::format("DxvkComputePipeline: Finished in ", td.count(), " ms"));
|
Logger::debug(str::format("DxvkComputePipeline: Finished in ", td.count(), " ms"));
|
||||||
|
|
||||||
m_cache->update();
|
|
||||||
return pipeline;
|
return pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +184,6 @@ namespace dxvk {
|
|||||||
DxvkStatCounters result;
|
DxvkStatCounters result;
|
||||||
result.setCtr(DxvkStatCounter::MemoryAllocated, mem.memoryAllocated);
|
result.setCtr(DxvkStatCounter::MemoryAllocated, mem.memoryAllocated);
|
||||||
result.setCtr(DxvkStatCounter::MemoryUsed, mem.memoryUsed);
|
result.setCtr(DxvkStatCounter::MemoryUsed, mem.memoryUsed);
|
||||||
result.setCtr(DxvkStatCounter::PipeCacheSize, m_pipelineCache->getCacheSize());
|
|
||||||
|
|
||||||
std::lock_guard<sync::Spinlock> lock(m_statLock);
|
std::lock_guard<sync::Spinlock> lock(m_statLock);
|
||||||
result.merge(m_statCounters);
|
result.merge(m_statCounters);
|
||||||
|
@ -265,8 +265,6 @@ namespace dxvk {
|
|||||||
auto t1 = std::chrono::high_resolution_clock::now();
|
auto t1 = std::chrono::high_resolution_clock::now();
|
||||||
auto td = std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0);
|
auto td = std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0);
|
||||||
Logger::debug(str::format("DxvkGraphicsPipeline: Finished in ", td.count(), " ms"));
|
Logger::debug(str::format("DxvkGraphicsPipeline: Finished in ", td.count(), " ms"));
|
||||||
|
|
||||||
m_cache->update();
|
|
||||||
return pipeline;
|
return pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,19 +4,13 @@ namespace dxvk {
|
|||||||
|
|
||||||
DxvkPipelineCache::DxvkPipelineCache(
|
DxvkPipelineCache::DxvkPipelineCache(
|
||||||
const Rc<vk::DeviceFn>& vkd)
|
const Rc<vk::DeviceFn>& vkd)
|
||||||
: m_vkd (vkd),
|
: m_vkd(vkd) {
|
||||||
m_fileName (getFileName()),
|
|
||||||
m_updateStop (0),
|
|
||||||
m_updateCounter (0),
|
|
||||||
m_updateThread ([this] { this->runThread(); }) {
|
|
||||||
auto initialData = this->loadPipelineCache();
|
|
||||||
|
|
||||||
VkPipelineCacheCreateInfo info;
|
VkPipelineCacheCreateInfo info;
|
||||||
info.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
|
info.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
|
||||||
info.pNext = nullptr;
|
info.pNext = nullptr;
|
||||||
info.flags = 0;
|
info.flags = 0;
|
||||||
info.initialDataSize = initialData.size();
|
info.initialDataSize = 0;
|
||||||
info.pInitialData = initialData.data();
|
info.pInitialData = nullptr;
|
||||||
|
|
||||||
if (m_vkd->vkCreatePipelineCache(m_vkd->device(),
|
if (m_vkd->vkCreatePipelineCache(m_vkd->device(),
|
||||||
&info, nullptr, &m_handle) != VK_SUCCESS)
|
&info, nullptr, &m_handle) != VK_SUCCESS)
|
||||||
@ -25,167 +19,8 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
DxvkPipelineCache::~DxvkPipelineCache() {
|
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->vkDestroyPipelineCache(
|
||||||
m_vkd->device(), m_handle, nullptr);
|
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;
|
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:
|
private:
|
||||||
|
|
||||||
Rc<vk::DeviceFn> m_vkd;
|
Rc<vk::DeviceFn> m_vkd;
|
||||||
VkPipelineCache m_handle;
|
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
|
MemoryUsed, ///< Amount of memory used
|
||||||
PipeCountGraphics, ///< Number of graphics pipelines
|
PipeCountGraphics, ///< Number of graphics pipelines
|
||||||
PipeCountCompute, ///< Number of compute pipelines
|
PipeCountCompute, ///< Number of compute pipelines
|
||||||
PipeCacheSize, ///< Pipeline cache size
|
|
||||||
QueueSubmitCount, ///< Number of command buffer submissions
|
QueueSubmitCount, ///< Number of command buffer submissions
|
||||||
QueuePresentCount, ///< Number of present calls / frames
|
QueuePresentCount, ///< Number of present calls / frames
|
||||||
NumCounters, ///< Number of counters available
|
NumCounters, ///< Number of counters available
|
||||||
|
@ -98,20 +98,12 @@ namespace dxvk::hud {
|
|||||||
const Rc<DxvkContext>& context,
|
const Rc<DxvkContext>& context,
|
||||||
HudTextRenderer& renderer,
|
HudTextRenderer& renderer,
|
||||||
HudPos position) {
|
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 gpCount = m_prevCounters.getCtr(DxvkStatCounter::PipeCountGraphics);
|
||||||
const uint64_t cpCount = m_prevCounters.getCtr(DxvkStatCounter::PipeCountCompute);
|
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 strGpCount = str::format("Graphics pipelines: ", gpCount);
|
||||||
const std::string strCpCount = str::format("Compute pipelines: ", cpCount);
|
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,
|
renderer.drawText(context, 16.0f,
|
||||||
{ position.x, position.y },
|
{ position.x, position.y },
|
||||||
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||||
@ -122,12 +114,7 @@ namespace dxvk::hud {
|
|||||||
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||||
strCpCount);
|
strCpCount);
|
||||||
|
|
||||||
renderer.drawText(context, 16.0f,
|
return { position.x, position.y + 44.0f };
|
||||||
{ position.x, position.y + 40.0f },
|
|
||||||
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
|
||||||
strPcSize);
|
|
||||||
|
|
||||||
return { position.x, position.y + 64.0f };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user