Create pipelines in parallel
This commit is contained in:
parent
5ca0bfe716
commit
8821d619e4
2 changed files with 70 additions and 23 deletions
|
@ -1,6 +1,7 @@
|
|||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
|
||||
#include "Common/Log.h"
|
||||
|
@ -218,26 +219,27 @@ void VKRGraphicsPipeline::LogCreationFailure() const {
|
|||
ERROR_LOG(G3D, "======== END OF PIPELINE ==========");
|
||||
}
|
||||
|
||||
bool VKRComputePipeline::Create(VulkanContext *vulkan) {
|
||||
bool VKRComputePipeline::CreateAsync(VulkanContext *vulkan) {
|
||||
if (!desc) {
|
||||
// Already failed to create this one.
|
||||
return false;
|
||||
}
|
||||
VkPipeline vkpipeline;
|
||||
VkResult result = vkCreateComputePipelines(vulkan->GetDevice(), desc->pipelineCache, 1, &desc->pipe, nullptr, &vkpipeline);
|
||||
pipeline->SpawnEmpty(&g_threadManager, [=] {
|
||||
VkPipeline vkpipeline;
|
||||
VkResult result = vkCreateComputePipelines(vulkan->GetDevice(), desc->pipelineCache, 1, &desc->pipe, nullptr, &vkpipeline);
|
||||
|
||||
bool success = true;
|
||||
if (result != VK_SUCCESS) {
|
||||
pipeline->Post(VK_NULL_HANDLE);
|
||||
ERROR_LOG(G3D, "Failed creating compute pipeline! result='%s'", VulkanResultToString(result));
|
||||
success = false;
|
||||
} else {
|
||||
pipeline->Post(vkpipeline);
|
||||
}
|
||||
|
||||
delete desc;
|
||||
bool success = true;
|
||||
if (result == VK_SUCCESS) {
|
||||
return vkpipeline;
|
||||
} else {
|
||||
ERROR_LOG(G3D, "Failed creating compute pipeline! result='%s'", VulkanResultToString(result));
|
||||
success = false;
|
||||
return (VkPipeline)VK_NULL_HANDLE;
|
||||
}
|
||||
delete desc;
|
||||
}, TaskType::CPU_COMPUTE);
|
||||
desc = nullptr;
|
||||
return success;
|
||||
return true;
|
||||
}
|
||||
|
||||
VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan)
|
||||
|
@ -370,7 +372,6 @@ VulkanRenderManager::~VulkanRenderManager() {
|
|||
|
||||
vulkan_->WaitUntilQueueIdle();
|
||||
|
||||
DrainCompileQueue();
|
||||
VkDevice device = vulkan_->GetDevice();
|
||||
frameDataShared_.Destroy(vulkan_);
|
||||
for (int i = 0; i < inflightFramesAtStart_; i++) {
|
||||
|
@ -379,12 +380,41 @@ VulkanRenderManager::~VulkanRenderManager() {
|
|||
queueRunner_.DestroyDeviceObjects();
|
||||
}
|
||||
|
||||
struct SinglePipelineTask {
|
||||
VKRGraphicsPipeline *pipeline;
|
||||
VkRenderPass compatibleRenderPass;
|
||||
RenderPassType rpType;
|
||||
VkSampleCountFlagBits sampleCount;
|
||||
};
|
||||
|
||||
class CreateMultiPipelinesTask : public Task {
|
||||
public:
|
||||
CreateMultiPipelinesTask(VulkanContext *vulkan, std::vector<SinglePipelineTask> tasks) : vulkan_(vulkan), tasks_(tasks) {}
|
||||
~CreateMultiPipelinesTask() {}
|
||||
|
||||
TaskType Type() const override {
|
||||
return TaskType::CPU_COMPUTE;
|
||||
}
|
||||
|
||||
void Run() override {
|
||||
for (auto &task : tasks_) {
|
||||
task.pipeline->Create(vulkan_, task.compatibleRenderPass, task.rpType, task.sampleCount);
|
||||
}
|
||||
}
|
||||
|
||||
VulkanContext *vulkan_;
|
||||
std::vector<SinglePipelineTask> tasks_;
|
||||
};
|
||||
|
||||
void VulkanRenderManager::CompileThreadFunc() {
|
||||
SetCurrentThreadName("ShaderCompile");
|
||||
while (true) {
|
||||
std::vector<CompileQueueEntry> toCompile;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(compileMutex_);
|
||||
// TODO: Should this be while?
|
||||
// It may be beneficial also to unlock and wait a little bit to see if we get some more shaders
|
||||
// so we can do a better job of thread-sorting them.
|
||||
if (compileQueue_.empty() && run_) {
|
||||
compileCond_.wait(lock);
|
||||
}
|
||||
|
@ -395,24 +425,41 @@ void VulkanRenderManager::CompileThreadFunc() {
|
|||
break;
|
||||
}
|
||||
|
||||
double time = time_now_d();
|
||||
// TODO: Here we can sort the pending pipelines by vertex and fragment shaders,
|
||||
NOTICE_LOG(G3D, "Compilation thread has %d pipelines to create", (int)toCompile.size());
|
||||
|
||||
// Here we sort the pending pipelines by vertex and fragment shaders,
|
||||
std::map<std::pair<Promise<VkShaderModule> *, Promise<VkShaderModule> *>, std::vector<SinglePipelineTask>> map;
|
||||
|
||||
// TODO: Here we can sort pending graphics pipelines by vertex and fragment shaders,
|
||||
// and split up further.
|
||||
// Those with the same pairs of shaders should be on the same thread.
|
||||
for (auto &entry : toCompile) {
|
||||
switch (entry.type) {
|
||||
case CompileQueueEntry::Type::GRAPHICS:
|
||||
entry.graphics->Create(vulkan_, entry.compatibleRenderPass, entry.renderPassType, entry.sampleCount);
|
||||
map[std::pair< Promise<VkShaderModule> *, Promise<VkShaderModule> *>(entry.graphics->desc->vertexShader, entry.graphics->desc->fragmentShader)].push_back(
|
||||
SinglePipelineTask{
|
||||
entry.graphics,
|
||||
entry.compatibleRenderPass,
|
||||
entry.renderPassType,
|
||||
entry.sampleCount,
|
||||
}
|
||||
);
|
||||
break;
|
||||
case CompileQueueEntry::Type::COMPUTE:
|
||||
entry.compute->Create(vulkan_);
|
||||
// Queue up pending compute pipelines on separate tasks.
|
||||
entry.compute->CreateAsync(vulkan_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
double delta = time_now_d() - time;
|
||||
if (delta > 0.005f) {
|
||||
INFO_LOG(G3D, "CompileThreadFunc: Creating %d pipelines took %0.3f ms", (int)toCompile.size(), delta * 1000.0f);
|
||||
for (auto iter : map) {
|
||||
auto &shaders = iter.first;
|
||||
auto &entries = iter.second;
|
||||
|
||||
NOTICE_LOG(G3D, "For this shader pair, we have %d pipelines to create", (int)entries.size());
|
||||
|
||||
Task *task = new CreateMultiPipelinesTask(vulkan_, entries);
|
||||
g_threadManager.EnqueueTask(task);
|
||||
}
|
||||
|
||||
queueRunner_.NotifyCompileDone();
|
||||
|
|
|
@ -153,7 +153,7 @@ struct VKRComputePipeline {
|
|||
VKRComputePipelineDesc *desc = nullptr;
|
||||
Promise<VkPipeline> *pipeline = nullptr;
|
||||
|
||||
bool Create(VulkanContext *vulkan);
|
||||
bool CreateAsync(VulkanContext *vulkan);
|
||||
bool Pending() const {
|
||||
return pipeline == VK_NULL_HANDLE && desc != nullptr;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue