mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-23 12:32:07 +00:00
Add vulkan pipeline cache
This commit is contained in:
parent
e99bf2b036
commit
7b864fd665
5 changed files with 172 additions and 2 deletions
|
@ -236,6 +236,7 @@ class ComputePipelineBuilder
|
|||
public:
|
||||
ComputePipelineBuilder();
|
||||
|
||||
ComputePipelineBuilder& Cache(VulkanPipelineCache* cache);
|
||||
ComputePipelineBuilder& Layout(VulkanPipelineLayout *layout);
|
||||
ComputePipelineBuilder& ComputeShader(VulkanShader *shader);
|
||||
ComputePipelineBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
||||
|
@ -245,6 +246,7 @@ public:
|
|||
private:
|
||||
VkComputePipelineCreateInfo pipelineInfo = {};
|
||||
VkPipelineShaderStageCreateInfo stageInfo = {};
|
||||
VulkanPipelineCache* cache = nullptr;
|
||||
const char* debugName = nullptr;
|
||||
};
|
||||
|
||||
|
@ -324,6 +326,7 @@ class GraphicsPipelineBuilder
|
|||
public:
|
||||
GraphicsPipelineBuilder();
|
||||
|
||||
GraphicsPipelineBuilder& Cache(VulkanPipelineCache* cache);
|
||||
GraphicsPipelineBuilder& Subpass(int subpass);
|
||||
GraphicsPipelineBuilder& Layout(VulkanPipelineLayout *layout);
|
||||
GraphicsPipelineBuilder& RenderPass(VulkanRenderPass *renderPass);
|
||||
|
@ -377,6 +380,7 @@ private:
|
|||
std::vector<VkVertexInputAttributeDescription> vertexInputAttributes;
|
||||
std::vector<VkDynamicState> dynamicStates;
|
||||
|
||||
VulkanPipelineCache* cache = nullptr;
|
||||
const char* debugName = nullptr;
|
||||
};
|
||||
|
||||
|
@ -399,6 +403,24 @@ private:
|
|||
const char* debugName = nullptr;
|
||||
};
|
||||
|
||||
class PipelineCacheBuilder
|
||||
{
|
||||
public:
|
||||
PipelineCacheBuilder();
|
||||
|
||||
PipelineCacheBuilder& InitialData(const void* data, size_t size);
|
||||
PipelineCacheBuilder& Flags(VkPipelineCacheCreateFlags flags);
|
||||
|
||||
PipelineCacheBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
||||
|
||||
std::unique_ptr<VulkanPipelineCache> Create(VulkanDevice* device);
|
||||
|
||||
private:
|
||||
VkPipelineCacheCreateInfo pipelineCacheInfo = {};
|
||||
std::vector<uint8_t> initData;
|
||||
const char* debugName = nullptr;
|
||||
};
|
||||
|
||||
class RenderPassBuilder
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -305,6 +305,24 @@ private:
|
|||
VulkanPipelineLayout &operator=(const VulkanPipelineLayout &) = delete;
|
||||
};
|
||||
|
||||
class VulkanPipelineCache
|
||||
{
|
||||
public:
|
||||
VulkanPipelineCache(VulkanDevice* device, VkPipelineCache cache);
|
||||
~VulkanPipelineCache();
|
||||
|
||||
void SetDebugName(const char* name) { device->SetObjectName(name, (uint64_t)cache, VK_OBJECT_TYPE_PIPELINE_CACHE); }
|
||||
|
||||
std::vector<uint8_t> GetCacheData();
|
||||
|
||||
VulkanDevice* device;
|
||||
VkPipelineCache cache;
|
||||
|
||||
private:
|
||||
VulkanPipelineCache(const VulkanPipelineCache&) = delete;
|
||||
VulkanPipelineCache& operator=(const VulkanPipelineCache&) = delete;
|
||||
};
|
||||
|
||||
class VulkanRenderPass
|
||||
{
|
||||
public:
|
||||
|
@ -1179,6 +1197,33 @@ inline VulkanPipelineLayout::~VulkanPipelineLayout()
|
|||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline VulkanPipelineCache::VulkanPipelineCache(VulkanDevice* device, VkPipelineCache cache) : device(device), cache(cache)
|
||||
{
|
||||
}
|
||||
|
||||
inline VulkanPipelineCache::~VulkanPipelineCache()
|
||||
{
|
||||
vkDestroyPipelineCache(device->device, cache, nullptr);
|
||||
}
|
||||
|
||||
inline std::vector<uint8_t> VulkanPipelineCache::GetCacheData()
|
||||
{
|
||||
size_t dataSize = 0;
|
||||
VkResult result = vkGetPipelineCacheData(device->device, cache, &dataSize, nullptr);
|
||||
CheckVulkanError(result, "Could not get cache data size");
|
||||
|
||||
std::vector<uint8_t> buffer;
|
||||
buffer.resize(dataSize);
|
||||
result = vkGetPipelineCacheData(device->device, cache, &dataSize, buffer.data());
|
||||
if (result == VK_INCOMPLETE)
|
||||
VulkanError("Could not get cache data (incomplete)");
|
||||
CheckVulkanError(result, "Could not get cache data");
|
||||
buffer.resize(dataSize);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline VulkanRenderPass::VulkanRenderPass(VulkanDevice *device, VkRenderPass renderPass) : device(device), renderPass(renderPass)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -589,6 +589,12 @@ ComputePipelineBuilder::ComputePipelineBuilder()
|
|||
stageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
}
|
||||
|
||||
ComputePipelineBuilder& ComputePipelineBuilder::Cache(VulkanPipelineCache* cache)
|
||||
{
|
||||
this->cache = cache;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ComputePipelineBuilder& ComputePipelineBuilder::Layout(VulkanPipelineLayout* layout)
|
||||
{
|
||||
pipelineInfo.layout = layout->layout;
|
||||
|
@ -608,7 +614,7 @@ ComputePipelineBuilder& ComputePipelineBuilder::ComputeShader(VulkanShader* shad
|
|||
std::unique_ptr<VulkanPipeline> ComputePipelineBuilder::Create(VulkanDevice* device)
|
||||
{
|
||||
VkPipeline pipeline;
|
||||
vkCreateComputePipelines(device->device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline);
|
||||
vkCreateComputePipelines(device->device, cache ? cache->cache : VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline);
|
||||
auto obj = std::make_unique<VulkanPipeline>(device, pipeline);
|
||||
if (debugName)
|
||||
obj->SetDebugName(debugName);
|
||||
|
@ -871,6 +877,12 @@ GraphicsPipelineBuilder& GraphicsPipelineBuilder::RasterizationSamples(VkSampleC
|
|||
return *this;
|
||||
}
|
||||
|
||||
GraphicsPipelineBuilder& GraphicsPipelineBuilder::Cache(VulkanPipelineCache* cache)
|
||||
{
|
||||
this->cache = cache;
|
||||
return *this;
|
||||
}
|
||||
|
||||
GraphicsPipelineBuilder& GraphicsPipelineBuilder::Subpass(int subpass)
|
||||
{
|
||||
pipelineInfo.subpass = subpass;
|
||||
|
@ -1087,7 +1099,7 @@ GraphicsPipelineBuilder& GraphicsPipelineBuilder::AddDynamicState(VkDynamicState
|
|||
std::unique_ptr<VulkanPipeline> GraphicsPipelineBuilder::Create(VulkanDevice* device)
|
||||
{
|
||||
VkPipeline pipeline = 0;
|
||||
VkResult result = vkCreateGraphicsPipelines(device->device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline);
|
||||
VkResult result = vkCreateGraphicsPipelines(device->device, cache ? cache->cache : VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline);
|
||||
CheckVulkanError(result, "Could not create graphics pipeline");
|
||||
auto obj = std::make_unique<VulkanPipeline>(device, pipeline);
|
||||
if (debugName)
|
||||
|
@ -1135,6 +1147,54 @@ std::unique_ptr<VulkanPipelineLayout> PipelineLayoutBuilder::Create(VulkanDevice
|
|||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PipelineCacheBuilder::PipelineCacheBuilder()
|
||||
{
|
||||
pipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
|
||||
}
|
||||
|
||||
PipelineCacheBuilder& PipelineCacheBuilder::InitialData(const void* data, size_t size)
|
||||
{
|
||||
initData.resize(size);
|
||||
memcpy(initData.data(), data, size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
PipelineCacheBuilder& PipelineCacheBuilder::Flags(VkPipelineCacheCreateFlags flags)
|
||||
{
|
||||
pipelineCacheInfo.flags = flags;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::unique_ptr<VulkanPipelineCache> PipelineCacheBuilder::Create(VulkanDevice* device)
|
||||
{
|
||||
pipelineCacheInfo.pInitialData = nullptr;
|
||||
pipelineCacheInfo.initialDataSize = 0;
|
||||
|
||||
// Check if the saved cache data is compatible with our device:
|
||||
if (initData.size() >= sizeof(VkPipelineCacheHeaderVersionOne))
|
||||
{
|
||||
VkPipelineCacheHeaderVersionOne* header = (VkPipelineCacheHeaderVersionOne*)initData.data();
|
||||
if (header->headerVersion == VK_PIPELINE_CACHE_HEADER_VERSION_ONE &&
|
||||
header->vendorID == device->PhysicalDevice.Properties.vendorID &&
|
||||
header->deviceID == device->PhysicalDevice.Properties.deviceID &&
|
||||
memcmp(header->pipelineCacheUUID, device->PhysicalDevice.Properties.pipelineCacheUUID, VK_UUID_SIZE) == 0)
|
||||
{
|
||||
pipelineCacheInfo.pInitialData = initData.data();
|
||||
pipelineCacheInfo.initialDataSize = initData.size();
|
||||
}
|
||||
}
|
||||
|
||||
VkPipelineCache pipelineCache;
|
||||
VkResult result = vkCreatePipelineCache(device->device, &pipelineCacheInfo, nullptr, &pipelineCache);
|
||||
CheckVulkanError(result, "Could not create pipeline cache");
|
||||
auto obj = std::make_unique<VulkanPipelineCache>(device, pipelineCache);
|
||||
if (debugName)
|
||||
obj->SetDebugName(debugName);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RenderPassBuilder::RenderPassBuilder()
|
||||
{
|
||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
|
|
|
@ -34,13 +34,49 @@
|
|||
#include "flatvertices.h"
|
||||
#include "hw_viewpointuniforms.h"
|
||||
#include "v_2ddrawer.h"
|
||||
#include "i_specialpaths.h"
|
||||
|
||||
VkRenderPassManager::VkRenderPassManager(VulkanRenderDevice* fb) : fb(fb)
|
||||
{
|
||||
FString path = M_GetCachePath(true);
|
||||
CreatePath(path);
|
||||
CacheFilename = path + "/pipelinecache.zdpc";
|
||||
|
||||
PipelineCacheBuilder builder;
|
||||
builder.DebugName("PipelineCache");
|
||||
|
||||
try
|
||||
{
|
||||
FileReader fr;
|
||||
if (fr.OpenFile(CacheFilename))
|
||||
{
|
||||
std::vector<uint8_t> data;
|
||||
data.resize(fr.GetLength());
|
||||
if (fr.Read(data.data(), data.size()) == data.size())
|
||||
{
|
||||
builder.InitialData(data.data(), data.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
|
||||
PipelineCache = builder.Create(fb->device.get());
|
||||
}
|
||||
|
||||
VkRenderPassManager::~VkRenderPassManager()
|
||||
{
|
||||
try
|
||||
{
|
||||
auto data = PipelineCache->GetCacheData();
|
||||
std::unique_ptr<FileWriter> fw(FileWriter::Open(CacheFilename));
|
||||
if (fw)
|
||||
fw->Write(data.data(), data.size());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void VkRenderPassManager::RenderBuffersReset()
|
||||
|
@ -206,6 +242,7 @@ VulkanPipeline *VkRenderPassSetup::GetPipeline(const VkPipelineKey &key)
|
|||
std::unique_ptr<VulkanPipeline> VkRenderPassSetup::CreatePipeline(const VkPipelineKey &key)
|
||||
{
|
||||
GraphicsPipelineBuilder builder;
|
||||
builder.Cache(fb->GetRenderPassManager()->GetCache());
|
||||
|
||||
VkShaderProgram *program;
|
||||
if (key.SpecialEffect != EFF_NONE)
|
||||
|
@ -332,6 +369,7 @@ void VkPPRenderPassSetup::CreatePipelineLayout(const VkPPRenderPassKey& key)
|
|||
void VkPPRenderPassSetup::CreatePipeline(const VkPPRenderPassKey& key)
|
||||
{
|
||||
GraphicsPipelineBuilder builder;
|
||||
builder.Cache(fb->GetRenderPassManager()->GetCache());
|
||||
builder.AddVertexShader(key.Shader->VertexShader.get());
|
||||
builder.AddFragmentShader(key.Shader->FragmentShader.get());
|
||||
|
||||
|
|
|
@ -135,6 +135,8 @@ public:
|
|||
|
||||
VkPPRenderPassSetup* GetPPRenderPass(const VkPPRenderPassKey& key);
|
||||
|
||||
VulkanPipelineCache* GetCache() { return PipelineCache.get(); }
|
||||
|
||||
private:
|
||||
VulkanRenderDevice* fb = nullptr;
|
||||
|
||||
|
@ -143,4 +145,7 @@ private:
|
|||
std::vector<VkVertexFormat> VertexFormats;
|
||||
|
||||
std::map<VkPPRenderPassKey, std::unique_ptr<VkPPRenderPassSetup>> PPRenderPassSetup;
|
||||
|
||||
FString CacheFilename;
|
||||
std::unique_ptr<VulkanPipelineCache> PipelineCache;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue