SpirvShaderDebugger: Ensure frames are fully popped

Currently stack frames are still WIP (inlined at is still unimplemented). The current implementation can leak stack frames, which collect between shader invocations.

Ensure the stack frame depth is the same on exit as it was on entry.

Bug: b/148401179
Change-Id: I95fb0739dd9691942826cf22eb097708762b72e5
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/44289
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/Pipeline/SpirvShaderDebugger.cpp b/src/Pipeline/SpirvShaderDebugger.cpp
index 9879278..e936a4d 100644
--- a/src/Pipeline/SpirvShaderDebugger.cpp
+++ b/src/Pipeline/SpirvShaderDebugger.cpp
@@ -568,6 +568,8 @@
 	Scopes rootScopes;                                                                        // Scopes for the root stack frame.
 	std::array<std::shared_ptr<vk::dbg::VariableContainer>, sw::SIMD::Width> builtinsByLane;  // Scopes for builtin varibles (shared by all shader frames).
 	debug::SourceScope *srcScope = nullptr;                                                   // Current source scope.
+
+	const size_t initialThreadDepth = 0;
 };
 
 SpirvShader::Impl::Debugger::State *SpirvShader::Impl::Debugger::State::create(const Debugger *debugger, const char *name)
@@ -584,6 +586,7 @@
 SpirvShader::Impl::Debugger::State::State(const Debugger *debugger, const char *stackBase, vk::dbg::Context::Lock &lock)
     : debugger(debugger)
     , thread(lock.currentThread())
+    , initialThreadDepth(thread->depth())
 {
 	enter(lock, stackBase);
 
@@ -607,7 +610,10 @@
 
 SpirvShader::Impl::Debugger::State::~State()
 {
-	exit();
+	for(auto depth = thread->depth(); depth > initialThreadDepth; depth--)
+	{
+		exit();
+	}
 }
 
 void SpirvShader::Impl::Debugger::State::enter(vk::dbg::Context::Lock &lock, const char *name)
diff --git a/src/Vulkan/Debug/Thread.cpp b/src/Vulkan/Debug/Thread.cpp
index 6b4fa96..5c819f7 100644
--- a/src/Vulkan/Debug/Thread.cpp
+++ b/src/Vulkan/Debug/Thread.cpp
@@ -126,6 +126,12 @@
 	return out;
 }
 
+size_t Thread::depth() const
+{
+	marl::lock lock(mutex);
+	return frames.size();
+}
+
 Thread::State Thread::state() const
 {
 	marl::lock lock(mutex);
diff --git a/src/Vulkan/Debug/Thread.hpp b/src/Vulkan/Debug/Thread.hpp
index 4c719f2..cf946a9 100644
--- a/src/Vulkan/Debug/Thread.hpp
+++ b/src/Vulkan/Debug/Thread.hpp
@@ -136,6 +136,9 @@
 	// stack() returns a copy of the thread's current stack frames.
 	std::vector<Frame> stack() const;
 
+	// depth() returns the number of stack frames.
+	size_t depth() const;
+
 	// state() returns the current thread's state.
 	State state() const;