summaryrefslogtreecommitdiff
path: root/src/video_core
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp66
-rw-r--r--src/video_core/debug_utils/debug_utils.h165
-rw-r--r--src/video_core/gpu.cpp4
-rw-r--r--src/video_core/gpu.h5
5 files changed, 242 insertions, 0 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 8c0e6663b..3dab81769 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -1,6 +1,8 @@
1add_library(video_core STATIC 1add_library(video_core STATIC
2 command_processor.cpp 2 command_processor.cpp
3 command_processor.h 3 command_processor.h
4 debug_utils/debug_utils.cpp
5 debug_utils/debug_utils.h
4 engines/fermi_2d.cpp 6 engines/fermi_2d.cpp
5 engines/fermi_2d.h 7 engines/fermi_2d.h
6 engines/maxwell_3d.cpp 8 engines/maxwell_3d.cpp
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
new file mode 100644
index 000000000..73fd4d7a3
--- /dev/null
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -0,0 +1,66 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <condition_variable>
7#include <cstdint>
8#include <cstring>
9#include <fstream>
10#include <map>
11#include <mutex>
12#include <string>
13
14#include "common/assert.h"
15#include "common/bit_field.h"
16#include "common/color.h"
17#include "common/common_types.h"
18#include "common/file_util.h"
19#include "common/logging/log.h"
20#include "common/math_util.h"
21#include "common/vector_math.h"
22#include "video_core/debug_utils/debug_utils.h"
23
24namespace Tegra {
25
26std::shared_ptr<DebugContext> g_debug_context;
27
28void DebugContext::DoOnEvent(Event event, void* data) {
29 {
30 std::unique_lock<std::mutex> lock(breakpoint_mutex);
31
32 // TODO(Subv): Commit the rasterizer's caches so framebuffers, render targets, etc. will
33 // show on debug widgets
34
35 // TODO: Should stop the CPU thread here once we multithread emulation.
36
37 active_breakpoint = event;
38 at_breakpoint = true;
39
40 // Tell all observers that we hit a breakpoint
41 for (auto& breakpoint_observer : breakpoint_observers) {
42 breakpoint_observer->OnMaxwellBreakPointHit(event, data);
43 }
44
45 // Wait until another thread tells us to Resume()
46 resume_from_breakpoint.wait(lock, [&] { return !at_breakpoint; });
47 }
48}
49
50void DebugContext::Resume() {
51 {
52 std::lock_guard<std::mutex> lock(breakpoint_mutex);
53
54 // Tell all observers that we are about to resume
55 for (auto& breakpoint_observer : breakpoint_observers) {
56 breakpoint_observer->OnMaxwellResume();
57 }
58
59 // Resume the waiting thread (i.e. OnEvent())
60 at_breakpoint = false;
61 }
62
63 resume_from_breakpoint.notify_one();
64}
65
66} // namespace Tegra
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h
new file mode 100644
index 000000000..98461d6d9
--- /dev/null
+++ b/src/video_core/debug_utils/debug_utils.h
@@ -0,0 +1,165 @@
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 <algorithm>
8#include <array>
9#include <condition_variable>
10#include <iterator>
11#include <list>
12#include <map>
13#include <memory>
14#include <mutex>
15#include <string>
16#include <utility>
17#include <vector>
18#include "common/common_types.h"
19#include "common/vector_math.h"
20
21namespace Tegra {
22
23class DebugContext {
24public:
25 enum class Event {
26 FirstEvent = 0,
27
28 MaxwellCommandLoaded = FirstEvent,
29 MaxwellCommandProcessed,
30 IncomingPrimitiveBatch,
31 FinishedPrimitiveBatch,
32
33 NumEvents
34 };
35
36 /**
37 * Inherit from this class to be notified of events registered to some debug context.
38 * Most importantly this is used for our debugger GUI.
39 *
40 * To implement event handling, override the OnMaxwellBreakPointHit and OnMaxwellResume methods.
41 * @warning All BreakPointObservers need to be on the same thread to guarantee thread-safe state
42 * access
43 * @todo Evaluate an alternative interface, in which there is only one managing observer and
44 * multiple child observers running (by design) on the same thread.
45 */
46 class BreakPointObserver {
47 public:
48 /// Constructs the object such that it observes events of the given DebugContext.
49 BreakPointObserver(std::shared_ptr<DebugContext> debug_context)
50 : context_weak(debug_context) {
51 std::unique_lock<std::mutex> lock(debug_context->breakpoint_mutex);
52 debug_context->breakpoint_observers.push_back(this);
53 }
54
55 virtual ~BreakPointObserver() {
56 auto context = context_weak.lock();
57 if (context) {
58 std::unique_lock<std::mutex> lock(context->breakpoint_mutex);
59 context->breakpoint_observers.remove(this);
60
61 // If we are the last observer to be destroyed, tell the debugger context that
62 // it is free to continue. In particular, this is required for a proper yuzu
63 // shutdown, when the emulation thread is waiting at a breakpoint.
64 if (context->breakpoint_observers.empty())
65 context->Resume();
66 }
67 }
68
69 /**
70 * Action to perform when a breakpoint was reached.
71 * @param event Type of event which triggered the breakpoint
72 * @param data Optional data pointer (if unused, this is a nullptr)
73 * @note This function will perform nothing unless it is overridden in the child class.
74 */
75 virtual void OnMaxwellBreakPointHit(Event event, void* data) {}
76
77 /**
78 * Action to perform when emulation is resumed from a breakpoint.
79 * @note This function will perform nothing unless it is overridden in the child class.
80 */
81 virtual void OnMaxwellResume() {}
82
83 protected:
84 /**
85 * Weak context pointer. This need not be valid, so when requesting a shared_ptr via
86 * context_weak.lock(), always compare the result against nullptr.
87 */
88 std::weak_ptr<DebugContext> context_weak;
89 };
90
91 /**
92 * Simple structure defining a breakpoint state
93 */
94 struct BreakPoint {
95 bool enabled = false;
96 };
97
98 /**
99 * Static constructor used to create a shared_ptr of a DebugContext.
100 */
101 static std::shared_ptr<DebugContext> Construct() {
102 return std::shared_ptr<DebugContext>(new DebugContext);
103 }
104
105 /**
106 * Used by the emulation core when a given event has happened. If a breakpoint has been set
107 * for this event, OnEvent calls the event handlers of the registered breakpoint observers.
108 * The current thread then is halted until Resume() is called from another thread (or until
109 * emulation is stopped).
110 * @param event Event which has happened
111 * @param data Optional data pointer (pass nullptr if unused). Needs to remain valid until
112 * Resume() is called.
113 */
114 void OnEvent(Event event, void* data) {
115 // This check is left in the header to allow the compiler to inline it.
116 if (!breakpoints[(int)event].enabled)
117 return;
118 // For the rest of event handling, call a separate function.
119 DoOnEvent(event, data);
120 }
121
122 void DoOnEvent(Event event, void* data);
123
124 /**
125 * Resume from the current breakpoint.
126 * @warning Calling this from the same thread that OnEvent was called in will cause a deadlock.
127 * Calling from any other thread is safe.
128 */
129 void Resume();
130
131 /**
132 * Delete all set breakpoints and resume emulation.
133 */
134 void ClearBreakpoints() {
135 for (auto& bp : breakpoints) {
136 bp.enabled = false;
137 }
138 Resume();
139 }
140
141 // TODO: Evaluate if access to these members should be hidden behind a public interface.
142 std::array<BreakPoint, (int)Event::NumEvents> breakpoints;
143 Event active_breakpoint;
144 bool at_breakpoint = false;
145
146private:
147 /**
148 * Private default constructor to make sure people always construct this through Construct()
149 * instead.
150 */
151 DebugContext() = default;
152
153 /// Mutex protecting current breakpoint state and the observer list.
154 std::mutex breakpoint_mutex;
155
156 /// Used by OnEvent to wait for resumption.
157 std::condition_variable resume_from_breakpoint;
158
159 /// List of registered observers
160 std::list<BreakPointObserver*> breakpoint_observers;
161};
162
163extern std::shared_ptr<DebugContext> g_debug_context;
164
165} // namespace Tegra
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index c384d236e..9463cd5d6 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -18,4 +18,8 @@ GPU::GPU() {
18 18
19GPU::~GPU() = default; 19GPU::~GPU() = default;
20 20
21const Tegra::Engines::Maxwell3D& GPU::Get3DEngine() const {
22 return *maxwell_3d;
23}
24
21} // namespace Tegra 25} // namespace Tegra
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 206b3e05e..778b63218 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -13,6 +13,8 @@
13 13
14namespace Tegra { 14namespace Tegra {
15 15
16class DebugContext;
17
16/** 18/**
17 * Struct describing framebuffer configuration 19 * Struct describing framebuffer configuration
18 */ 20 */
@@ -66,6 +68,9 @@ public:
66 /// Processes a command list stored at the specified address in GPU memory. 68 /// Processes a command list stored at the specified address in GPU memory.
67 void ProcessCommandList(GPUVAddr address, u32 size); 69 void ProcessCommandList(GPUVAddr address, u32 size);
68 70
71 /// Returns a reference to the Maxwell3D GPU engine.
72 const Engines::Maxwell3D& Get3DEngine() const;
73
69 std::unique_ptr<MemoryManager> memory_manager; 74 std::unique_ptr<MemoryManager> memory_manager;
70 75
71 Engines::Maxwell3D& Maxwell3D() { 76 Engines::Maxwell3D& Maxwell3D() {