diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index 3bb4080694..ac4d98148f 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -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_; } diff --git a/Common/Vulkan/VulkanImage.cpp b/Common/Vulkan/VulkanImage.cpp index 70b561b036..4e8b841517 100644 --- a/Common/Vulkan/VulkanImage.cpp +++ b/Common/Vulkan/VulkanImage.cpp @@ -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); diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 6e9a62aeb9..70870997fb 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -1,5 +1,6 @@ #include #include +#include #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 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) { diff --git a/GPU/Vulkan/PipelineManagerVulkan.h b/GPU/Vulkan/PipelineManagerVulkan.h index 6cf98c7ed4..60a0582c38 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.h +++ b/GPU/Vulkan/PipelineManagerVulkan.h @@ -17,6 +17,7 @@ #pragma once +#include #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 { diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index b753ebd19a..666f47aa52 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -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;