diff --git a/hw/xbox/nv2a/debug.c b/hw/xbox/nv2a/debug.c
index 2d24c8d222..b570cf3168 100644
--- a/hw/xbox/nv2a/debug.c
+++ b/hw/xbox/nv2a/debug.c
@@ -27,6 +27,14 @@
 #include <stdarg.h>
 #include <assert.h>
 
+#ifdef ENABLE_RENDERDOC
+#include <renderdoc_app.h>
+#include <dlfcn.h>
+
+static RENDERDOC_API_1_1_2 *rdoc_api = NULL;
+static int32_t renderdoc_capture_frames = 0;
+#endif
+
 static bool has_GL_GREMEDY_frame_terminator = false;
 static bool has_GL_KHR_debug = false;
 
@@ -52,6 +60,17 @@ void gl_debug_initialize(void)
        assert(glGetError() == GL_NO_ERROR);
 #endif
     }
+
+#ifdef ENABLE_RENDERDOC
+    void* renderdoc = dlopen("librenderdoc.so", RTLD_NOW | RTLD_NOLOAD);
+    if (renderdoc) {
+        pRENDERDOC_GetAPI RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)dlsym(
+            renderdoc, "RENDERDOC_GetAPI");
+        int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2,
+                                   (void **)&rdoc_api);
+        assert(ret == 1 && "Failed to retrieve RenderDoc API.");
+    }
+#endif
 }
 
 void gl_debug_message(bool cc, const char *fmt, ...)
@@ -121,10 +140,26 @@ void gl_debug_label(GLenum target, GLuint name, const char *fmt, ...)
     va_end(ap);
 
     glObjectLabel(target, name, n, buffer);
+
+    GLenum err = glGetError();
+    assert(err == GL_NO_ERROR);
 }
 
 void gl_debug_frame_terminator(void)
 {
+#ifdef ENABLE_RENDERDOC
+    if (rdoc_api) {
+        if (rdoc_api->IsTargetControlConnected()) {
+            if (rdoc_api->IsFrameCapturing()) {
+                rdoc_api->EndFrameCapture(NULL, NULL);
+            }
+            if (renderdoc_capture_frames) {
+                rdoc_api->StartFrameCapture(NULL, NULL);
+                --renderdoc_capture_frames;
+            }
+        }
+    }
+#endif
     if (!has_GL_GREMEDY_frame_terminator) {
         return;
     }
@@ -132,4 +167,15 @@ void gl_debug_frame_terminator(void)
     glFrameTerminatorGREMEDY();
 }
 
+#ifdef ENABLE_RENDERDOC
+
+bool nv2a_dbg_renderdoc_available(void) {
+  return rdoc_api != NULL;
+}
+
+void nv2a_dbg_renderdoc_capture_frames(uint32_t num_frames) {
+  renderdoc_capture_frames = num_frames;
+}
+#endif // ENABLE_RENDERDOC
+
 #endif
diff --git a/hw/xbox/nv2a/debug.h b/hw/xbox/nv2a/debug.h
index ed1491a246..73c8bd3f4f 100644
--- a/hw/xbox/nv2a/debug.h
+++ b/hw/xbox/nv2a/debug.h
@@ -40,6 +40,9 @@
 // #define DEBUG_NV2A_GL
 #ifdef DEBUG_NV2A_GL
 
+// Improve frame capture boundaries with RenderDoc.
+// #define ENABLE_RENDERDOC
+
 #include <stdbool.h>
 #include "gl/gloffscreen.h"
 
@@ -149,6 +152,11 @@ extern NV2AStats g_nv2a_stats;
 const char *nv2a_profile_get_counter_name(unsigned int cnt);
 int nv2a_profile_get_counter_value(unsigned int cnt);
 
+#ifdef ENABLE_RENDERDOC
+bool nv2a_dbg_renderdoc_available(void);
+void nv2a_dbg_renderdoc_capture_frames(uint32_t num_frames);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/ui/xemu-hud.cc b/ui/xemu-hud.cc
index 0154eb28dd..6054a5a5ec 100644
--- a/ui/xemu-hud.cc
+++ b/ui/xemu-hud.cc
@@ -1898,6 +1898,10 @@ static AutoUpdateWindow update_window;
 #endif
 static std::deque<const char *> g_errors;
 
+#ifdef ENABLE_RENDERDOC
+static bool capture_renderdoc_frame = false;
+#endif
+
 class FirstBootWindow
 {
 public:
@@ -2058,6 +2062,12 @@ static void process_keyboard_shortcuts(void)
     if (is_key_pressed(SDL_SCANCODE_GRAVE)) {
         monitor_window.toggle_open();
     }
+
+#ifdef ENABLE_RENDERDOC
+    if (is_key_pressed(SDL_SCANCODE_F10)) {
+        nv2a_dbg_renderdoc_capture_frames(1);
+    }
+#endif
 }
 
 #if defined(__APPLE__)
@@ -2136,6 +2146,11 @@ static void ShowMainMenu()
             ImGui::MenuItem("Monitor", "~", &monitor_window.is_open);
             ImGui::MenuItem("Audio", NULL, &apu_window.is_open);
             ImGui::MenuItem("Video", NULL, &video_window.is_open);
+#ifdef ENABLE_RENDERDOC
+            if (nv2a_dbg_renderdoc_available()) {
+                ImGui::MenuItem("RenderDoc: Capture", NULL, &capture_renderdoc_frame);
+            }
+#endif
             ImGui::EndMenu();
         }
 
@@ -2413,6 +2428,13 @@ void xemu_hud_render(void)
     ImGui::NewFrame();
     process_keyboard_shortcuts();
 
+#ifdef ENABLE_RENDERDOC
+    if (capture_renderdoc_frame) {
+        nv2a_dbg_renderdoc_capture_frames(1);
+        capture_renderdoc_frame = false;
+    }
+#endif
+
     bool show_main_menu = true;
 
     if (first_boot_window.is_open) {