summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/core.cpp10
-rw-r--r--src/core/core.h4
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp49
-rw-r--r--src/video_core/debug_utils/debug_utils.h157
-rw-r--r--src/video_core/engines/maxwell_3d.cpp31
-rw-r--r--src/yuzu/CMakeLists.txt5
-rw-r--r--src/yuzu/debugger/graphics/graphics_breakpoint_observer.cpp27
-rw-r--r--src/yuzu/debugger/graphics/graphics_breakpoint_observer.h33
-rw-r--r--src/yuzu/debugger/graphics/graphics_breakpoints.cpp221
-rw-r--r--src/yuzu/debugger/graphics/graphics_breakpoints.h45
-rw-r--r--src/yuzu/debugger/graphics/graphics_breakpoints_p.h37
-rw-r--r--src/yuzu/main.cpp11
-rw-r--r--src/yuzu/main.h8
14 files changed, 0 insertions, 640 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index c45fb960c..d697b80ef 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -46,7 +46,6 @@
46#include "core/settings.h" 46#include "core/settings.h"
47#include "core/telemetry_session.h" 47#include "core/telemetry_session.h"
48#include "core/tools/freezer.h" 48#include "core/tools/freezer.h"
49#include "video_core/debug_utils/debug_utils.h"
50#include "video_core/renderer_base.h" 49#include "video_core/renderer_base.h"
51#include "video_core/video_core.h" 50#include "video_core/video_core.h"
52 51
@@ -341,7 +340,6 @@ struct System::Impl {
341 std::unique_ptr<Loader::AppLoader> app_loader; 340 std::unique_ptr<Loader::AppLoader> app_loader;
342 std::unique_ptr<VideoCore::RendererBase> renderer; 341 std::unique_ptr<VideoCore::RendererBase> renderer;
343 std::unique_ptr<Tegra::GPU> gpu_core; 342 std::unique_ptr<Tegra::GPU> gpu_core;
344 std::shared_ptr<Tegra::DebugContext> debug_context;
345 std::unique_ptr<Hardware::InterruptManager> interrupt_manager; 343 std::unique_ptr<Hardware::InterruptManager> interrupt_manager;
346 Memory::Memory memory; 344 Memory::Memory memory;
347 CpuCoreManager cpu_core_manager; 345 CpuCoreManager cpu_core_manager;
@@ -580,14 +578,6 @@ Loader::AppLoader& System::GetAppLoader() const {
580 return *impl->app_loader; 578 return *impl->app_loader;
581} 579}
582 580
583void System::SetGPUDebugContext(std::shared_ptr<Tegra::DebugContext> context) {
584 impl->debug_context = std::move(context);
585}
586
587Tegra::DebugContext* System::GetGPUDebugContext() const {
588 return impl->debug_context.get();
589}
590
591void System::SetFilesystem(std::shared_ptr<FileSys::VfsFilesystem> vfs) { 581void System::SetFilesystem(std::shared_ptr<FileSys::VfsFilesystem> vfs) {
592 impl->virtual_filesystem = std::move(vfs); 582 impl->virtual_filesystem = std::move(vfs);
593} 583}
diff --git a/src/core/core.h b/src/core/core.h
index 91184e433..e240c5c58 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -307,10 +307,6 @@ public:
307 Service::SM::ServiceManager& ServiceManager(); 307 Service::SM::ServiceManager& ServiceManager();
308 const Service::SM::ServiceManager& ServiceManager() const; 308 const Service::SM::ServiceManager& ServiceManager() const;
309 309
310 void SetGPUDebugContext(std::shared_ptr<Tegra::DebugContext> context);
311
312 Tegra::DebugContext* GetGPUDebugContext() const;
313
314 void SetFilesystem(std::shared_ptr<FileSys::VfsFilesystem> vfs); 310 void SetFilesystem(std::shared_ptr<FileSys::VfsFilesystem> vfs);
315 311
316 std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const; 312 std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const;
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 2594cd0bd..65d7b9f93 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -4,8 +4,6 @@ add_library(video_core STATIC
4 buffer_cache/map_interval.h 4 buffer_cache/map_interval.h
5 dma_pusher.cpp 5 dma_pusher.cpp
6 dma_pusher.h 6 dma_pusher.h
7 debug_utils/debug_utils.cpp
8 debug_utils/debug_utils.h
9 engines/const_buffer_engine_interface.h 7 engines/const_buffer_engine_interface.h
10 engines/const_buffer_info.h 8 engines/const_buffer_info.h
11 engines/engine_upload.cpp 9 engines/engine_upload.cpp
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
deleted file mode 100644
index f0ef67535..000000000
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <mutex>
6
7#include "video_core/debug_utils/debug_utils.h"
8
9namespace Tegra {
10
11void DebugContext::DoOnEvent(Event event, void* data) {
12 {
13 std::unique_lock lock{breakpoint_mutex};
14
15 // TODO(Subv): Commit the rasterizer's caches so framebuffers, render targets, etc. will
16 // show on debug widgets
17
18 // TODO: Should stop the CPU thread here once we multithread emulation.
19
20 active_breakpoint = event;
21 at_breakpoint = true;
22
23 // Tell all observers that we hit a breakpoint
24 for (auto& breakpoint_observer : breakpoint_observers) {
25 breakpoint_observer->OnMaxwellBreakPointHit(event, data);
26 }
27
28 // Wait until another thread tells us to Resume()
29 resume_from_breakpoint.wait(lock, [&] { return !at_breakpoint; });
30 }
31}
32
33void DebugContext::Resume() {
34 {
35 std::lock_guard lock{breakpoint_mutex};
36
37 // Tell all observers that we are about to resume
38 for (auto& breakpoint_observer : breakpoint_observers) {
39 breakpoint_observer->OnMaxwellResume();
40 }
41
42 // Resume the waiting thread (i.e. OnEvent())
43 at_breakpoint = false;
44 }
45
46 resume_from_breakpoint.notify_one();
47}
48
49} // namespace Tegra
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h
deleted file mode 100644
index ac3a2eb01..000000000
--- a/src/video_core/debug_utils/debug_utils.h
+++ /dev/null
@@ -1,157 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <condition_variable>
9#include <list>
10#include <memory>
11#include <mutex>
12
13namespace Tegra {
14
15class DebugContext {
16public:
17 enum class Event {
18 FirstEvent = 0,
19
20 MaxwellCommandLoaded = FirstEvent,
21 MaxwellCommandProcessed,
22 IncomingPrimitiveBatch,
23 FinishedPrimitiveBatch,
24
25 NumEvents
26 };
27
28 /**
29 * Inherit from this class to be notified of events registered to some debug context.
30 * Most importantly this is used for our debugger GUI.
31 *
32 * To implement event handling, override the OnMaxwellBreakPointHit and OnMaxwellResume methods.
33 * @warning All BreakPointObservers need to be on the same thread to guarantee thread-safe state
34 * access
35 * @todo Evaluate an alternative interface, in which there is only one managing observer and
36 * multiple child observers running (by design) on the same thread.
37 */
38 class BreakPointObserver {
39 public:
40 /// Constructs the object such that it observes events of the given DebugContext.
41 explicit BreakPointObserver(std::shared_ptr<DebugContext> debug_context)
42 : context_weak(debug_context) {
43 std::unique_lock lock{debug_context->breakpoint_mutex};
44 debug_context->breakpoint_observers.push_back(this);
45 }
46
47 virtual ~BreakPointObserver() {
48 auto context = context_weak.lock();
49 if (context) {
50 {
51 std::unique_lock lock{context->breakpoint_mutex};
52 context->breakpoint_observers.remove(this);
53 }
54
55 // If we are the last observer to be destroyed, tell the debugger context that
56 // it is free to continue. In particular, this is required for a proper yuzu
57 // shutdown, when the emulation thread is waiting at a breakpoint.
58 if (context->breakpoint_observers.empty())
59 context->Resume();
60 }
61 }
62
63 /**
64 * Action to perform when a breakpoint was reached.
65 * @param event Type of event which triggered the breakpoint
66 * @param data Optional data pointer (if unused, this is a nullptr)
67 * @note This function will perform nothing unless it is overridden in the child class.
68 */
69 virtual void OnMaxwellBreakPointHit(Event event, void* data) {}
70
71 /**
72 * Action to perform when emulation is resumed from a breakpoint.
73 * @note This function will perform nothing unless it is overridden in the child class.
74 */
75 virtual void OnMaxwellResume() {}
76
77 protected:
78 /**
79 * Weak context pointer. This need not be valid, so when requesting a shared_ptr via
80 * context_weak.lock(), always compare the result against nullptr.
81 */
82 std::weak_ptr<DebugContext> context_weak;
83 };
84
85 /**
86 * Simple structure defining a breakpoint state
87 */
88 struct BreakPoint {
89 bool enabled = false;
90 };
91
92 /**
93 * Static constructor used to create a shared_ptr of a DebugContext.
94 */
95 static std::shared_ptr<DebugContext> Construct() {
96 return std::shared_ptr<DebugContext>(new DebugContext);
97 }
98
99 /**
100 * Used by the emulation core when a given event has happened. If a breakpoint has been set
101 * for this event, OnEvent calls the event handlers of the registered breakpoint observers.
102 * The current thread then is halted until Resume() is called from another thread (or until
103 * emulation is stopped).
104 * @param event Event which has happened
105 * @param data Optional data pointer (pass nullptr if unused). Needs to remain valid until
106 * Resume() is called.
107 */
108 void OnEvent(Event event, void* data) {
109 // This check is left in the header to allow the compiler to inline it.
110 if (!breakpoints[(int)event].enabled)
111 return;
112 // For the rest of event handling, call a separate function.
113 DoOnEvent(event, data);
114 }
115
116 void DoOnEvent(Event event, void* data);
117
118 /**
119 * Resume from the current breakpoint.
120 * @warning Calling this from the same thread that OnEvent was called in will cause a deadlock.
121 * Calling from any other thread is safe.
122 */
123 void Resume();
124
125 /**
126 * Delete all set breakpoints and resume emulation.
127 */
128 void ClearBreakpoints() {
129 for (auto& bp : breakpoints) {
130 bp.enabled = false;
131 }
132 Resume();
133 }
134
135 // TODO: Evaluate if access to these members should be hidden behind a public interface.
136 std::array<BreakPoint, static_cast<int>(Event::NumEvents)> breakpoints;
137 Event active_breakpoint{};
138 bool at_breakpoint = false;
139
140private:
141 /**
142 * Private default constructor to make sure people always construct this through Construct()
143 * instead.
144 */
145 DebugContext() = default;
146
147 /// Mutex protecting current breakpoint state and the observer list.
148 std::mutex breakpoint_mutex;
149
150 /// Used by OnEvent to wait for resumption.
151 std::condition_variable resume_from_breakpoint;
152
153 /// List of registered observers
154 std::list<BreakPointObserver*> breakpoint_observers;
155};
156
157} // namespace Tegra
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index e1cb8b0b0..1d1f780e7 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -7,7 +7,6 @@
7#include "common/assert.h" 7#include "common/assert.h"
8#include "core/core.h" 8#include "core/core.h"
9#include "core/core_timing.h" 9#include "core/core_timing.h"
10#include "video_core/debug_utils/debug_utils.h"
11#include "video_core/engines/maxwell_3d.h" 10#include "video_core/engines/maxwell_3d.h"
12#include "video_core/engines/shader_type.h" 11#include "video_core/engines/shader_type.h"
13#include "video_core/memory_manager.h" 12#include "video_core/memory_manager.h"
@@ -273,8 +272,6 @@ void Maxwell3D::CallMacroMethod(u32 method, std::size_t num_parameters, const u3
273} 272}
274 273
275void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) { 274void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
276 auto debug_context = system.GetGPUDebugContext();
277
278 const u32 method = method_call.method; 275 const u32 method = method_call.method;
279 276
280 if (method == cb_data_state.current) { 277 if (method == cb_data_state.current) {
@@ -315,10 +312,6 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
315 ASSERT_MSG(method < Regs::NUM_REGS, 312 ASSERT_MSG(method < Regs::NUM_REGS,
316 "Invalid Maxwell3D register, increase the size of the Regs structure"); 313 "Invalid Maxwell3D register, increase the size of the Regs structure");
317 314
318 if (debug_context) {
319 debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandLoaded, nullptr);
320 }
321
322 if (regs.reg_array[method] != method_call.argument) { 315 if (regs.reg_array[method] != method_call.argument) {
323 regs.reg_array[method] = method_call.argument; 316 regs.reg_array[method] = method_call.argument;
324 const std::size_t dirty_reg = dirty_pointers[method]; 317 const std::size_t dirty_reg = dirty_pointers[method];
@@ -424,10 +417,6 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
424 default: 417 default:
425 break; 418 break;
426 } 419 }
427
428 if (debug_context) {
429 debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandProcessed, nullptr);
430 }
431} 420}
432 421
433void Maxwell3D::StepInstance(const MMEDrawMode expected_mode, const u32 count) { 422void Maxwell3D::StepInstance(const MMEDrawMode expected_mode, const u32 count) {
@@ -485,12 +474,6 @@ void Maxwell3D::FlushMMEInlineDraw() {
485 ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?"); 474 ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?");
486 ASSERT(mme_draw.instance_count == mme_draw.gl_end_count); 475 ASSERT(mme_draw.instance_count == mme_draw.gl_end_count);
487 476
488 auto debug_context = system.GetGPUDebugContext();
489
490 if (debug_context) {
491 debug_context->OnEvent(Tegra::DebugContext::Event::IncomingPrimitiveBatch, nullptr);
492 }
493
494 // Both instance configuration registers can not be set at the same time. 477 // Both instance configuration registers can not be set at the same time.
495 ASSERT_MSG(!regs.draw.instance_next || !regs.draw.instance_cont, 478 ASSERT_MSG(!regs.draw.instance_next || !regs.draw.instance_cont,
496 "Illegal combination of instancing parameters"); 479 "Illegal combination of instancing parameters");
@@ -500,10 +483,6 @@ void Maxwell3D::FlushMMEInlineDraw() {
500 rasterizer.DrawMultiBatch(is_indexed); 483 rasterizer.DrawMultiBatch(is_indexed);
501 } 484 }
502 485
503 if (debug_context) {
504 debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr);
505 }
506
507 // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if 486 // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if
508 // the game is trying to draw indexed or direct mode. This needs to be verified on HW still - 487 // the game is trying to draw indexed or direct mode. This needs to be verified on HW still -
509 // it's possible that it is incorrect and that there is some other register used to specify the 488 // it's possible that it is incorrect and that there is some other register used to specify the
@@ -650,12 +629,6 @@ void Maxwell3D::DrawArrays() {
650 regs.vertex_buffer.count); 629 regs.vertex_buffer.count);
651 ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?"); 630 ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?");
652 631
653 auto debug_context = system.GetGPUDebugContext();
654
655 if (debug_context) {
656 debug_context->OnEvent(Tegra::DebugContext::Event::IncomingPrimitiveBatch, nullptr);
657 }
658
659 // Both instance configuration registers can not be set at the same time. 632 // Both instance configuration registers can not be set at the same time.
660 ASSERT_MSG(!regs.draw.instance_next || !regs.draw.instance_cont, 633 ASSERT_MSG(!regs.draw.instance_next || !regs.draw.instance_cont,
661 "Illegal combination of instancing parameters"); 634 "Illegal combination of instancing parameters");
@@ -673,10 +646,6 @@ void Maxwell3D::DrawArrays() {
673 rasterizer.DrawBatch(is_indexed); 646 rasterizer.DrawBatch(is_indexed);
674 } 647 }
675 648
676 if (debug_context) {
677 debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr);
678 }
679
680 // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if 649 // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if
681 // the game is trying to draw indexed or direct mode. This needs to be verified on HW still - 650 // the game is trying to draw indexed or direct mode. This needs to be verified on HW still -
682 // it's possible that it is incorrect and that there is some other register used to specify the 651 // it's possible that it is incorrect and that there is some other register used to specify the
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index ff1c1d985..11ae1e66e 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -78,11 +78,6 @@ add_executable(yuzu
78 configuration/configure_web.cpp 78 configuration/configure_web.cpp
79 configuration/configure_web.h 79 configuration/configure_web.h
80 configuration/configure_web.ui 80 configuration/configure_web.ui
81 debugger/graphics/graphics_breakpoint_observer.cpp
82 debugger/graphics/graphics_breakpoint_observer.h
83 debugger/graphics/graphics_breakpoints.cpp
84 debugger/graphics/graphics_breakpoints.h
85 debugger/graphics/graphics_breakpoints_p.h
86 debugger/console.cpp 81 debugger/console.cpp
87 debugger/console.h 82 debugger/console.h
88 debugger/profiler.cpp 83 debugger/profiler.cpp
diff --git a/src/yuzu/debugger/graphics/graphics_breakpoint_observer.cpp b/src/yuzu/debugger/graphics/graphics_breakpoint_observer.cpp
deleted file mode 100644
index 5f459ccfb..000000000
--- a/src/yuzu/debugger/graphics/graphics_breakpoint_observer.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <QMetaType>
6#include "yuzu/debugger/graphics/graphics_breakpoint_observer.h"
7
8BreakPointObserverDock::BreakPointObserverDock(std::shared_ptr<Tegra::DebugContext> debug_context,
9 const QString& title, QWidget* parent)
10 : QDockWidget(title, parent), BreakPointObserver(debug_context) {
11 qRegisterMetaType<Tegra::DebugContext::Event>("Tegra::DebugContext::Event");
12
13 connect(this, &BreakPointObserverDock::Resumed, this, &BreakPointObserverDock::OnResumed);
14
15 // NOTE: This signal is emitted from a non-GUI thread, but connect() takes
16 // care of delaying its handling to the GUI thread.
17 connect(this, &BreakPointObserverDock::BreakPointHit, this,
18 &BreakPointObserverDock::OnBreakPointHit, Qt::BlockingQueuedConnection);
19}
20
21void BreakPointObserverDock::OnMaxwellBreakPointHit(Tegra::DebugContext::Event event, void* data) {
22 emit BreakPointHit(event, data);
23}
24
25void BreakPointObserverDock::OnMaxwellResume() {
26 emit Resumed();
27}
diff --git a/src/yuzu/debugger/graphics/graphics_breakpoint_observer.h b/src/yuzu/debugger/graphics/graphics_breakpoint_observer.h
deleted file mode 100644
index ab32f0115..000000000
--- a/src/yuzu/debugger/graphics/graphics_breakpoint_observer.h
+++ /dev/null
@@ -1,33 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <QDockWidget>
8#include "video_core/debug_utils/debug_utils.h"
9
10/**
11 * Utility class which forwards calls to OnMaxwellBreakPointHit and OnMaxwellResume to public slots.
12 * This is because the Maxwell breakpoint callbacks are called from a non-GUI thread, while
13 * the widget usually wants to perform reactions in the GUI thread.
14 */
15class BreakPointObserverDock : public QDockWidget,
16 protected Tegra::DebugContext::BreakPointObserver {
17 Q_OBJECT
18
19public:
20 BreakPointObserverDock(std::shared_ptr<Tegra::DebugContext> debug_context, const QString& title,
21 QWidget* parent = nullptr);
22
23 void OnMaxwellBreakPointHit(Tegra::DebugContext::Event event, void* data) override;
24 void OnMaxwellResume() override;
25
26signals:
27 void Resumed();
28 void BreakPointHit(Tegra::DebugContext::Event event, void* data);
29
30private:
31 virtual void OnBreakPointHit(Tegra::DebugContext::Event event, void* data) = 0;
32 virtual void OnResumed() = 0;
33};
diff --git a/src/yuzu/debugger/graphics/graphics_breakpoints.cpp b/src/yuzu/debugger/graphics/graphics_breakpoints.cpp
deleted file mode 100644
index 1c80082a4..000000000
--- a/src/yuzu/debugger/graphics/graphics_breakpoints.cpp
+++ /dev/null
@@ -1,221 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <QLabel>
6#include <QMetaType>
7#include <QPushButton>
8#include <QTreeView>
9#include <QVBoxLayout>
10#include "common/assert.h"
11#include "yuzu/debugger/graphics/graphics_breakpoints.h"
12#include "yuzu/debugger/graphics/graphics_breakpoints_p.h"
13
14BreakPointModel::BreakPointModel(std::shared_ptr<Tegra::DebugContext> debug_context,
15 QObject* parent)
16 : QAbstractListModel(parent), context_weak(debug_context),
17 at_breakpoint(debug_context->at_breakpoint),
18 active_breakpoint(debug_context->active_breakpoint) {}
19
20int BreakPointModel::columnCount(const QModelIndex& parent) const {
21 return 1;
22}
23
24int BreakPointModel::rowCount(const QModelIndex& parent) const {
25 return static_cast<int>(Tegra::DebugContext::Event::NumEvents);
26}
27
28QVariant BreakPointModel::data(const QModelIndex& index, int role) const {
29 const auto event = static_cast<Tegra::DebugContext::Event>(index.row());
30
31 switch (role) {
32 case Qt::DisplayRole: {
33 if (index.column() == 0) {
34 return DebugContextEventToString(event);
35 }
36 break;
37 }
38
39 case Qt::CheckStateRole: {
40 if (index.column() == 0)
41 return data(index, Role_IsEnabled).toBool() ? Qt::Checked : Qt::Unchecked;
42 break;
43 }
44
45 case Qt::BackgroundRole: {
46 if (at_breakpoint && index.row() == static_cast<int>(active_breakpoint)) {
47 return QBrush(QColor(0xE0, 0xE0, 0x10));
48 }
49 break;
50 }
51
52 case Role_IsEnabled: {
53 auto context = context_weak.lock();
54 return context && context->breakpoints[(int)event].enabled;
55 }
56
57 default:
58 break;
59 }
60 return QVariant();
61}
62
63Qt::ItemFlags BreakPointModel::flags(const QModelIndex& index) const {
64 if (!index.isValid())
65 return 0;
66
67 Qt::ItemFlags flags = Qt::ItemIsEnabled;
68 if (index.column() == 0)
69 flags |= Qt::ItemIsUserCheckable;
70 return flags;
71}
72
73bool BreakPointModel::setData(const QModelIndex& index, const QVariant& value, int role) {
74 const auto event = static_cast<Tegra::DebugContext::Event>(index.row());
75
76 switch (role) {
77 case Qt::CheckStateRole: {
78 if (index.column() != 0)
79 return false;
80
81 auto context = context_weak.lock();
82 if (!context)
83 return false;
84
85 context->breakpoints[(int)event].enabled = value == Qt::Checked;
86 QModelIndex changed_index = createIndex(index.row(), 0);
87 emit dataChanged(changed_index, changed_index);
88 return true;
89 }
90 }
91
92 return false;
93}
94
95void BreakPointModel::OnBreakPointHit(Tegra::DebugContext::Event event) {
96 auto context = context_weak.lock();
97 if (!context)
98 return;
99
100 active_breakpoint = context->active_breakpoint;
101 at_breakpoint = context->at_breakpoint;
102 emit dataChanged(createIndex(static_cast<int>(event), 0),
103 createIndex(static_cast<int>(event), 0));
104}
105
106void BreakPointModel::OnResumed() {
107 auto context = context_weak.lock();
108 if (!context)
109 return;
110
111 at_breakpoint = context->at_breakpoint;
112 emit dataChanged(createIndex(static_cast<int>(active_breakpoint), 0),
113 createIndex(static_cast<int>(active_breakpoint), 0));
114 active_breakpoint = context->active_breakpoint;
115}
116
117QString BreakPointModel::DebugContextEventToString(Tegra::DebugContext::Event event) {
118 switch (event) {
119 case Tegra::DebugContext::Event::MaxwellCommandLoaded:
120 return tr("Maxwell command loaded");
121 case Tegra::DebugContext::Event::MaxwellCommandProcessed:
122 return tr("Maxwell command processed");
123 case Tegra::DebugContext::Event::IncomingPrimitiveBatch:
124 return tr("Incoming primitive batch");
125 case Tegra::DebugContext::Event::FinishedPrimitiveBatch:
126 return tr("Finished primitive batch");
127 case Tegra::DebugContext::Event::NumEvents:
128 break;
129 }
130
131 return tr("Unknown debug context event");
132}
133
134GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(
135 std::shared_ptr<Tegra::DebugContext> debug_context, QWidget* parent)
136 : QDockWidget(tr("Maxwell Breakpoints"), parent), Tegra::DebugContext::BreakPointObserver(
137 debug_context) {
138 setObjectName(QStringLiteral("TegraBreakPointsWidget"));
139
140 status_text = new QLabel(tr("Emulation running"));
141 resume_button = new QPushButton(tr("Resume"));
142 resume_button->setEnabled(false);
143
144 breakpoint_model = new BreakPointModel(debug_context, this);
145 breakpoint_list = new QTreeView;
146 breakpoint_list->setRootIsDecorated(false);
147 breakpoint_list->setHeaderHidden(true);
148 breakpoint_list->setModel(breakpoint_model);
149
150 qRegisterMetaType<Tegra::DebugContext::Event>("Tegra::DebugContext::Event");
151
152 connect(breakpoint_list, &QTreeView::doubleClicked, this,
153 &GraphicsBreakPointsWidget::OnItemDoubleClicked);
154
155 connect(resume_button, &QPushButton::clicked, this,
156 &GraphicsBreakPointsWidget::OnResumeRequested);
157
158 connect(this, &GraphicsBreakPointsWidget::BreakPointHit, this,
159 &GraphicsBreakPointsWidget::OnBreakPointHit, Qt::BlockingQueuedConnection);
160 connect(this, &GraphicsBreakPointsWidget::Resumed, this, &GraphicsBreakPointsWidget::OnResumed);
161
162 connect(this, &GraphicsBreakPointsWidget::BreakPointHit, breakpoint_model,
163 &BreakPointModel::OnBreakPointHit, Qt::BlockingQueuedConnection);
164 connect(this, &GraphicsBreakPointsWidget::Resumed, breakpoint_model,
165 &BreakPointModel::OnResumed);
166
167 connect(this, &GraphicsBreakPointsWidget::BreakPointsChanged,
168 [this](const QModelIndex& top_left, const QModelIndex& bottom_right) {
169 breakpoint_model->dataChanged(top_left, bottom_right);
170 });
171
172 QWidget* main_widget = new QWidget;
173 auto main_layout = new QVBoxLayout;
174 {
175 auto sub_layout = new QHBoxLayout;
176 sub_layout->addWidget(status_text);
177 sub_layout->addWidget(resume_button);
178 main_layout->addLayout(sub_layout);
179 }
180 main_layout->addWidget(breakpoint_list);
181 main_widget->setLayout(main_layout);
182
183 setWidget(main_widget);
184}
185
186void GraphicsBreakPointsWidget::OnMaxwellBreakPointHit(Event event, void* data) {
187 // Process in GUI thread
188 emit BreakPointHit(event, data);
189}
190
191void GraphicsBreakPointsWidget::OnBreakPointHit(Tegra::DebugContext::Event event, void* data) {
192 status_text->setText(tr("Emulation halted at breakpoint"));
193 resume_button->setEnabled(true);
194}
195
196void GraphicsBreakPointsWidget::OnMaxwellResume() {
197 // Process in GUI thread
198 emit Resumed();
199}
200
201void GraphicsBreakPointsWidget::OnResumed() {
202 status_text->setText(tr("Emulation running"));
203 resume_button->setEnabled(false);
204}
205
206void GraphicsBreakPointsWidget::OnResumeRequested() {
207 if (auto context = context_weak.lock())
208 context->Resume();
209}
210
211void GraphicsBreakPointsWidget::OnItemDoubleClicked(const QModelIndex& index) {
212 if (!index.isValid())
213 return;
214
215 QModelIndex check_index = breakpoint_list->model()->index(index.row(), 0);
216 QVariant enabled = breakpoint_list->model()->data(check_index, Qt::CheckStateRole);
217 QVariant new_state = Qt::Unchecked;
218 if (enabled == Qt::Unchecked)
219 new_state = Qt::Checked;
220 breakpoint_list->model()->setData(check_index, new_state, Qt::CheckStateRole);
221}
diff --git a/src/yuzu/debugger/graphics/graphics_breakpoints.h b/src/yuzu/debugger/graphics/graphics_breakpoints.h
deleted file mode 100644
index a920a2ae5..000000000
--- a/src/yuzu/debugger/graphics/graphics_breakpoints.h
+++ /dev/null
@@ -1,45 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <QDockWidget>
9#include "video_core/debug_utils/debug_utils.h"
10
11class QLabel;
12class QPushButton;
13class QTreeView;
14
15class BreakPointModel;
16
17class GraphicsBreakPointsWidget : public QDockWidget, Tegra::DebugContext::BreakPointObserver {
18 Q_OBJECT
19
20 using Event = Tegra::DebugContext::Event;
21
22public:
23 explicit GraphicsBreakPointsWidget(std::shared_ptr<Tegra::DebugContext> debug_context,
24 QWidget* parent = nullptr);
25
26 void OnMaxwellBreakPointHit(Tegra::DebugContext::Event event, void* data) override;
27 void OnMaxwellResume() override;
28
29signals:
30 void Resumed();
31 void BreakPointHit(Tegra::DebugContext::Event event, void* data);
32 void BreakPointsChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
33
34private:
35 void OnBreakPointHit(Tegra::DebugContext::Event event, void* data);
36 void OnItemDoubleClicked(const QModelIndex&);
37 void OnResumeRequested();
38 void OnResumed();
39
40 QLabel* status_text;
41 QPushButton* resume_button;
42
43 BreakPointModel* breakpoint_model;
44 QTreeView* breakpoint_list;
45};
diff --git a/src/yuzu/debugger/graphics/graphics_breakpoints_p.h b/src/yuzu/debugger/graphics/graphics_breakpoints_p.h
deleted file mode 100644
index fb488e38f..000000000
--- a/src/yuzu/debugger/graphics/graphics_breakpoints_p.h
+++ /dev/null
@@ -1,37 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <QAbstractListModel>
9#include "video_core/debug_utils/debug_utils.h"
10
11class BreakPointModel : public QAbstractListModel {
12 Q_OBJECT
13
14public:
15 enum {
16 Role_IsEnabled = Qt::UserRole,
17 };
18
19 BreakPointModel(std::shared_ptr<Tegra::DebugContext> context, QObject* parent);
20
21 int columnCount(const QModelIndex& parent = QModelIndex()) const override;
22 int rowCount(const QModelIndex& parent = QModelIndex()) const override;
23 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
24 Qt::ItemFlags flags(const QModelIndex& index) const override;
25
26 bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
27
28 void OnBreakPointHit(Tegra::DebugContext::Event event);
29 void OnResumed();
30
31private:
32 static QString DebugContextEventToString(Tegra::DebugContext::Event event);
33
34 std::weak_ptr<Tegra::DebugContext> context_weak;
35 bool at_breakpoint;
36 Tegra::DebugContext::Event active_breakpoint;
37};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 867f8e913..b21fbf826 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -93,7 +93,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
93#include "core/perf_stats.h" 93#include "core/perf_stats.h"
94#include "core/settings.h" 94#include "core/settings.h"
95#include "core/telemetry_session.h" 95#include "core/telemetry_session.h"
96#include "video_core/debug_utils/debug_utils.h"
97#include "yuzu/about_dialog.h" 96#include "yuzu/about_dialog.h"
98#include "yuzu/bootmanager.h" 97#include "yuzu/bootmanager.h"
99#include "yuzu/compatdb.h" 98#include "yuzu/compatdb.h"
@@ -101,7 +100,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
101#include "yuzu/configuration/config.h" 100#include "yuzu/configuration/config.h"
102#include "yuzu/configuration/configure_dialog.h" 101#include "yuzu/configuration/configure_dialog.h"
103#include "yuzu/debugger/console.h" 102#include "yuzu/debugger/console.h"
104#include "yuzu/debugger/graphics/graphics_breakpoints.h"
105#include "yuzu/debugger/profiler.h" 103#include "yuzu/debugger/profiler.h"
106#include "yuzu/debugger/wait_tree.h" 104#include "yuzu/debugger/wait_tree.h"
107#include "yuzu/discord.h" 105#include "yuzu/discord.h"
@@ -187,8 +185,6 @@ GMainWindow::GMainWindow()
187 provider(std::make_unique<FileSys::ManualContentProvider>()) { 185 provider(std::make_unique<FileSys::ManualContentProvider>()) {
188 InitializeLogging(); 186 InitializeLogging();
189 187
190 debug_context = Tegra::DebugContext::Construct();
191
192 setAcceptDrops(true); 188 setAcceptDrops(true);
193 ui.setupUi(this); 189 ui.setupUi(this);
194 statusBar()->hide(); 190 statusBar()->hide();
@@ -495,11 +491,6 @@ void GMainWindow::InitializeDebugWidgets() {
495 debug_menu->addAction(microProfileDialog->toggleViewAction()); 491 debug_menu->addAction(microProfileDialog->toggleViewAction());
496#endif 492#endif
497 493
498 graphicsBreakpointsWidget = new GraphicsBreakPointsWidget(debug_context, this);
499 addDockWidget(Qt::RightDockWidgetArea, graphicsBreakpointsWidget);
500 graphicsBreakpointsWidget->hide();
501 debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction());
502
503 waitTreeWidget = new WaitTreeWidget(this); 494 waitTreeWidget = new WaitTreeWidget(this);
504 addDockWidget(Qt::LeftDockWidgetArea, waitTreeWidget); 495 addDockWidget(Qt::LeftDockWidgetArea, waitTreeWidget);
505 waitTreeWidget->hide(); 496 waitTreeWidget->hide();
@@ -869,8 +860,6 @@ bool GMainWindow::LoadROM(const QString& filename) {
869 Core::System& system{Core::System::GetInstance()}; 860 Core::System& system{Core::System::GetInstance()};
870 system.SetFilesystem(vfs); 861 system.SetFilesystem(vfs);
871 862
872 system.SetGPUDebugContext(debug_context);
873
874 system.SetAppletFrontendSet({ 863 system.SetAppletFrontendSet({
875 nullptr, // Parental Controls 864 nullptr, // Parental Controls
876 std::make_unique<QtErrorDisplay>(*this), // 865 std::make_unique<QtErrorDisplay>(*this), //
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 7f46bea2b..a56f9a981 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -22,7 +22,6 @@ class Config;
22class EmuThread; 22class EmuThread;
23class GameList; 23class GameList;
24class GImageInfo; 24class GImageInfo;
25class GraphicsBreakPointsWidget;
26class GRenderWindow; 25class GRenderWindow;
27class LoadingScreen; 26class LoadingScreen;
28class MicroProfileDialog; 27class MicroProfileDialog;
@@ -42,10 +41,6 @@ class ManualContentProvider;
42class VfsFilesystem; 41class VfsFilesystem;
43} // namespace FileSys 42} // namespace FileSys
44 43
45namespace Tegra {
46class DebugContext;
47}
48
49enum class EmulatedDirectoryTarget { 44enum class EmulatedDirectoryTarget {
50 NAND, 45 NAND,
51 SDMC, 46 SDMC,
@@ -223,8 +218,6 @@ private:
223 218
224 Ui::MainWindow ui; 219 Ui::MainWindow ui;
225 220
226 std::shared_ptr<Tegra::DebugContext> debug_context;
227
228 GRenderWindow* render_window; 221 GRenderWindow* render_window;
229 GameList* game_list; 222 GameList* game_list;
230 LoadingScreen* loading_screen; 223 LoadingScreen* loading_screen;
@@ -255,7 +248,6 @@ private:
255 // Debugger panes 248 // Debugger panes
256 ProfilerWidget* profilerWidget; 249 ProfilerWidget* profilerWidget;
257 MicroProfileDialog* microProfileDialog; 250 MicroProfileDialog* microProfileDialog;
258 GraphicsBreakPointsWidget* graphicsBreakpointsWidget;
259 WaitTreeWidget* waitTreeWidget; 251 WaitTreeWidget* waitTreeWidget;
260 252
261 QAction* actions_recent_files[max_recent_files_item]; 253 QAction* actions_recent_files[max_recent_files_item];