Vulkan: De-duplicate pipelines when storing cache

The new variety of renderpasses with different transitions causes
duplication. Hopefully drivers are smart enough to re-use work
between similar pipelines as much as possible...
This commit is contained in:
Henrik Rydgård 2018-03-19 10:55:06 +01:00
parent 1dabccb453
commit 8f87a9f5c5
5 changed files with 34 additions and 10 deletions

View File

@ -135,10 +135,11 @@ public:
bool EnableDeviceExtension(const char *extension);
VkResult CreateDevice();
const std::string &InitError() { return init_error_; }
const std::string &InitError() const { return init_error_; }
VkDevice GetDevice() { return device_; }
VkInstance GetInstance() { return instance_; }
VkDevice GetDevice() const { return device_; }
VkInstance GetInstance() const { return instance_; }
uint32_t GetFlags() const { return flags_; }
VulkanDeleteList &Delete() { return globalDeleteList_; }

View File

@ -58,6 +58,12 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips,
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
}
// The graphics debugger always "needs" TRANSFER_SRC but in practice doesn't matter -
// unless validation is on. So let's only force it on when being validated, for now.
if (vulkan_->GetFlags() & VULKAN_FLAG_VALIDATE) {
image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
}
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &image_);
if (res != VK_SUCCESS) {
_assert_(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS);

View File

@ -1,5 +1,6 @@
#include <cstring>
#include <memory>
#include <set>
#include "profiler/profiler.h"
@ -526,12 +527,14 @@ void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, Sha
}
size_t seekPosOnFailure = ftell(file);
// Write the number of pipelines.
size = (uint32_t)pipelines_.size();
fwrite(&size, sizeof(size), 1, file);
bool failed = false;
int count = 0;
// Since we don't include the full pipeline key, there can be duplicates,
// caused by things like switching from buffered to non-buffered rendering.
// Make sure the set of pipelines we write is "unique".
std::set<StoredVulkanPipelineKey> keys;
pipelines_.Iterate([&](const VulkanPipelineKey &pkey, VulkanPipeline *value) {
if (failed)
return;
@ -550,10 +553,18 @@ void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, Sha
// NOTE: This is not a vtype, but a decoded vertex format.
key.vtxFmtId = pkey.vtxFmtId;
}
fwrite(&key, sizeof(key), 1, file);
count++;
keys.insert(key);
});
// Write the number of pipelines.
size = (uint32_t)keys.size();
fwrite(&size, sizeof(size), 1, file);
// Write the pipelines.
for (auto &key : keys) {
fwrite(&key, sizeof(key), 1, file);
}
if (failed) {
ERROR_LOG(G3D, "Failed to write pipeline cache, some shader was missing");
// Write a zero in the right place so it doesn't try to load the pipelines next time.
@ -562,7 +573,7 @@ void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, Sha
fwrite(&size, sizeof(size), 1, file);
return;
}
NOTICE_LOG(G3D, "Saved Vulkan pipeline ID cache (%d pipelines).", (int)count);
NOTICE_LOG(G3D, "Saved Vulkan pipeline ID cache (%d unique pipelines/%d).", (int)keys.size(), (int)pipelines_.size());
}
bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, DrawEngineCommon *drawEngine, VkPipelineLayout layout, VkRenderPass renderPass) {

View File

@ -17,6 +17,7 @@
#pragma once
#include <cstring>
#include "Common/Hashmaps.h"
#include "GPU/Common/VertexDecoderCommon.h"
@ -60,6 +61,11 @@ struct StoredVulkanPipelineKey {
FShaderID fShaderID;
uint32_t vtxFmtId;
bool useHWTransform;
// For std::set. Better zero-initialize the struct properly for this to work.
bool operator < (const StoredVulkanPipelineKey &other) const {
return memcmp(this, &other, sizeof(*this)) < 0;
}
};
enum PipelineFlags {

View File

@ -350,7 +350,7 @@ VulkanFragmentShader *ShaderManagerVulkan::GetFragmentShaderFromModule(VkShaderM
// instantaneous.
#define CACHE_HEADER_MAGIC 0xff51f420
#define CACHE_VERSION 5
#define CACHE_VERSION 6
struct VulkanCacheHeader {
uint32_t magic;
uint32_t version;