mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 13:30:02 +00:00
Vulkan: Fix synchronization when shutting the GPU down in-game.
This commit is contained in:
parent
e26bf611e0
commit
0ad2827e14
@ -1244,6 +1244,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c
|
||||
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
descSets = &c.graphics_pipeline.pipelineLayout->frameData[curFrame].descSets_;
|
||||
pipelineLayout = c.graphics_pipeline.pipelineLayout->pipelineLayout;
|
||||
_dbg_assert_(pipelineLayout != VK_NULL_HANDLE);
|
||||
lastGraphicsPipeline = graphicsPipeline;
|
||||
pipelineOK = true;
|
||||
} else {
|
||||
|
@ -413,6 +413,8 @@ VulkanRenderManager::~VulkanRenderManager() {
|
||||
|
||||
vulkan_->WaitUntilQueueIdle();
|
||||
|
||||
_dbg_assert_(pipelineLayouts_.empty());
|
||||
|
||||
VkDevice device = vulkan_->GetDevice();
|
||||
frameDataShared_.Destroy(vulkan_);
|
||||
for (int i = 0; i < inflightFramesAtStart_; i++) {
|
||||
@ -519,12 +521,14 @@ void VulkanRenderManager::CompileThreadFunc() {
|
||||
}
|
||||
|
||||
void VulkanRenderManager::DrainAndBlockCompileQueue() {
|
||||
EndCurRenderStep();
|
||||
std::unique_lock<std::mutex> lock(compileMutex_);
|
||||
compileBlocked_ = true;
|
||||
compileCond_.notify_all();
|
||||
while (!compileQueue_.empty()) {
|
||||
queueRunner_.WaitForCompileNotification();
|
||||
}
|
||||
FlushSync();
|
||||
}
|
||||
|
||||
void VulkanRenderManager::ReleaseCompileQueue() {
|
||||
@ -1538,6 +1542,8 @@ void VulkanRenderManager::Run(VKRRenderThreadTask &task) {
|
||||
|
||||
// Called from main thread.
|
||||
void VulkanRenderManager::FlushSync() {
|
||||
_dbg_assert_(!curRenderStep_);
|
||||
|
||||
if (invalidationCallback_) {
|
||||
invalidationCallback_(InvalidationCallbackFlags::COMMAND_BUFFER_STATE);
|
||||
}
|
||||
@ -1669,6 +1675,7 @@ void VulkanRenderManager::DestroyPipelineLayout(VKRPipelineLayout *layout) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete layout;
|
||||
}
|
||||
|
||||
void VulkanRenderManager::FlushDescriptors(int frame) {
|
||||
@ -1687,6 +1694,11 @@ void VulkanRenderManager::ResetDescriptorLists(int frame) {
|
||||
}
|
||||
}
|
||||
|
||||
VKRPipelineLayout::~VKRPipelineLayout() {
|
||||
_assert_(!pipelineLayout && !descriptorSetLayout);
|
||||
_assert_(frameData[0].pool.IsDestroyed());
|
||||
}
|
||||
|
||||
void VKRPipelineLayout::FlushDescSets(VulkanContext *vulkan, int frame, QueueProfileContext *profile) {
|
||||
_dbg_assert_(frame < VulkanContext::MAX_INFLIGHT_FRAMES);
|
||||
|
||||
|
@ -210,11 +210,7 @@ struct PackedDescriptor {
|
||||
// Note that we only support a single descriptor set due to compatibility with some ancient devices.
|
||||
// We should probably eventually give that up.
|
||||
struct VKRPipelineLayout {
|
||||
VKRPipelineLayout() {}
|
||||
~VKRPipelineLayout() {
|
||||
_assert_(!pipelineLayout && !descriptorSetLayout);
|
||||
_assert_(frameData[0].pool.IsDestroyed());
|
||||
}
|
||||
~VKRPipelineLayout();
|
||||
enum { MAX_DESC_SET_BINDINGS = 10 };
|
||||
BindingType bindingTypes[MAX_DESC_SET_BINDINGS];
|
||||
|
||||
|
@ -254,11 +254,8 @@ void DrawEngineVulkan::DoFlush() {
|
||||
const bool forceIndexed = draw_->GetDeviceCaps().verySlowShaderCompiler;
|
||||
|
||||
if (useHWTransform) {
|
||||
int vertexCount = 0;
|
||||
bool useElements = true;
|
||||
VkBuffer vbuf = VK_NULL_HANDLE;
|
||||
VkBuffer ibuf = VK_NULL_HANDLE;
|
||||
bool useIndexGen = true;
|
||||
if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) {
|
||||
// If software skinning, we're predecoding into "decoded". So make sure we're done, then push that content.
|
||||
DecodeVerts(decoded_);
|
||||
@ -272,8 +269,8 @@ void DrawEngineVulkan::DoFlush() {
|
||||
DecodeInds();
|
||||
gpuStats.numUncachedVertsDrawn += indexGen.VertexCount();
|
||||
|
||||
if (useIndexGen) {
|
||||
vertexCount = indexGen.VertexCount();
|
||||
bool useElements;
|
||||
int vertexCount = indexGen.VertexCount();
|
||||
if (forceIndexed) {
|
||||
useElements = true;
|
||||
prim = indexGen.GeneralPrim();
|
||||
@ -284,7 +281,6 @@ void DrawEngineVulkan::DoFlush() {
|
||||
}
|
||||
prim = indexGen.Prim();
|
||||
}
|
||||
}
|
||||
|
||||
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
|
||||
if (gstate.isModeThrough()) {
|
||||
|
@ -167,6 +167,7 @@ void GPU_Vulkan::SaveCache(const Path &filename) {
|
||||
GPU_Vulkan::~GPU_Vulkan() {
|
||||
if (draw_) {
|
||||
VulkanRenderManager *rm = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
// This now also does a hard sync with the render thread, so that we can safely delete our pipeline layout below.
|
||||
rm->DrainAndBlockCompileQueue();
|
||||
}
|
||||
|
||||
@ -423,6 +424,7 @@ void GPU_Vulkan::CheckRenderResized() {
|
||||
|
||||
void GPU_Vulkan::DeviceLost() {
|
||||
// draw_ is normally actually still valid here in Vulkan. But we null it out in GPUCommonHW::DeviceLost so we don't try to use it again.
|
||||
// So, we have to save it here to be able to call ReleaseCompileQueue().
|
||||
Draw::DrawContext *draw = draw_;
|
||||
if (draw) {
|
||||
VulkanRenderManager *rm = (VulkanRenderManager *)draw->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
|
@ -1177,7 +1177,7 @@ void EmuScreen::update() {
|
||||
}
|
||||
}
|
||||
|
||||
void EmuScreen::checkPowerDown() {
|
||||
bool EmuScreen::checkPowerDown() {
|
||||
if (PSP_IsRebooting()) {
|
||||
bootPending_ = true;
|
||||
invalid_ = true;
|
||||
@ -1191,7 +1191,9 @@ void EmuScreen::checkPowerDown() {
|
||||
screenManager()->switchScreen(new MainScreen());
|
||||
bootPending_ = false;
|
||||
invalid_ = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char *CPUCoreAsString(int core) {
|
||||
@ -1454,6 +1456,7 @@ void EmuScreen::render() {
|
||||
Core_UpdateDebugStats((DebugOverlay)g_Config.iDebugOverlay == DebugOverlay::DEBUG_STATS || g_Config.bLogFrameDrops);
|
||||
|
||||
bool blockedExecution = Achievements::IsBlockingExecution();
|
||||
bool rebind = false;
|
||||
if (!blockedExecution) {
|
||||
PSP_BeginHostFrame();
|
||||
PSP_RunLoopWhileState();
|
||||
@ -1490,7 +1493,7 @@ void EmuScreen::render() {
|
||||
// Didn't actually reach the end of the frame, ran out of the blockTicks cycles.
|
||||
// In this case we need to bind and wipe the backbuffer, at least.
|
||||
// It's possible we never ended up outputted anything - make sure we have the backbuffer cleared
|
||||
thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_NoFrame");
|
||||
rebind = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1498,10 +1501,10 @@ void EmuScreen::render() {
|
||||
}
|
||||
|
||||
// This must happen after PSP_EndHostFrame so that things like push buffers are end-frame'd before we start destroying stuff.
|
||||
checkPowerDown();
|
||||
|
||||
if (invalid_)
|
||||
return;
|
||||
if (checkPowerDown() || rebind) {
|
||||
// Shutting down can end up ending the current render pass
|
||||
thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_NoFrame");
|
||||
}
|
||||
|
||||
if (hasVisibleUI()) {
|
||||
// In most cases, this should already be bound and a no-op.
|
||||
|
@ -76,7 +76,7 @@ private:
|
||||
void onVKeyAnalog(int virtualKeyCode, float value);
|
||||
|
||||
void autoLoad();
|
||||
void checkPowerDown();
|
||||
bool checkPowerDown();
|
||||
|
||||
UI::Event OnDevMenu;
|
||||
UI::Event OnChatMenu;
|
||||
|
@ -335,6 +335,8 @@ shutdown:
|
||||
|
||||
g_graphicsContext->Shutdown();
|
||||
|
||||
delete g_graphicsContext;
|
||||
|
||||
UpdateConsolePosition();
|
||||
NativeShutdown();
|
||||
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 6f02e791aa202de5eaf3e86ed269dda6d456b779
|
||||
Subproject commit 24dc84ca2dfbdbddebc9a26f4df225888e56a4f4
|
Loading…
Reference in New Issue
Block a user