mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Fix a Vulkan lifetime issue causing invalid descriptors on shutdown
Also simplifies the code a little
This commit is contained in:
@@ -1790,7 +1790,7 @@ void VulkanDeleteList::PerformDeletes(VulkanContext *vulkan, VmaAllocator alloca
|
||||
int deleteCount = 0;
|
||||
|
||||
for (auto &callback : callbacks_) {
|
||||
callback.func(vulkan, callback.userdata);
|
||||
callback(vulkan);
|
||||
deleteCount++;
|
||||
}
|
||||
callbacks_.clear();
|
||||
|
||||
@@ -90,6 +90,8 @@ enum class PerfClass {
|
||||
FAST,
|
||||
};
|
||||
|
||||
typedef std::function<void(VulkanContext *)> DeleteCallback;
|
||||
|
||||
// This is a bit repetitive...
|
||||
class VulkanDeleteList {
|
||||
struct BufferWithAlloc {
|
||||
@@ -127,7 +129,7 @@ public:
|
||||
void QueueDeletePipelineLayout(VkPipelineLayout &pipelineLayout) { _dbg_assert_(pipelineLayout != VK_NULL_HANDLE); pipelineLayouts_.push_back(pipelineLayout); pipelineLayout = VK_NULL_HANDLE; }
|
||||
void QueueDeleteDescriptorSetLayout(VkDescriptorSetLayout &descSetLayout) { _dbg_assert_(descSetLayout != VK_NULL_HANDLE); descSetLayouts_.push_back(descSetLayout); descSetLayout = VK_NULL_HANDLE; }
|
||||
void QueueDeleteQueryPool(VkQueryPool &queryPool) { _dbg_assert_(queryPool != VK_NULL_HANDLE); queryPools_.push_back(queryPool); queryPool = VK_NULL_HANDLE; }
|
||||
void QueueCallback(void (*func)(VulkanContext *vulkan, void *userdata), void *userdata) { callbacks_.push_back(Callback(func, userdata)); }
|
||||
void QueueCallback(DeleteCallback func) { callbacks_.push_back(func); }
|
||||
|
||||
void QueueDeleteBufferAllocation(VkBuffer &buffer, VmaAllocation &alloc) {
|
||||
_dbg_assert_(buffer != VK_NULL_HANDLE);
|
||||
@@ -167,7 +169,7 @@ private:
|
||||
std::vector<VkPipelineLayout> pipelineLayouts_;
|
||||
std::vector<VkDescriptorSetLayout> descSetLayouts_;
|
||||
std::vector<VkQueryPool> queryPools_;
|
||||
std::vector<Callback> callbacks_;
|
||||
std::vector<DeleteCallback> callbacks_;
|
||||
int deleteCount_ = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -975,7 +975,7 @@ void VulkanQueueRunner::LogReadbackImage(const VKRStep &step) {
|
||||
INFO_LOG(Log::G3D, "%s", StepToString(vulkan_, step).c_str());
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer cmd, int curFrame, QueueProfileContext &profile) {
|
||||
void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer cmd, const int curFrame, QueueProfileContext &profile) {
|
||||
for (size_t i = 0; i < step.preTransitions.size(); i++) {
|
||||
const TransitionRequest &iter = step.preTransitions[i];
|
||||
if (iter.aspect == VK_IMAGE_ASPECT_COLOR_BIT && iter.fb->color.layout != iter.targetLayout) {
|
||||
@@ -1198,6 +1198,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
|
||||
|
||||
case VKRRenderCommand::DRAW_INDEXED:
|
||||
if (pipelineOK) {
|
||||
_dbg_assert_(c.drawIndexed.descSetIndex < descSets->size());
|
||||
VkDescriptorSet set = (*descSets)[c.drawIndexed.descSetIndex].set;
|
||||
_dbg_assert_(set != VK_NULL_HANDLE);
|
||||
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &set, c.drawIndexed.numUboOffsets, c.drawIndexed.uboOffsets);
|
||||
@@ -1210,7 +1211,8 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
|
||||
|
||||
case VKRRenderCommand::DRAW:
|
||||
if (pipelineOK) {
|
||||
VkDescriptorSet set = (*descSets)[c.drawIndexed.descSetIndex].set;
|
||||
_dbg_assert_(c.draw.descSetIndex < descSets->size());
|
||||
VkDescriptorSet set = (*descSets)[c.draw.descSetIndex].set;
|
||||
_dbg_assert_(set != VK_NULL_HANDLE);
|
||||
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &set, c.draw.numUboOffsets, c.draw.uboOffsets);
|
||||
if (c.draw.vbuffer) {
|
||||
|
||||
@@ -223,11 +223,10 @@ void VKRGraphicsPipeline::BlockUntilCompiled() {
|
||||
|
||||
void VKRGraphicsPipeline::QueueForDeletion(VulkanContext *vulkan) {
|
||||
// Can't destroy variants here, the pipeline still lives for a while.
|
||||
vulkan->Delete().QueueCallback([](VulkanContext *vulkan, void *p) {
|
||||
VKRGraphicsPipeline *pipeline = (VKRGraphicsPipeline *)p;
|
||||
pipeline->DestroyVariantsInstant(vulkan->GetDevice());
|
||||
delete pipeline;
|
||||
}, this);
|
||||
vulkan->Delete().QueueCallback([this](VulkanContext *vulkan) {
|
||||
this->DestroyVariantsInstant(vulkan->GetDevice());
|
||||
delete this;
|
||||
});
|
||||
}
|
||||
|
||||
u32 VKRGraphicsPipeline::GetVariantsBitmask() const {
|
||||
@@ -528,6 +527,7 @@ VulkanRenderManager::~VulkanRenderManager() {
|
||||
_dbg_assert_(!runCompileThread_); // StopThread should already have been called from DestroyBackbuffers.
|
||||
|
||||
vulkan_->WaitUntilQueueIdle();
|
||||
vulkan_->PerformPendingDeletes(); // Some callbacks can contain a reference to the render manager.
|
||||
|
||||
_dbg_assert_(pipelineLayouts_.empty());
|
||||
|
||||
@@ -1632,11 +1632,6 @@ void VulkanRenderManager::Run(VKRRenderThreadTask &task) {
|
||||
}
|
||||
frameData.Submit(vulkan_, FrameSubmitType::Pending, frameDataShared_);
|
||||
|
||||
// Flush descriptors.
|
||||
double descStart = time_now_d();
|
||||
FlushDescriptors(task.frame);
|
||||
frameData.profile.descWriteTime = time_now_d() - descStart;
|
||||
|
||||
if (!frameData.hasMainCommands) {
|
||||
// Effectively resets both main and present command buffers, since they both live in this pool.
|
||||
// We always record main commands first, so we don't need to reset the present command buffer separately.
|
||||
@@ -1649,6 +1644,12 @@ void VulkanRenderManager::Run(VKRRenderThreadTask &task) {
|
||||
_assert_msg_(res == VK_SUCCESS, "vkBeginCommandBuffer failed! result=%s", VulkanResultToString(res));
|
||||
}
|
||||
|
||||
// Flush descriptors.
|
||||
double descStart = time_now_d();
|
||||
int f = task.frame;
|
||||
FlushDescriptors(task.frame);
|
||||
frameData.profile.descWriteTime = time_now_d() - descStart;
|
||||
|
||||
queueRunner_.PreprocessSteps(task.steps);
|
||||
// Likely during shutdown, happens in headless.
|
||||
if (task.steps.empty() && !frameData.hasAcquired)
|
||||
@@ -1815,14 +1816,13 @@ VKRPipelineLayout *VulkanRenderManager::CreatePipelineLayout(BindingType *bindin
|
||||
}
|
||||
|
||||
void VulkanRenderManager::DestroyPipelineLayout(VKRPipelineLayout *layout) {
|
||||
for (auto iter = pipelineLayouts_.begin(); iter != pipelineLayouts_.end(); iter++) {
|
||||
if (*iter == layout) {
|
||||
pipelineLayouts_.erase(iter);
|
||||
break;
|
||||
vulkan_->Delete().QueueCallback([this, layout](VulkanContext *vulkan) {
|
||||
for (auto iter = pipelineLayouts_.begin(); iter != pipelineLayouts_.end(); iter++) {
|
||||
if (*iter == layout) {
|
||||
pipelineLayouts_.erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
vulkan_->Delete().QueueCallback([](VulkanContext *vulkan, void *userdata) {
|
||||
VKRPipelineLayout *layout = (VKRPipelineLayout *)userdata;
|
||||
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
|
||||
layout->frameData[i].pool.DestroyImmediately();
|
||||
}
|
||||
@@ -1830,17 +1830,17 @@ void VulkanRenderManager::DestroyPipelineLayout(VKRPipelineLayout *layout) {
|
||||
vkDestroyDescriptorSetLayout(vulkan->GetDevice(), layout->descriptorSetLayout, nullptr);
|
||||
|
||||
delete layout;
|
||||
}, layout);
|
||||
});
|
||||
}
|
||||
|
||||
void VulkanRenderManager::FlushDescriptors(int frame) {
|
||||
for (auto iter : pipelineLayouts_) {
|
||||
for (VKRPipelineLayout *iter : pipelineLayouts_) {
|
||||
iter->FlushDescSets(vulkan_, frame, &frameData_[frame].profile);
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanRenderManager::ResetDescriptorLists(int frame) {
|
||||
for (auto iter : pipelineLayouts_) {
|
||||
for (VKRPipelineLayout *iter : pipelineLayouts_) {
|
||||
VKRPipelineLayout::FrameData &data = iter->frameData[frame];
|
||||
|
||||
data.flushedDescriptors_ = 0;
|
||||
|
||||
@@ -194,10 +194,9 @@ public:
|
||||
if (module_) {
|
||||
VkShaderModule shaderModule = module_->BlockUntilReady();
|
||||
vulkan_->Delete().QueueDeleteShaderModule(shaderModule);
|
||||
vulkan_->Delete().QueueCallback([](VulkanContext *context, void *m) {
|
||||
auto module = (Promise<VkShaderModule> *)m;
|
||||
vulkan_->Delete().QueueCallback([module = module_](VulkanContext *context) {
|
||||
delete module;
|
||||
}, module_);
|
||||
});
|
||||
}
|
||||
}
|
||||
Promise<VkShaderModule> *Get() const { return module_; }
|
||||
@@ -1783,10 +1782,9 @@ public:
|
||||
}
|
||||
~VKFramebuffer() {
|
||||
_assert_msg_(buf_, "Null buf_ in VKFramebuffer - double delete?");
|
||||
buf_->Vulkan()->Delete().QueueCallback([](VulkanContext *vulkan, void *fb) {
|
||||
VKRFramebuffer *vfb = static_cast<VKRFramebuffer *>(fb);
|
||||
delete vfb;
|
||||
}, buf_);
|
||||
buf_->Vulkan()->Delete().QueueCallback([buf = buf_](VulkanContext *vulkan) {
|
||||
delete buf;
|
||||
});
|
||||
buf_ = nullptr;
|
||||
}
|
||||
VKRFramebuffer *GetFB() const { return buf_; }
|
||||
|
||||
@@ -116,10 +116,9 @@ VulkanFragmentShader::~VulkanFragmentShader() {
|
||||
if (shaderModule) {
|
||||
vulkan_->Delete().QueueDeleteShaderModule(shaderModule);
|
||||
}
|
||||
vulkan_->Delete().QueueCallback([](VulkanContext *vulkan, void *m) {
|
||||
auto module = (Promise<VkShaderModule> *)m;
|
||||
vulkan_->Delete().QueueCallback([module = module_](VulkanContext *vulkan) {
|
||||
delete module;
|
||||
}, module_);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,10 +147,9 @@ VulkanVertexShader::~VulkanVertexShader() {
|
||||
if (shaderModule) {
|
||||
vulkan_->Delete().QueueDeleteShaderModule(shaderModule);
|
||||
}
|
||||
vulkan_->Delete().QueueCallback([](VulkanContext *vulkan, void *m) {
|
||||
auto module = (Promise<VkShaderModule> *)m;
|
||||
vulkan_->Delete().QueueCallback([module = module_](VulkanContext *vulkan) {
|
||||
delete module;
|
||||
}, module_);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user