mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 06:42:12 +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:
|
public:
|
||||||
ComputePipelineBuilder();
|
ComputePipelineBuilder();
|
||||||
|
|
||||||
|
ComputePipelineBuilder& Cache(VulkanPipelineCache* cache);
|
||||||
ComputePipelineBuilder& Layout(VulkanPipelineLayout *layout);
|
ComputePipelineBuilder& Layout(VulkanPipelineLayout *layout);
|
||||||
ComputePipelineBuilder& ComputeShader(VulkanShader *shader);
|
ComputePipelineBuilder& ComputeShader(VulkanShader *shader);
|
||||||
ComputePipelineBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
ComputePipelineBuilder& DebugName(const char* name) { debugName = name; return *this; }
|
||||||
|
@ -245,6 +246,7 @@ public:
|
||||||
private:
|
private:
|
||||||
VkComputePipelineCreateInfo pipelineInfo = {};
|
VkComputePipelineCreateInfo pipelineInfo = {};
|
||||||
VkPipelineShaderStageCreateInfo stageInfo = {};
|
VkPipelineShaderStageCreateInfo stageInfo = {};
|
||||||
|
VulkanPipelineCache* cache = nullptr;
|
||||||
const char* debugName = nullptr;
|
const char* debugName = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -324,6 +326,7 @@ class GraphicsPipelineBuilder
|
||||||
public:
|
public:
|
||||||
GraphicsPipelineBuilder();
|
GraphicsPipelineBuilder();
|
||||||
|
|
||||||
|
GraphicsPipelineBuilder& Cache(VulkanPipelineCache* cache);
|
||||||
GraphicsPipelineBuilder& Subpass(int subpass);
|
GraphicsPipelineBuilder& Subpass(int subpass);
|
||||||
GraphicsPipelineBuilder& Layout(VulkanPipelineLayout *layout);
|
GraphicsPipelineBuilder& Layout(VulkanPipelineLayout *layout);
|
||||||
GraphicsPipelineBuilder& RenderPass(VulkanRenderPass *renderPass);
|
GraphicsPipelineBuilder& RenderPass(VulkanRenderPass *renderPass);
|
||||||
|
@ -377,6 +380,7 @@ private:
|
||||||
std::vector<VkVertexInputAttributeDescription> vertexInputAttributes;
|
std::vector<VkVertexInputAttributeDescription> vertexInputAttributes;
|
||||||
std::vector<VkDynamicState> dynamicStates;
|
std::vector<VkDynamicState> dynamicStates;
|
||||||
|
|
||||||
|
VulkanPipelineCache* cache = nullptr;
|
||||||
const char* debugName = nullptr;
|
const char* debugName = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -399,6 +403,24 @@ private:
|
||||||
const char* debugName = nullptr;
|
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
|
class RenderPassBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -305,6 +305,24 @@ private:
|
||||||
VulkanPipelineLayout &operator=(const VulkanPipelineLayout &) = delete;
|
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
|
class VulkanRenderPass
|
||||||
{
|
{
|
||||||
public:
|
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)
|
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;
|
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)
|
ComputePipelineBuilder& ComputePipelineBuilder::Layout(VulkanPipelineLayout* layout)
|
||||||
{
|
{
|
||||||
pipelineInfo.layout = layout->layout;
|
pipelineInfo.layout = layout->layout;
|
||||||
|
@ -608,7 +614,7 @@ ComputePipelineBuilder& ComputePipelineBuilder::ComputeShader(VulkanShader* shad
|
||||||
std::unique_ptr<VulkanPipeline> ComputePipelineBuilder::Create(VulkanDevice* device)
|
std::unique_ptr<VulkanPipeline> ComputePipelineBuilder::Create(VulkanDevice* device)
|
||||||
{
|
{
|
||||||
VkPipeline pipeline;
|
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);
|
auto obj = std::make_unique<VulkanPipeline>(device, pipeline);
|
||||||
if (debugName)
|
if (debugName)
|
||||||
obj->SetDebugName(debugName);
|
obj->SetDebugName(debugName);
|
||||||
|
@ -871,6 +877,12 @@ GraphicsPipelineBuilder& GraphicsPipelineBuilder::RasterizationSamples(VkSampleC
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GraphicsPipelineBuilder& GraphicsPipelineBuilder::Cache(VulkanPipelineCache* cache)
|
||||||
|
{
|
||||||
|
this->cache = cache;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
GraphicsPipelineBuilder& GraphicsPipelineBuilder::Subpass(int subpass)
|
GraphicsPipelineBuilder& GraphicsPipelineBuilder::Subpass(int subpass)
|
||||||
{
|
{
|
||||||
pipelineInfo.subpass = subpass;
|
pipelineInfo.subpass = subpass;
|
||||||
|
@ -1087,7 +1099,7 @@ GraphicsPipelineBuilder& GraphicsPipelineBuilder::AddDynamicState(VkDynamicState
|
||||||
std::unique_ptr<VulkanPipeline> GraphicsPipelineBuilder::Create(VulkanDevice* device)
|
std::unique_ptr<VulkanPipeline> GraphicsPipelineBuilder::Create(VulkanDevice* device)
|
||||||
{
|
{
|
||||||
VkPipeline pipeline = 0;
|
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");
|
CheckVulkanError(result, "Could not create graphics pipeline");
|
||||||
auto obj = std::make_unique<VulkanPipeline>(device, pipeline);
|
auto obj = std::make_unique<VulkanPipeline>(device, pipeline);
|
||||||
if (debugName)
|
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()
|
RenderPassBuilder::RenderPassBuilder()
|
||||||
{
|
{
|
||||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||||
|
|
|
@ -34,13 +34,49 @@
|
||||||
#include "flatvertices.h"
|
#include "flatvertices.h"
|
||||||
#include "hw_viewpointuniforms.h"
|
#include "hw_viewpointuniforms.h"
|
||||||
#include "v_2ddrawer.h"
|
#include "v_2ddrawer.h"
|
||||||
|
#include "i_specialpaths.h"
|
||||||
|
|
||||||
VkRenderPassManager::VkRenderPassManager(VulkanRenderDevice* fb) : fb(fb)
|
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()
|
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()
|
void VkRenderPassManager::RenderBuffersReset()
|
||||||
|
@ -206,6 +242,7 @@ VulkanPipeline *VkRenderPassSetup::GetPipeline(const VkPipelineKey &key)
|
||||||
std::unique_ptr<VulkanPipeline> VkRenderPassSetup::CreatePipeline(const VkPipelineKey &key)
|
std::unique_ptr<VulkanPipeline> VkRenderPassSetup::CreatePipeline(const VkPipelineKey &key)
|
||||||
{
|
{
|
||||||
GraphicsPipelineBuilder builder;
|
GraphicsPipelineBuilder builder;
|
||||||
|
builder.Cache(fb->GetRenderPassManager()->GetCache());
|
||||||
|
|
||||||
VkShaderProgram *program;
|
VkShaderProgram *program;
|
||||||
if (key.SpecialEffect != EFF_NONE)
|
if (key.SpecialEffect != EFF_NONE)
|
||||||
|
@ -332,6 +369,7 @@ void VkPPRenderPassSetup::CreatePipelineLayout(const VkPPRenderPassKey& key)
|
||||||
void VkPPRenderPassSetup::CreatePipeline(const VkPPRenderPassKey& key)
|
void VkPPRenderPassSetup::CreatePipeline(const VkPPRenderPassKey& key)
|
||||||
{
|
{
|
||||||
GraphicsPipelineBuilder builder;
|
GraphicsPipelineBuilder builder;
|
||||||
|
builder.Cache(fb->GetRenderPassManager()->GetCache());
|
||||||
builder.AddVertexShader(key.Shader->VertexShader.get());
|
builder.AddVertexShader(key.Shader->VertexShader.get());
|
||||||
builder.AddFragmentShader(key.Shader->FragmentShader.get());
|
builder.AddFragmentShader(key.Shader->FragmentShader.get());
|
||||||
|
|
||||||
|
|
|
@ -135,6 +135,8 @@ public:
|
||||||
|
|
||||||
VkPPRenderPassSetup* GetPPRenderPass(const VkPPRenderPassKey& key);
|
VkPPRenderPassSetup* GetPPRenderPass(const VkPPRenderPassKey& key);
|
||||||
|
|
||||||
|
VulkanPipelineCache* GetCache() { return PipelineCache.get(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VulkanRenderDevice* fb = nullptr;
|
VulkanRenderDevice* fb = nullptr;
|
||||||
|
|
||||||
|
@ -143,4 +145,7 @@ private:
|
||||||
std::vector<VkVertexFormat> VertexFormats;
|
std::vector<VkVertexFormat> VertexFormats;
|
||||||
|
|
||||||
std::map<VkPPRenderPassKey, std::unique_ptr<VkPPRenderPassSetup>> PPRenderPassSetup;
|
std::map<VkPPRenderPassKey, std::unique_ptr<VkPPRenderPassSetup>> PPRenderPassSetup;
|
||||||
|
|
||||||
|
FString CacheFilename;
|
||||||
|
std::unique_ptr<VulkanPipelineCache> PipelineCache;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue