yuzu: Remove Maxwell debugger
This was carried from Citra and wasn't really used on yuzu. It also adds some runtime overhead. This commit removes it from yuzu's codebase.
This commit is contained in:
parent
ae0e481677
commit
0d6d8129c4
14 changed files with 0 additions and 640 deletions
|
@ -46,7 +46,6 @@
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "core/telemetry_session.h"
|
#include "core/telemetry_session.h"
|
||||||
#include "core/tools/freezer.h"
|
#include "core/tools/freezer.h"
|
||||||
#include "video_core/debug_utils/debug_utils.h"
|
|
||||||
#include "video_core/renderer_base.h"
|
#include "video_core/renderer_base.h"
|
||||||
#include "video_core/video_core.h"
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
|
@ -341,7 +340,6 @@ struct System::Impl {
|
||||||
std::unique_ptr<Loader::AppLoader> app_loader;
|
std::unique_ptr<Loader::AppLoader> app_loader;
|
||||||
std::unique_ptr<VideoCore::RendererBase> renderer;
|
std::unique_ptr<VideoCore::RendererBase> renderer;
|
||||||
std::unique_ptr<Tegra::GPU> gpu_core;
|
std::unique_ptr<Tegra::GPU> gpu_core;
|
||||||
std::shared_ptr<Tegra::DebugContext> debug_context;
|
|
||||||
std::unique_ptr<Hardware::InterruptManager> interrupt_manager;
|
std::unique_ptr<Hardware::InterruptManager> interrupt_manager;
|
||||||
Memory::Memory memory;
|
Memory::Memory memory;
|
||||||
CpuCoreManager cpu_core_manager;
|
CpuCoreManager cpu_core_manager;
|
||||||
|
@ -580,14 +578,6 @@ Loader::AppLoader& System::GetAppLoader() const {
|
||||||
return *impl->app_loader;
|
return *impl->app_loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::SetGPUDebugContext(std::shared_ptr<Tegra::DebugContext> context) {
|
|
||||||
impl->debug_context = std::move(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
Tegra::DebugContext* System::GetGPUDebugContext() const {
|
|
||||||
return impl->debug_context.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void System::SetFilesystem(std::shared_ptr<FileSys::VfsFilesystem> vfs) {
|
void System::SetFilesystem(std::shared_ptr<FileSys::VfsFilesystem> vfs) {
|
||||||
impl->virtual_filesystem = std::move(vfs);
|
impl->virtual_filesystem = std::move(vfs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -307,10 +307,6 @@ public:
|
||||||
Service::SM::ServiceManager& ServiceManager();
|
Service::SM::ServiceManager& ServiceManager();
|
||||||
const Service::SM::ServiceManager& ServiceManager() const;
|
const Service::SM::ServiceManager& ServiceManager() const;
|
||||||
|
|
||||||
void SetGPUDebugContext(std::shared_ptr<Tegra::DebugContext> context);
|
|
||||||
|
|
||||||
Tegra::DebugContext* GetGPUDebugContext() const;
|
|
||||||
|
|
||||||
void SetFilesystem(std::shared_ptr<FileSys::VfsFilesystem> vfs);
|
void SetFilesystem(std::shared_ptr<FileSys::VfsFilesystem> vfs);
|
||||||
|
|
||||||
std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const;
|
std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const;
|
||||||
|
|
|
@ -4,8 +4,6 @@ add_library(video_core STATIC
|
||||||
buffer_cache/map_interval.h
|
buffer_cache/map_interval.h
|
||||||
dma_pusher.cpp
|
dma_pusher.cpp
|
||||||
dma_pusher.h
|
dma_pusher.h
|
||||||
debug_utils/debug_utils.cpp
|
|
||||||
debug_utils/debug_utils.h
|
|
||||||
engines/const_buffer_engine_interface.h
|
engines/const_buffer_engine_interface.h
|
||||||
engines/const_buffer_info.h
|
engines/const_buffer_info.h
|
||||||
engines/engine_upload.cpp
|
engines/engine_upload.cpp
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
// Copyright 2014 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
#include "video_core/debug_utils/debug_utils.h"
|
|
||||||
|
|
||||||
namespace Tegra {
|
|
||||||
|
|
||||||
void DebugContext::DoOnEvent(Event event, void* data) {
|
|
||||||
{
|
|
||||||
std::unique_lock lock{breakpoint_mutex};
|
|
||||||
|
|
||||||
// TODO(Subv): Commit the rasterizer's caches so framebuffers, render targets, etc. will
|
|
||||||
// show on debug widgets
|
|
||||||
|
|
||||||
// TODO: Should stop the CPU thread here once we multithread emulation.
|
|
||||||
|
|
||||||
active_breakpoint = event;
|
|
||||||
at_breakpoint = true;
|
|
||||||
|
|
||||||
// Tell all observers that we hit a breakpoint
|
|
||||||
for (auto& breakpoint_observer : breakpoint_observers) {
|
|
||||||
breakpoint_observer->OnMaxwellBreakPointHit(event, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait until another thread tells us to Resume()
|
|
||||||
resume_from_breakpoint.wait(lock, [&] { return !at_breakpoint; });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebugContext::Resume() {
|
|
||||||
{
|
|
||||||
std::lock_guard lock{breakpoint_mutex};
|
|
||||||
|
|
||||||
// Tell all observers that we are about to resume
|
|
||||||
for (auto& breakpoint_observer : breakpoint_observers) {
|
|
||||||
breakpoint_observer->OnMaxwellResume();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resume the waiting thread (i.e. OnEvent())
|
|
||||||
at_breakpoint = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
resume_from_breakpoint.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Tegra
|
|
|
@ -1,157 +0,0 @@
|
||||||
// Copyright 2014 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <list>
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
namespace Tegra {
|
|
||||||
|
|
||||||
class DebugContext {
|
|
||||||
public:
|
|
||||||
enum class Event {
|
|
||||||
FirstEvent = 0,
|
|
||||||
|
|
||||||
MaxwellCommandLoaded = FirstEvent,
|
|
||||||
MaxwellCommandProcessed,
|
|
||||||
IncomingPrimitiveBatch,
|
|
||||||
FinishedPrimitiveBatch,
|
|
||||||
|
|
||||||
NumEvents
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inherit from this class to be notified of events registered to some debug context.
|
|
||||||
* Most importantly this is used for our debugger GUI.
|
|
||||||
*
|
|
||||||
* To implement event handling, override the OnMaxwellBreakPointHit and OnMaxwellResume methods.
|
|
||||||
* @warning All BreakPointObservers need to be on the same thread to guarantee thread-safe state
|
|
||||||
* access
|
|
||||||
* @todo Evaluate an alternative interface, in which there is only one managing observer and
|
|
||||||
* multiple child observers running (by design) on the same thread.
|
|
||||||
*/
|
|
||||||
class BreakPointObserver {
|
|
||||||
public:
|
|
||||||
/// Constructs the object such that it observes events of the given DebugContext.
|
|
||||||
explicit BreakPointObserver(std::shared_ptr<DebugContext> debug_context)
|
|
||||||
: context_weak(debug_context) {
|
|
||||||
std::unique_lock lock{debug_context->breakpoint_mutex};
|
|
||||||
debug_context->breakpoint_observers.push_back(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~BreakPointObserver() {
|
|
||||||
auto context = context_weak.lock();
|
|
||||||
if (context) {
|
|
||||||
{
|
|
||||||
std::unique_lock lock{context->breakpoint_mutex};
|
|
||||||
context->breakpoint_observers.remove(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are the last observer to be destroyed, tell the debugger context that
|
|
||||||
// it is free to continue. In particular, this is required for a proper yuzu
|
|
||||||
// shutdown, when the emulation thread is waiting at a breakpoint.
|
|
||||||
if (context->breakpoint_observers.empty())
|
|
||||||
context->Resume();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action to perform when a breakpoint was reached.
|
|
||||||
* @param event Type of event which triggered the breakpoint
|
|
||||||
* @param data Optional data pointer (if unused, this is a nullptr)
|
|
||||||
* @note This function will perform nothing unless it is overridden in the child class.
|
|
||||||
*/
|
|
||||||
virtual void OnMaxwellBreakPointHit(Event event, void* data) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action to perform when emulation is resumed from a breakpoint.
|
|
||||||
* @note This function will perform nothing unless it is overridden in the child class.
|
|
||||||
*/
|
|
||||||
virtual void OnMaxwellResume() {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/**
|
|
||||||
* Weak context pointer. This need not be valid, so when requesting a shared_ptr via
|
|
||||||
* context_weak.lock(), always compare the result against nullptr.
|
|
||||||
*/
|
|
||||||
std::weak_ptr<DebugContext> context_weak;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple structure defining a breakpoint state
|
|
||||||
*/
|
|
||||||
struct BreakPoint {
|
|
||||||
bool enabled = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Static constructor used to create a shared_ptr of a DebugContext.
|
|
||||||
*/
|
|
||||||
static std::shared_ptr<DebugContext> Construct() {
|
|
||||||
return std::shared_ptr<DebugContext>(new DebugContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used by the emulation core when a given event has happened. If a breakpoint has been set
|
|
||||||
* for this event, OnEvent calls the event handlers of the registered breakpoint observers.
|
|
||||||
* The current thread then is halted until Resume() is called from another thread (or until
|
|
||||||
* emulation is stopped).
|
|
||||||
* @param event Event which has happened
|
|
||||||
* @param data Optional data pointer (pass nullptr if unused). Needs to remain valid until
|
|
||||||
* Resume() is called.
|
|
||||||
*/
|
|
||||||
void OnEvent(Event event, void* data) {
|
|
||||||
// This check is left in the header to allow the compiler to inline it.
|
|
||||||
if (!breakpoints[(int)event].enabled)
|
|
||||||
return;
|
|
||||||
// For the rest of event handling, call a separate function.
|
|
||||||
DoOnEvent(event, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DoOnEvent(Event event, void* data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resume from the current breakpoint.
|
|
||||||
* @warning Calling this from the same thread that OnEvent was called in will cause a deadlock.
|
|
||||||
* Calling from any other thread is safe.
|
|
||||||
*/
|
|
||||||
void Resume();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete all set breakpoints and resume emulation.
|
|
||||||
*/
|
|
||||||
void ClearBreakpoints() {
|
|
||||||
for (auto& bp : breakpoints) {
|
|
||||||
bp.enabled = false;
|
|
||||||
}
|
|
||||||
Resume();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Evaluate if access to these members should be hidden behind a public interface.
|
|
||||||
std::array<BreakPoint, static_cast<int>(Event::NumEvents)> breakpoints;
|
|
||||||
Event active_breakpoint{};
|
|
||||||
bool at_breakpoint = false;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* Private default constructor to make sure people always construct this through Construct()
|
|
||||||
* instead.
|
|
||||||
*/
|
|
||||||
DebugContext() = default;
|
|
||||||
|
|
||||||
/// Mutex protecting current breakpoint state and the observer list.
|
|
||||||
std::mutex breakpoint_mutex;
|
|
||||||
|
|
||||||
/// Used by OnEvent to wait for resumption.
|
|
||||||
std::condition_variable resume_from_breakpoint;
|
|
||||||
|
|
||||||
/// List of registered observers
|
|
||||||
std::list<BreakPointObserver*> breakpoint_observers;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Tegra
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "video_core/debug_utils/debug_utils.h"
|
|
||||||
#include "video_core/engines/maxwell_3d.h"
|
#include "video_core/engines/maxwell_3d.h"
|
||||||
#include "video_core/engines/shader_type.h"
|
#include "video_core/engines/shader_type.h"
|
||||||
#include "video_core/memory_manager.h"
|
#include "video_core/memory_manager.h"
|
||||||
|
@ -273,8 +272,6 @@ void Maxwell3D::CallMacroMethod(u32 method, std::size_t num_parameters, const u3
|
||||||
}
|
}
|
||||||
|
|
||||||
void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
|
void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
|
||||||
auto debug_context = system.GetGPUDebugContext();
|
|
||||||
|
|
||||||
const u32 method = method_call.method;
|
const u32 method = method_call.method;
|
||||||
|
|
||||||
if (method == cb_data_state.current) {
|
if (method == cb_data_state.current) {
|
||||||
|
@ -315,10 +312,6 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
|
||||||
ASSERT_MSG(method < Regs::NUM_REGS,
|
ASSERT_MSG(method < Regs::NUM_REGS,
|
||||||
"Invalid Maxwell3D register, increase the size of the Regs structure");
|
"Invalid Maxwell3D register, increase the size of the Regs structure");
|
||||||
|
|
||||||
if (debug_context) {
|
|
||||||
debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandLoaded, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (regs.reg_array[method] != method_call.argument) {
|
if (regs.reg_array[method] != method_call.argument) {
|
||||||
regs.reg_array[method] = method_call.argument;
|
regs.reg_array[method] = method_call.argument;
|
||||||
const std::size_t dirty_reg = dirty_pointers[method];
|
const std::size_t dirty_reg = dirty_pointers[method];
|
||||||
|
@ -424,10 +417,6 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug_context) {
|
|
||||||
debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandProcessed, nullptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Maxwell3D::StepInstance(const MMEDrawMode expected_mode, const u32 count) {
|
void Maxwell3D::StepInstance(const MMEDrawMode expected_mode, const u32 count) {
|
||||||
|
@ -485,12 +474,6 @@ void Maxwell3D::FlushMMEInlineDraw() {
|
||||||
ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?");
|
ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?");
|
||||||
ASSERT(mme_draw.instance_count == mme_draw.gl_end_count);
|
ASSERT(mme_draw.instance_count == mme_draw.gl_end_count);
|
||||||
|
|
||||||
auto debug_context = system.GetGPUDebugContext();
|
|
||||||
|
|
||||||
if (debug_context) {
|
|
||||||
debug_context->OnEvent(Tegra::DebugContext::Event::IncomingPrimitiveBatch, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Both instance configuration registers can not be set at the same time.
|
// Both instance configuration registers can not be set at the same time.
|
||||||
ASSERT_MSG(!regs.draw.instance_next || !regs.draw.instance_cont,
|
ASSERT_MSG(!regs.draw.instance_next || !regs.draw.instance_cont,
|
||||||
"Illegal combination of instancing parameters");
|
"Illegal combination of instancing parameters");
|
||||||
|
@ -500,10 +483,6 @@ void Maxwell3D::FlushMMEInlineDraw() {
|
||||||
rasterizer.DrawMultiBatch(is_indexed);
|
rasterizer.DrawMultiBatch(is_indexed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug_context) {
|
|
||||||
debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if
|
// TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if
|
||||||
// the game is trying to draw indexed or direct mode. This needs to be verified on HW still -
|
// the game is trying to draw indexed or direct mode. This needs to be verified on HW still -
|
||||||
// it's possible that it is incorrect and that there is some other register used to specify the
|
// 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() {
|
||||||
regs.vertex_buffer.count);
|
regs.vertex_buffer.count);
|
||||||
ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?");
|
ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?");
|
||||||
|
|
||||||
auto debug_context = system.GetGPUDebugContext();
|
|
||||||
|
|
||||||
if (debug_context) {
|
|
||||||
debug_context->OnEvent(Tegra::DebugContext::Event::IncomingPrimitiveBatch, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Both instance configuration registers can not be set at the same time.
|
// Both instance configuration registers can not be set at the same time.
|
||||||
ASSERT_MSG(!regs.draw.instance_next || !regs.draw.instance_cont,
|
ASSERT_MSG(!regs.draw.instance_next || !regs.draw.instance_cont,
|
||||||
"Illegal combination of instancing parameters");
|
"Illegal combination of instancing parameters");
|
||||||
|
@ -673,10 +646,6 @@ void Maxwell3D::DrawArrays() {
|
||||||
rasterizer.DrawBatch(is_indexed);
|
rasterizer.DrawBatch(is_indexed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug_context) {
|
|
||||||
debug_context->OnEvent(Tegra::DebugContext::Event::FinishedPrimitiveBatch, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if
|
// TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if
|
||||||
// the game is trying to draw indexed or direct mode. This needs to be verified on HW still -
|
// the game is trying to draw indexed or direct mode. This needs to be verified on HW still -
|
||||||
// it's possible that it is incorrect and that there is some other register used to specify the
|
// it's possible that it is incorrect and that there is some other register used to specify the
|
||||||
|
|
|
@ -78,11 +78,6 @@ add_executable(yuzu
|
||||||
configuration/configure_web.cpp
|
configuration/configure_web.cpp
|
||||||
configuration/configure_web.h
|
configuration/configure_web.h
|
||||||
configuration/configure_web.ui
|
configuration/configure_web.ui
|
||||||
debugger/graphics/graphics_breakpoint_observer.cpp
|
|
||||||
debugger/graphics/graphics_breakpoint_observer.h
|
|
||||||
debugger/graphics/graphics_breakpoints.cpp
|
|
||||||
debugger/graphics/graphics_breakpoints.h
|
|
||||||
debugger/graphics/graphics_breakpoints_p.h
|
|
||||||
debugger/console.cpp
|
debugger/console.cpp
|
||||||
debugger/console.h
|
debugger/console.h
|
||||||
debugger/profiler.cpp
|
debugger/profiler.cpp
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
// Copyright 2014 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#include <QMetaType>
|
|
||||||
#include "yuzu/debugger/graphics/graphics_breakpoint_observer.h"
|
|
||||||
|
|
||||||
BreakPointObserverDock::BreakPointObserverDock(std::shared_ptr<Tegra::DebugContext> debug_context,
|
|
||||||
const QString& title, QWidget* parent)
|
|
||||||
: QDockWidget(title, parent), BreakPointObserver(debug_context) {
|
|
||||||
qRegisterMetaType<Tegra::DebugContext::Event>("Tegra::DebugContext::Event");
|
|
||||||
|
|
||||||
connect(this, &BreakPointObserverDock::Resumed, this, &BreakPointObserverDock::OnResumed);
|
|
||||||
|
|
||||||
// NOTE: This signal is emitted from a non-GUI thread, but connect() takes
|
|
||||||
// care of delaying its handling to the GUI thread.
|
|
||||||
connect(this, &BreakPointObserverDock::BreakPointHit, this,
|
|
||||||
&BreakPointObserverDock::OnBreakPointHit, Qt::BlockingQueuedConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BreakPointObserverDock::OnMaxwellBreakPointHit(Tegra::DebugContext::Event event, void* data) {
|
|
||||||
emit BreakPointHit(event, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BreakPointObserverDock::OnMaxwellResume() {
|
|
||||||
emit Resumed();
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
// Copyright 2014 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QDockWidget>
|
|
||||||
#include "video_core/debug_utils/debug_utils.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility class which forwards calls to OnMaxwellBreakPointHit and OnMaxwellResume to public slots.
|
|
||||||
* This is because the Maxwell breakpoint callbacks are called from a non-GUI thread, while
|
|
||||||
* the widget usually wants to perform reactions in the GUI thread.
|
|
||||||
*/
|
|
||||||
class BreakPointObserverDock : public QDockWidget,
|
|
||||||
protected Tegra::DebugContext::BreakPointObserver {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
BreakPointObserverDock(std::shared_ptr<Tegra::DebugContext> debug_context, const QString& title,
|
|
||||||
QWidget* parent = nullptr);
|
|
||||||
|
|
||||||
void OnMaxwellBreakPointHit(Tegra::DebugContext::Event event, void* data) override;
|
|
||||||
void OnMaxwellResume() override;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void Resumed();
|
|
||||||
void BreakPointHit(Tegra::DebugContext::Event event, void* data);
|
|
||||||
|
|
||||||
private:
|
|
||||||
virtual void OnBreakPointHit(Tegra::DebugContext::Event event, void* data) = 0;
|
|
||||||
virtual void OnResumed() = 0;
|
|
||||||
};
|
|
|
@ -1,221 +0,0 @@
|
||||||
// Copyright 2014 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QMetaType>
|
|
||||||
#include <QPushButton>
|
|
||||||
#include <QTreeView>
|
|
||||||
#include <QVBoxLayout>
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "yuzu/debugger/graphics/graphics_breakpoints.h"
|
|
||||||
#include "yuzu/debugger/graphics/graphics_breakpoints_p.h"
|
|
||||||
|
|
||||||
BreakPointModel::BreakPointModel(std::shared_ptr<Tegra::DebugContext> debug_context,
|
|
||||||
QObject* parent)
|
|
||||||
: QAbstractListModel(parent), context_weak(debug_context),
|
|
||||||
at_breakpoint(debug_context->at_breakpoint),
|
|
||||||
active_breakpoint(debug_context->active_breakpoint) {}
|
|
||||||
|
|
||||||
int BreakPointModel::columnCount(const QModelIndex& parent) const {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int BreakPointModel::rowCount(const QModelIndex& parent) const {
|
|
||||||
return static_cast<int>(Tegra::DebugContext::Event::NumEvents);
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant BreakPointModel::data(const QModelIndex& index, int role) const {
|
|
||||||
const auto event = static_cast<Tegra::DebugContext::Event>(index.row());
|
|
||||||
|
|
||||||
switch (role) {
|
|
||||||
case Qt::DisplayRole: {
|
|
||||||
if (index.column() == 0) {
|
|
||||||
return DebugContextEventToString(event);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Qt::CheckStateRole: {
|
|
||||||
if (index.column() == 0)
|
|
||||||
return data(index, Role_IsEnabled).toBool() ? Qt::Checked : Qt::Unchecked;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Qt::BackgroundRole: {
|
|
||||||
if (at_breakpoint && index.row() == static_cast<int>(active_breakpoint)) {
|
|
||||||
return QBrush(QColor(0xE0, 0xE0, 0x10));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Role_IsEnabled: {
|
|
||||||
auto context = context_weak.lock();
|
|
||||||
return context && context->breakpoints[(int)event].enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
Qt::ItemFlags BreakPointModel::flags(const QModelIndex& index) const {
|
|
||||||
if (!index.isValid())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
Qt::ItemFlags flags = Qt::ItemIsEnabled;
|
|
||||||
if (index.column() == 0)
|
|
||||||
flags |= Qt::ItemIsUserCheckable;
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BreakPointModel::setData(const QModelIndex& index, const QVariant& value, int role) {
|
|
||||||
const auto event = static_cast<Tegra::DebugContext::Event>(index.row());
|
|
||||||
|
|
||||||
switch (role) {
|
|
||||||
case Qt::CheckStateRole: {
|
|
||||||
if (index.column() != 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto context = context_weak.lock();
|
|
||||||
if (!context)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
context->breakpoints[(int)event].enabled = value == Qt::Checked;
|
|
||||||
QModelIndex changed_index = createIndex(index.row(), 0);
|
|
||||||
emit dataChanged(changed_index, changed_index);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BreakPointModel::OnBreakPointHit(Tegra::DebugContext::Event event) {
|
|
||||||
auto context = context_weak.lock();
|
|
||||||
if (!context)
|
|
||||||
return;
|
|
||||||
|
|
||||||
active_breakpoint = context->active_breakpoint;
|
|
||||||
at_breakpoint = context->at_breakpoint;
|
|
||||||
emit dataChanged(createIndex(static_cast<int>(event), 0),
|
|
||||||
createIndex(static_cast<int>(event), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
void BreakPointModel::OnResumed() {
|
|
||||||
auto context = context_weak.lock();
|
|
||||||
if (!context)
|
|
||||||
return;
|
|
||||||
|
|
||||||
at_breakpoint = context->at_breakpoint;
|
|
||||||
emit dataChanged(createIndex(static_cast<int>(active_breakpoint), 0),
|
|
||||||
createIndex(static_cast<int>(active_breakpoint), 0));
|
|
||||||
active_breakpoint = context->active_breakpoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString BreakPointModel::DebugContextEventToString(Tegra::DebugContext::Event event) {
|
|
||||||
switch (event) {
|
|
||||||
case Tegra::DebugContext::Event::MaxwellCommandLoaded:
|
|
||||||
return tr("Maxwell command loaded");
|
|
||||||
case Tegra::DebugContext::Event::MaxwellCommandProcessed:
|
|
||||||
return tr("Maxwell command processed");
|
|
||||||
case Tegra::DebugContext::Event::IncomingPrimitiveBatch:
|
|
||||||
return tr("Incoming primitive batch");
|
|
||||||
case Tegra::DebugContext::Event::FinishedPrimitiveBatch:
|
|
||||||
return tr("Finished primitive batch");
|
|
||||||
case Tegra::DebugContext::Event::NumEvents:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tr("Unknown debug context event");
|
|
||||||
}
|
|
||||||
|
|
||||||
GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(
|
|
||||||
std::shared_ptr<Tegra::DebugContext> debug_context, QWidget* parent)
|
|
||||||
: QDockWidget(tr("Maxwell Breakpoints"), parent), Tegra::DebugContext::BreakPointObserver(
|
|
||||||
debug_context) {
|
|
||||||
setObjectName(QStringLiteral("TegraBreakPointsWidget"));
|
|
||||||
|
|
||||||
status_text = new QLabel(tr("Emulation running"));
|
|
||||||
resume_button = new QPushButton(tr("Resume"));
|
|
||||||
resume_button->setEnabled(false);
|
|
||||||
|
|
||||||
breakpoint_model = new BreakPointModel(debug_context, this);
|
|
||||||
breakpoint_list = new QTreeView;
|
|
||||||
breakpoint_list->setRootIsDecorated(false);
|
|
||||||
breakpoint_list->setHeaderHidden(true);
|
|
||||||
breakpoint_list->setModel(breakpoint_model);
|
|
||||||
|
|
||||||
qRegisterMetaType<Tegra::DebugContext::Event>("Tegra::DebugContext::Event");
|
|
||||||
|
|
||||||
connect(breakpoint_list, &QTreeView::doubleClicked, this,
|
|
||||||
&GraphicsBreakPointsWidget::OnItemDoubleClicked);
|
|
||||||
|
|
||||||
connect(resume_button, &QPushButton::clicked, this,
|
|
||||||
&GraphicsBreakPointsWidget::OnResumeRequested);
|
|
||||||
|
|
||||||
connect(this, &GraphicsBreakPointsWidget::BreakPointHit, this,
|
|
||||||
&GraphicsBreakPointsWidget::OnBreakPointHit, Qt::BlockingQueuedConnection);
|
|
||||||
connect(this, &GraphicsBreakPointsWidget::Resumed, this, &GraphicsBreakPointsWidget::OnResumed);
|
|
||||||
|
|
||||||
connect(this, &GraphicsBreakPointsWidget::BreakPointHit, breakpoint_model,
|
|
||||||
&BreakPointModel::OnBreakPointHit, Qt::BlockingQueuedConnection);
|
|
||||||
connect(this, &GraphicsBreakPointsWidget::Resumed, breakpoint_model,
|
|
||||||
&BreakPointModel::OnResumed);
|
|
||||||
|
|
||||||
connect(this, &GraphicsBreakPointsWidget::BreakPointsChanged,
|
|
||||||
[this](const QModelIndex& top_left, const QModelIndex& bottom_right) {
|
|
||||||
breakpoint_model->dataChanged(top_left, bottom_right);
|
|
||||||
});
|
|
||||||
|
|
||||||
QWidget* main_widget = new QWidget;
|
|
||||||
auto main_layout = new QVBoxLayout;
|
|
||||||
{
|
|
||||||
auto sub_layout = new QHBoxLayout;
|
|
||||||
sub_layout->addWidget(status_text);
|
|
||||||
sub_layout->addWidget(resume_button);
|
|
||||||
main_layout->addLayout(sub_layout);
|
|
||||||
}
|
|
||||||
main_layout->addWidget(breakpoint_list);
|
|
||||||
main_widget->setLayout(main_layout);
|
|
||||||
|
|
||||||
setWidget(main_widget);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GraphicsBreakPointsWidget::OnMaxwellBreakPointHit(Event event, void* data) {
|
|
||||||
// Process in GUI thread
|
|
||||||
emit BreakPointHit(event, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GraphicsBreakPointsWidget::OnBreakPointHit(Tegra::DebugContext::Event event, void* data) {
|
|
||||||
status_text->setText(tr("Emulation halted at breakpoint"));
|
|
||||||
resume_button->setEnabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GraphicsBreakPointsWidget::OnMaxwellResume() {
|
|
||||||
// Process in GUI thread
|
|
||||||
emit Resumed();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GraphicsBreakPointsWidget::OnResumed() {
|
|
||||||
status_text->setText(tr("Emulation running"));
|
|
||||||
resume_button->setEnabled(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GraphicsBreakPointsWidget::OnResumeRequested() {
|
|
||||||
if (auto context = context_weak.lock())
|
|
||||||
context->Resume();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GraphicsBreakPointsWidget::OnItemDoubleClicked(const QModelIndex& index) {
|
|
||||||
if (!index.isValid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QModelIndex check_index = breakpoint_list->model()->index(index.row(), 0);
|
|
||||||
QVariant enabled = breakpoint_list->model()->data(check_index, Qt::CheckStateRole);
|
|
||||||
QVariant new_state = Qt::Unchecked;
|
|
||||||
if (enabled == Qt::Unchecked)
|
|
||||||
new_state = Qt::Checked;
|
|
||||||
breakpoint_list->model()->setData(check_index, new_state, Qt::CheckStateRole);
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
// Copyright 2014 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <QDockWidget>
|
|
||||||
#include "video_core/debug_utils/debug_utils.h"
|
|
||||||
|
|
||||||
class QLabel;
|
|
||||||
class QPushButton;
|
|
||||||
class QTreeView;
|
|
||||||
|
|
||||||
class BreakPointModel;
|
|
||||||
|
|
||||||
class GraphicsBreakPointsWidget : public QDockWidget, Tegra::DebugContext::BreakPointObserver {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
using Event = Tegra::DebugContext::Event;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit GraphicsBreakPointsWidget(std::shared_ptr<Tegra::DebugContext> debug_context,
|
|
||||||
QWidget* parent = nullptr);
|
|
||||||
|
|
||||||
void OnMaxwellBreakPointHit(Tegra::DebugContext::Event event, void* data) override;
|
|
||||||
void OnMaxwellResume() override;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void Resumed();
|
|
||||||
void BreakPointHit(Tegra::DebugContext::Event event, void* data);
|
|
||||||
void BreakPointsChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void OnBreakPointHit(Tegra::DebugContext::Event event, void* data);
|
|
||||||
void OnItemDoubleClicked(const QModelIndex&);
|
|
||||||
void OnResumeRequested();
|
|
||||||
void OnResumed();
|
|
||||||
|
|
||||||
QLabel* status_text;
|
|
||||||
QPushButton* resume_button;
|
|
||||||
|
|
||||||
BreakPointModel* breakpoint_model;
|
|
||||||
QTreeView* breakpoint_list;
|
|
||||||
};
|
|
|
@ -1,37 +0,0 @@
|
||||||
// Copyright 2014 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <QAbstractListModel>
|
|
||||||
#include "video_core/debug_utils/debug_utils.h"
|
|
||||||
|
|
||||||
class BreakPointModel : public QAbstractListModel {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum {
|
|
||||||
Role_IsEnabled = Qt::UserRole,
|
|
||||||
};
|
|
||||||
|
|
||||||
BreakPointModel(std::shared_ptr<Tegra::DebugContext> context, QObject* parent);
|
|
||||||
|
|
||||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
|
||||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
|
||||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
|
||||||
Qt::ItemFlags flags(const QModelIndex& index) const override;
|
|
||||||
|
|
||||||
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
|
|
||||||
|
|
||||||
void OnBreakPointHit(Tegra::DebugContext::Event event);
|
|
||||||
void OnResumed();
|
|
||||||
|
|
||||||
private:
|
|
||||||
static QString DebugContextEventToString(Tegra::DebugContext::Event event);
|
|
||||||
|
|
||||||
std::weak_ptr<Tegra::DebugContext> context_weak;
|
|
||||||
bool at_breakpoint;
|
|
||||||
Tegra::DebugContext::Event active_breakpoint;
|
|
||||||
};
|
|
|
@ -93,7 +93,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
|
||||||
#include "core/perf_stats.h"
|
#include "core/perf_stats.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "core/telemetry_session.h"
|
#include "core/telemetry_session.h"
|
||||||
#include "video_core/debug_utils/debug_utils.h"
|
|
||||||
#include "yuzu/about_dialog.h"
|
#include "yuzu/about_dialog.h"
|
||||||
#include "yuzu/bootmanager.h"
|
#include "yuzu/bootmanager.h"
|
||||||
#include "yuzu/compatdb.h"
|
#include "yuzu/compatdb.h"
|
||||||
|
@ -101,7 +100,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
|
||||||
#include "yuzu/configuration/config.h"
|
#include "yuzu/configuration/config.h"
|
||||||
#include "yuzu/configuration/configure_dialog.h"
|
#include "yuzu/configuration/configure_dialog.h"
|
||||||
#include "yuzu/debugger/console.h"
|
#include "yuzu/debugger/console.h"
|
||||||
#include "yuzu/debugger/graphics/graphics_breakpoints.h"
|
|
||||||
#include "yuzu/debugger/profiler.h"
|
#include "yuzu/debugger/profiler.h"
|
||||||
#include "yuzu/debugger/wait_tree.h"
|
#include "yuzu/debugger/wait_tree.h"
|
||||||
#include "yuzu/discord.h"
|
#include "yuzu/discord.h"
|
||||||
|
@ -187,8 +185,6 @@ GMainWindow::GMainWindow()
|
||||||
provider(std::make_unique<FileSys::ManualContentProvider>()) {
|
provider(std::make_unique<FileSys::ManualContentProvider>()) {
|
||||||
InitializeLogging();
|
InitializeLogging();
|
||||||
|
|
||||||
debug_context = Tegra::DebugContext::Construct();
|
|
||||||
|
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
ui.setupUi(this);
|
ui.setupUi(this);
|
||||||
statusBar()->hide();
|
statusBar()->hide();
|
||||||
|
@ -495,11 +491,6 @@ void GMainWindow::InitializeDebugWidgets() {
|
||||||
debug_menu->addAction(microProfileDialog->toggleViewAction());
|
debug_menu->addAction(microProfileDialog->toggleViewAction());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
graphicsBreakpointsWidget = new GraphicsBreakPointsWidget(debug_context, this);
|
|
||||||
addDockWidget(Qt::RightDockWidgetArea, graphicsBreakpointsWidget);
|
|
||||||
graphicsBreakpointsWidget->hide();
|
|
||||||
debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction());
|
|
||||||
|
|
||||||
waitTreeWidget = new WaitTreeWidget(this);
|
waitTreeWidget = new WaitTreeWidget(this);
|
||||||
addDockWidget(Qt::LeftDockWidgetArea, waitTreeWidget);
|
addDockWidget(Qt::LeftDockWidgetArea, waitTreeWidget);
|
||||||
waitTreeWidget->hide();
|
waitTreeWidget->hide();
|
||||||
|
@ -869,8 +860,6 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
||||||
Core::System& system{Core::System::GetInstance()};
|
Core::System& system{Core::System::GetInstance()};
|
||||||
system.SetFilesystem(vfs);
|
system.SetFilesystem(vfs);
|
||||||
|
|
||||||
system.SetGPUDebugContext(debug_context);
|
|
||||||
|
|
||||||
system.SetAppletFrontendSet({
|
system.SetAppletFrontendSet({
|
||||||
nullptr, // Parental Controls
|
nullptr, // Parental Controls
|
||||||
std::make_unique<QtErrorDisplay>(*this), //
|
std::make_unique<QtErrorDisplay>(*this), //
|
||||||
|
|
|
@ -22,7 +22,6 @@ class Config;
|
||||||
class EmuThread;
|
class EmuThread;
|
||||||
class GameList;
|
class GameList;
|
||||||
class GImageInfo;
|
class GImageInfo;
|
||||||
class GraphicsBreakPointsWidget;
|
|
||||||
class GRenderWindow;
|
class GRenderWindow;
|
||||||
class LoadingScreen;
|
class LoadingScreen;
|
||||||
class MicroProfileDialog;
|
class MicroProfileDialog;
|
||||||
|
@ -42,10 +41,6 @@ class ManualContentProvider;
|
||||||
class VfsFilesystem;
|
class VfsFilesystem;
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|
||||||
namespace Tegra {
|
|
||||||
class DebugContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class EmulatedDirectoryTarget {
|
enum class EmulatedDirectoryTarget {
|
||||||
NAND,
|
NAND,
|
||||||
SDMC,
|
SDMC,
|
||||||
|
@ -223,8 +218,6 @@ private:
|
||||||
|
|
||||||
Ui::MainWindow ui;
|
Ui::MainWindow ui;
|
||||||
|
|
||||||
std::shared_ptr<Tegra::DebugContext> debug_context;
|
|
||||||
|
|
||||||
GRenderWindow* render_window;
|
GRenderWindow* render_window;
|
||||||
GameList* game_list;
|
GameList* game_list;
|
||||||
LoadingScreen* loading_screen;
|
LoadingScreen* loading_screen;
|
||||||
|
@ -255,7 +248,6 @@ private:
|
||||||
// Debugger panes
|
// Debugger panes
|
||||||
ProfilerWidget* profilerWidget;
|
ProfilerWidget* profilerWidget;
|
||||||
MicroProfileDialog* microProfileDialog;
|
MicroProfileDialog* microProfileDialog;
|
||||||
GraphicsBreakPointsWidget* graphicsBreakpointsWidget;
|
|
||||||
WaitTreeWidget* waitTreeWidget;
|
WaitTreeWidget* waitTreeWidget;
|
||||||
|
|
||||||
QAction* actions_recent_files[max_recent_files_item];
|
QAction* actions_recent_files[max_recent_files_item];
|
||||||
|
|
Loading…
Reference in a new issue