Compare commits

...

2 Commits

Author SHA1 Message Date
ReinUsesLisp
dca38b7b8d qt: Add a shader tools dialog with a viewer and editor 2018-11-19 21:28:01 -03:00
ReinUsesLisp
b3254df4ec video_core: Expose shader query and injection 2018-11-19 21:28:01 -03:00
18 changed files with 556 additions and 14 deletions

View File

@@ -55,6 +55,7 @@ add_library(video_core STATIC
renderer_opengl/renderer_opengl.h
renderer_opengl/utils.cpp
renderer_opengl/utils.h
shader_info.h
surface.cpp
surface.h
textures/astc.cpp

View File

@@ -459,6 +459,14 @@ Texture::FullTextureInfo Maxwell3D::GetStageTexture(Regs::ShaderStage stage,
return tex_info;
}
std::vector<VideoCore::ShaderInfo> Maxwell3D::GetShaderList() const {
return rasterizer.GetShaderList();
}
void Maxwell3D::InjectShader(Tegra::GPUVAddr addr, std::size_t code_size, const u8* code) {
rasterizer.InjectShader(addr, code_size, code);
}
u32 Maxwell3D::GetRegisterValue(u32 method) const {
ASSERT_MSG(method < Regs::NUM_REGS, "Invalid Maxwell3D register");
return regs.reg_array[method];

View File

@@ -15,6 +15,7 @@
#include "video_core/gpu.h"
#include "video_core/macro_interpreter.h"
#include "video_core/memory_manager.h"
#include "video_core/shader_info.h"
#include "video_core/textures/texture.h"
namespace VideoCore {
@@ -1044,6 +1045,17 @@ public:
/// Returns the texture information for a specific texture in a specific shader stage.
Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, std::size_t offset) const;
/// Returns a list including all shaders. Use for debugging purposes.
std::vector<VideoCore::ShaderInfo> GetShaderList() const;
/**
* Injects a new shader source. Use for debugging purposes
* @param addr GPU address where the shader is
* @param size Size of the injected code
* @param code Injected code compatible with rasterizer shading language
*/
void InjectShader(Tegra::GPUVAddr addr, std::size_t code_size, const u8* code);
/// Memory for macro code - it's undetermined how big this is, however 1MB is much larger than
/// we've seen used.
using MacroMemory = std::array<u32, 0x40000>;

View File

@@ -129,6 +129,17 @@ protected:
return ++modified_ticks;
}
/// Returns a list of current objects
std::set<T> GetObjects() const {
std::set<T> objects;
for (const auto& pair : interval_cache) {
for (const auto& cached_object : pair.second) {
objects.insert(cached_object);
}
}
return objects;
}
private:
/// Returns a list of cached objects from the specified memory region, ordered by access time
std::vector<T> GetSortedObjectsFromRegion(VAddr addr, u64 size) {

View File

@@ -4,10 +4,12 @@
#pragma once
#include <vector>
#include "common/common_types.h"
#include "video_core/engines/fermi_2d.h"
#include "video_core/gpu.h"
#include "video_core/memory_manager.h"
#include "video_core/shader_info.h"
namespace VideoCore {
@@ -57,5 +59,13 @@ public:
/// Increase/decrease the number of object in pages touching the specified region
virtual void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) {}
/// Returns a list including all shaders
virtual std::vector<VideoCore::ShaderInfo> GetShaderList() const {
return {};
}
/// Injects a new shader source
virtual void InjectShader(Tegra::GPUVAddr addr, std::size_t code_size, const u8* code) {}
};
} // namespace VideoCore

View File

@@ -373,6 +373,14 @@ bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) {
return true;
}
std::vector<VideoCore::ShaderInfo> RasterizerOpenGL::GetShaderList() const {
return shader_cache.GetShaderInfo();
}
void RasterizerOpenGL::InjectShader(Tegra::GPUVAddr addr, std::size_t code_size, const u8* code) {
shader_cache.InjectShader(addr, code_size, code);
}
template <typename Map, typename Interval>
static constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
return boost::make_iterator_range(map.equal_range(interval));

View File

@@ -59,6 +59,8 @@ public:
u32 pixel_stride) override;
bool AccelerateDrawBatch(bool is_indexed) override;
void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) override;
std::vector<VideoCore::ShaderInfo> GetShaderList() const override;
void InjectShader(Tegra::GPUVAddr addr, std::size_t code_size, const u8* code);
/// OpenGL shader generated for a given Maxwell register state
struct MaxwellShader {

View File

@@ -10,6 +10,8 @@
#include "video_core/renderer_opengl/gl_shader_cache.h"
#include "video_core/renderer_opengl/gl_shader_manager.h"
#include "video_core/renderer_opengl/utils.h"
#include "video_core/shader_info.h"
#include "video_core/utils.h"
namespace OpenGL {
@@ -57,7 +59,6 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
: addr{addr}, program_type{program_type}, setup{GetShaderCode(addr)} {
GLShader::ProgramResult program_result;
GLenum gl_type{};
switch (program_type) {
case Maxwell::ShaderProgram::VertexA:
@@ -83,18 +84,10 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
return;
}
code = program_result.first;
entries = program_result.second;
if (program_type != Maxwell::ShaderProgram::Geometry) {
OGLShader shader;
shader.Create(program_result.first.c_str(), gl_type);
program.Create(true, shader.handle);
SetShaderUniformBlockBindings(program.handle);
LabelGLObject(GL_PROGRAM, program.handle, addr);
} else {
// Store shader's code to lazily build it on draw
geometry_programs.code = program_result.first;
}
BuildProgram();
}
GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) {
@@ -120,6 +113,26 @@ GLint CachedShader::GetUniformLocation(const GLShader::SamplerEntry& sampler) {
return search->second;
}
void CachedShader::BuildProgram() {
resource_cache.clear();
uniform_cache.clear();
rebuild = false;
// Geometry shaders just have to be invalidated, they'll get lazily built later
if (program_type == Maxwell::ShaderProgram::Geometry) {
geometry_programs.Release();
return;
}
program.Release();
OGLShader shader;
shader.Create(code.c_str(), gl_type);
program.Create(true, shader.handle);
SetShaderUniformBlockBindings(program.handle);
LabelGLObject(GL_PROGRAM, program.handle, addr);
}
GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program,
const std::string& glsl_topology, u32 max_vertices,
const std::string& debug_name) {
@@ -129,7 +142,7 @@ GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program,
std::string source = "#version 430 core\n";
source += "layout (" + glsl_topology + ") in;\n";
source += "#define MAX_VERTEX_INPUT " + std::to_string(max_vertices) + '\n';
source += geometry_programs.code;
source += code;
OGLShader shader;
shader.Create(source.c_str(), GL_GEOMETRY_SHADER);
@@ -139,6 +152,37 @@ GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program,
return target_program.handle;
};
VideoCore::ShaderInfo CachedShader::GetShaderInfo() const {
VideoCore::ShaderInfo shader_info;
shader_info.addr = static_cast<u64>(addr);
shader_info.stage = [=]() {
switch (program_type) {
case Maxwell::ShaderProgram::VertexA:
case Maxwell::ShaderProgram::VertexB:
return VideoCore::ShaderStage::Vertex;
case Maxwell::ShaderProgram::TesselationControl:
return VideoCore::ShaderStage::TesselationControl;
case Maxwell::ShaderProgram::TesselationEval:
return VideoCore::ShaderStage::TesselationEval;
case Maxwell::ShaderProgram::Geometry:
return VideoCore::ShaderStage::Geometry;
case Maxwell::ShaderProgram::Fragment:
return VideoCore::ShaderStage::Fragment;
default:
return VideoCore::ShaderStage::Invalid;
}
}();
shader_info.code = code;
return shader_info;
}
void CachedShader::InjectGLSL(std::size_t code_size, const GLchar* inject_code) {
LOG_INFO(Render_OpenGL, "Injecting GLSL");
code = std::string(inject_code, code_size);
rebuild = true;
}
ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer) : RasterizerCache{rasterizer} {}
Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) {
@@ -156,4 +200,17 @@ Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) {
return shader;
}
std::vector<VideoCore::ShaderInfo> ShaderCacheOpenGL::GetShaderInfo() const {
std::vector<VideoCore::ShaderInfo> info;
for (const auto& shader : GetObjects()) {
info.push_back(shader->GetShaderInfo());
}
return info;
}
void ShaderCacheOpenGL::InjectShader(Tegra::GPUVAddr addr, std::size_t code_size, const u8* code) {
if (Shader shader{TryGet(addr)}; shader) {
shader->InjectGLSL(code_size, reinterpret_cast<const GLchar*>(code));
}
}
} // namespace OpenGL

View File

@@ -6,12 +6,15 @@
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/rasterizer_cache.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_shader_gen.h"
#include "video_core/shader_info.h"
namespace OpenGL {
@@ -43,6 +46,9 @@ public:
/// Gets the GL program handle for the shader
GLuint GetProgramHandle(GLenum primitive_mode) {
if (rebuild) {
BuildProgram();
}
if (program_type != Maxwell::ShaderProgram::Geometry) {
return program.handle;
}
@@ -76,7 +82,16 @@ public:
/// Gets the GL uniform location for the specified resource, caching as needed
GLint GetUniformLocation(const GLShader::SamplerEntry& sampler);
/// Gets shader info for debugging purposes
VideoCore::ShaderInfo GetShaderInfo() const;
/// Inject GLSL for debugging purposes
void InjectGLSL(std::size_t code_size, const GLchar* inject_code);
private:
/// Builds programs from current set code.
void BuildProgram();
/// Generates a geometry shader or returns one that already exists.
GLuint LazyGeometryProgram(OGLProgram& target_program, const std::string& glsl_topology,
u32 max_vertices, const std::string& debug_name);
@@ -86,6 +101,10 @@ private:
GLShader::ShaderSetup setup;
GLShader::ShaderEntries entries;
GLenum gl_type{};
std::string code;
bool rebuild{};
// Non-geometry program.
OGLProgram program;
@@ -93,12 +112,19 @@ private:
// declared by the hardware. Workaround this issue by generating a different shader per input
// topology class.
struct {
std::string code;
OGLProgram points;
OGLProgram lines;
OGLProgram lines_adjacency;
OGLProgram triangles;
OGLProgram triangles_adjacency;
void Release() {
points.Release();
lines.Release();
lines_adjacency.Release();
triangles.Release();
triangles_adjacency.Release();
}
} geometry_programs;
std::map<u32, GLuint> resource_cache;
@@ -111,6 +137,12 @@ public:
/// Gets the current specified shader stage program
Shader GetStageProgram(Maxwell::ShaderProgram program);
/// Gets shader info for debugging purposes
std::vector<VideoCore::ShaderInfo> GetShaderInfo() const;
/// Injects shader code for debugging purposes
void InjectShader(Tegra::GPUVAddr addr, std::size_t code_size, const u8* code);
};
} // namespace OpenGL

View File

@@ -63,7 +63,7 @@ GLuint LoadProgram(bool separable_program, T... shaders) {
// Check the program
GLint result = GL_FALSE;
GLint info_log_length;
GLint info_log_length{};
glGetProgramiv(program_id, GL_LINK_STATUS, &result);
glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length);

View File

@@ -0,0 +1,29 @@
// Copyright 2018 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <string>
#include "common/common_types.h"
namespace VideoCore {
enum class ShaderStage {
Vertex,
TesselationControl,
TesselationEval,
Geometry,
Fragment,
Compute,
Invalid,
};
struct ShaderInfo {
u64 addr;
ShaderStage stage;
std::string code;
};
} // namespace VideoCore

View File

@@ -48,6 +48,8 @@ add_executable(yuzu
debugger/console.h
debugger/profiler.cpp
debugger/profiler.h
debugger/shader_tools.cpp
debugger/shader_tools.h
debugger/wait_tree.cpp
debugger/wait_tree.h
discord.h

View File

@@ -467,6 +467,9 @@ void Config::ReadValues() {
qt_config->value("microProfileDialogGeometry").toByteArray();
UISettings::values.microprofile_visible =
qt_config->value("microProfileDialogVisible", false).toBool();
UISettings::values.shader_tools_geometry =
qt_config->value("shaderToolsDialogGeometry").toByteArray();
UISettings::values.shader_tools_visible = qt_config->value("shaderToolsDialogVisible").toBool();
qt_config->endGroup();
qt_config->beginGroup("Paths");
@@ -667,6 +670,8 @@ void Config::SaveValues() {
qt_config->setValue("gameListHeaderState", UISettings::values.gamelist_header_state);
qt_config->setValue("microProfileDialogGeometry", UISettings::values.microprofile_geometry);
qt_config->setValue("microProfileDialogVisible", UISettings::values.microprofile_visible);
qt_config->setValue("shaderToolsDialogGeometry", UISettings::values.shader_tools_geometry);
qt_config->setValue("shaderToolsDialogVisible", UISettings::values.shader_tools_visible);
qt_config->endGroup();
qt_config->beginGroup("Paths");

View File

@@ -0,0 +1,261 @@
// Copyright 2018 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <QAction>
#include <QFontDatabase>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QMessageBox>
#include <QScrollBar>
#include <QStandardItemModel>
#include <QTextEdit>
#include <QTreeView>
#include "core/core.h"
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/gpu.h"
#include "yuzu/debugger/shader_tools.h"
ShaderToolsDialog::ShaderToolsDialog(std::shared_ptr<Tegra::DebugContext> debug_context,
QWidget* parent)
: context(debug_context),
QWidget(parent, Qt::Dialog), Tegra::DebugContext::BreakPointObserver(debug_context) {
setObjectName("ShaderTools");
setWindowTitle(tr("Shader Tools"));
resize(1024, 600);
setWindowFlags(windowFlags() | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint);
layout = new QHBoxLayout;
item_model = new QStandardItemModel;
tree_view = new QTreeView;
code_editor = new QTextEdit;
tree_view->setAlternatingRowColors(true);
tree_view->setSelectionMode(QHeaderView::SingleSelection);
tree_view->setSelectionBehavior(QHeaderView::SelectRows);
tree_view->setVerticalScrollMode(QHeaderView::ScrollPerPixel);
tree_view->setHorizontalScrollMode(QHeaderView::ScrollPerPixel);
tree_view->setSortingEnabled(true);
tree_view->setEditTriggers(QHeaderView::NoEditTriggers);
tree_view->setUniformRowHeights(true);
tree_view->setContextMenuPolicy(Qt::CustomContextMenu);
tree_view->setModel(item_model);
connect(tree_view, &QAbstractItemView::activated, this, &ShaderToolsDialog::onSelectionChanged);
item_model->insertColumns(0, COLUMN_COUNT);
item_model->setHeaderData(COLUMN_STAGE, Qt::Horizontal, tr("Stage"));
item_model->setHeaderData(COLUMN_ADDRESS, Qt::Horizontal, tr("Address"));
const QFont fixed_font = QFontDatabase::systemFont(QFontDatabase::FixedFont);
code_editor->setFont(fixed_font);
connect(this, &ShaderToolsDialog::BreakPointHit, this, &ShaderToolsDialog::OnBreakPointHit,
Qt::BlockingQueuedConnection);
connect(this, &ShaderToolsDialog::Resumed, this, &ShaderToolsDialog::OnResumed);
layout->addWidget(code_editor);
layout->addWidget(tree_view);
layout->setStretchFactor(code_editor, 1);
setLayout(layout);
DisableEditor();
}
void ShaderToolsDialog::OnMaxwellBreakPointHit(Tegra::DebugContext::Event event, void* data) {
emit BreakPointHit(event, data);
}
void ShaderToolsDialog::OnMaxwellResume() {
emit Resumed();
}
void ShaderToolsDialog::OnBreakPointHit(Tegra::DebugContext::Event event, void* data) {
auto& gpu = Core::System::GetInstance().GPU();
shaders = gpu.Maxwell3D().GetShaderList();
modified_shaders.resize(shaders.size());
if (shaders.empty()) {
return;
}
RemoveShaderList();
for (const auto& shader : shaders) {
QList<QStandardItem*> items;
items.append(new QStandardItem(GetShaderStageName(shader.stage)));
items.append(new QStandardItem(fmt::format("0x{:08x}", shader.addr).c_str()));
item_model->appendRow(items);
}
RestoreSelectedShader();
}
void ShaderToolsDialog::OnResumed() {
SaveActiveCode();
SaveScrollPosition();
SaveSelectedShader();
active_shader = {};
auto& gpu = Core::System::GetInstance().GPU();
for (std::size_t i = 0; i < shaders.size(); ++i) {
if (!modified_shaders[i]) {
continue;
}
const auto& shader = shaders[i];
const auto* code = shader.code.c_str();
gpu.Maxwell3D().InjectShader(shader.addr, shader.code.size(),
reinterpret_cast<const u8*>(code));
}
RemoveShaderList();
DisableEditor();
}
QAction* ShaderToolsDialog::toggleViewAction() {
if (toggle_view_action != nullptr) {
return toggle_view_action;
}
toggle_view_action = new QAction(windowTitle(), this);
toggle_view_action->setCheckable(true);
toggle_view_action->setChecked(isVisible());
connect(toggle_view_action, &QAction::toggled, this, &ShaderToolsDialog::setVisible);
return toggle_view_action;
}
void ShaderToolsDialog::showEvent(QShowEvent* ev) {
if (toggle_view_action) {
toggle_view_action->setChecked(isVisible());
}
QWidget::showEvent(ev);
}
void ShaderToolsDialog::hideEvent(QHideEvent* ev) {
if (toggle_view_action) {
toggle_view_action->setChecked(isVisible());
}
QWidget::hideEvent(ev);
}
void ShaderToolsDialog::onSelectionChanged() {
SaveActiveCode();
SaveScrollPosition();
SelectShader(tree_view->currentIndex().row());
RestoreScrollPosition();
}
void ShaderToolsDialog::SelectShader(int index) {
active_shader = std::make_optional(index);
if (static_cast<std::size_t>(*active_shader) >= shaders.size()) {
QMessageBox message_box;
message_box.setWindowTitle(tr("Shader Tools"));
message_box.setText(tr("Tried to select an out of bounds shader"));
message_box.setIcon(QMessageBox::Critical);
message_box.exec();
return;
}
auto& shader = shaders[*active_shader];
code_editor->setText(shader.code.c_str());
EnableEditor();
RestoreScrollPosition();
}
void ShaderToolsDialog::DisableEditor() {
code_editor->setText("");
code_editor->setDisabled(true);
}
void ShaderToolsDialog::EnableEditor() {
code_editor->setDisabled(false);
}
void ShaderToolsDialog::RemoveShaderList() {
item_model->removeRows(0, item_model->rowCount());
}
const char* ShaderToolsDialog::GetActiveCode() const {
return code_editor->toPlainText().toUtf8().constData();
}
void ShaderToolsDialog::SaveActiveCode() {
if (!active_shader) {
return;
}
auto& shader = shaders[*active_shader];
const std::string new_code = GetActiveCode();
if (shader.code != new_code) {
shader.code = GetActiveCode();
modified_shaders[*active_shader] = true;
}
}
void ShaderToolsDialog::SaveScrollPosition() {
if (!active_shader) {
return;
}
auto& shader = shaders[*active_shader];
const int scroll_pos = code_editor->verticalScrollBar()->value();
scroll_map.insert_or_assign(shader.addr, scroll_pos);
}
void ShaderToolsDialog::RestoreScrollPosition() {
if (!active_shader) {
return;
}
auto& shader = shaders[*active_shader];
if (const auto it = scroll_map.find(shader.addr); it != scroll_map.end()) {
const int scroll_pos = it->second;
code_editor->verticalScrollBar()->setValue(scroll_pos);
}
}
void ShaderToolsDialog::SaveSelectedShader() {
if (!active_shader) {
return;
}
auto& shader = shaders[*active_shader];
last_shader = std::make_optional(shader.addr);
}
void ShaderToolsDialog::RestoreSelectedShader() {
if (!last_shader) {
return;
}
const auto it =
std::find_if(shaders.begin(), shaders.end(), [&](const VideoCore::ShaderInfo& shader) {
return shader.addr == *last_shader;
});
if (it == shaders.end())
return;
const auto index = static_cast<int>(std::distance(shaders.begin(), it));
tree_view->setCurrentIndex(item_model->index(index, 0));
SelectShader(index);
}
QString ShaderToolsDialog::GetShaderStageName(VideoCore::ShaderStage stage) {
switch (stage) {
case VideoCore::ShaderStage::Vertex:
return tr("Vertex");
case VideoCore::ShaderStage::TesselationControl:
return tr("Hull");
case VideoCore::ShaderStage::TesselationEval:
return tr("Domain");
case VideoCore::ShaderStage::Geometry:
return tr("Geometry");
case VideoCore::ShaderStage::Fragment:
return tr("Pixel");
case VideoCore::ShaderStage::Compute:
return tr("Compute");
default:
return tr("Invalid");
}
}

View File

@@ -0,0 +1,89 @@
// Copyright 2018 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <map>
#include <memory>
#include <optional>
#include <vector>
#include <QWidget>
#include "common/common_types.h"
#include "video_core/shader_info.h"
class QHBoxLayout;
class QStandardItemModel;
class QTreeView;
class QTextEdit;
class ShaderToolsDialog : public QWidget, Tegra::DebugContext::BreakPointObserver {
Q_OBJECT
public:
enum {
COLUMN_STAGE,
COLUMN_ADDRESS,
COLUMN_COUNT,
};
explicit ShaderToolsDialog(std::shared_ptr<Tegra::DebugContext> debug_context,
QWidget* parent = nullptr);
void OnMaxwellBreakPointHit(Tegra::DebugContext::Event event, void* data) override;
void OnMaxwellResume() override;
/// Returns a QAction that can be used to toggle visibility of this dialog.
QAction* toggleViewAction();
signals:
void BreakPointHit(Tegra::DebugContext::Event event, void* data);
void Resumed();
protected:
void showEvent(QShowEvent* ev) override;
void hideEvent(QHideEvent* ev) override;
private:
static QString GetShaderStageName(VideoCore::ShaderStage stage);
void onSelectionChanged();
void OnBreakPointHit(Tegra::DebugContext::Event event, void* data);
void OnResumed();
void SelectShader(int index);
void DisableEditor();
void EnableEditor();
void RemoveShaderList();
const char* GetActiveCode() const;
void SaveActiveCode();
void SaveScrollPosition();
void RestoreScrollPosition();
void SaveSelectedShader();
void RestoreSelectedShader();
using ShaderAddress = u64;
std::shared_ptr<Tegra::DebugContext> context;
std::vector<VideoCore::ShaderInfo> shaders;
std::vector<bool> modified_shaders;
std::optional<int> active_shader;
// UX cached values
std::map<ShaderAddress, int> scroll_map;
std::optional<ShaderAddress> last_shader;
QAction* toggle_view_action = nullptr;
QHBoxLayout* layout = nullptr;
QStandardItemModel* item_model = nullptr;
QTreeView* tree_view = nullptr;
QTextEdit* code_editor = nullptr;
};

View File

@@ -79,6 +79,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "yuzu/debugger/graphics/graphics_breakpoints.h"
#include "yuzu/debugger/graphics/graphics_surface.h"
#include "yuzu/debugger/profiler.h"
#include "yuzu/debugger/shader_tools.h"
#include "yuzu/debugger/wait_tree.h"
#include "yuzu/discord.h"
#include "yuzu/game_list.h"
@@ -254,6 +255,10 @@ void GMainWindow::InitializeDebugWidgets() {
debug_menu->addAction(microProfileDialog->toggleViewAction());
#endif
shaderToolsDialog = new ShaderToolsDialog(debug_context, this);
shaderToolsDialog->hide();
debug_menu->addAction(shaderToolsDialog->toggleViewAction());
graphicsBreakpointsWidget = new GraphicsBreakPointsWidget(debug_context, this);
addDockWidget(Qt::RightDockWidgetArea, graphicsBreakpointsWidget);
graphicsBreakpointsWidget->hide();
@@ -392,6 +397,9 @@ void GMainWindow::RestoreUIState() {
microProfileDialog->setVisible(UISettings::values.microprofile_visible);
#endif
shaderToolsDialog->restoreGeometry(UISettings::values.shader_tools_geometry);
shaderToolsDialog->setVisible(UISettings::values.shader_tools_visible);
game_list->LoadInterfaceLayout();
ui.action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode);
@@ -1645,6 +1653,8 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
UISettings::values.microprofile_geometry = microProfileDialog->saveGeometry();
UISettings::values.microprofile_visible = microProfileDialog->isVisible();
#endif
UISettings::values.shader_tools_geometry = shaderToolsDialog->saveGeometry();
UISettings::values.shader_tools_visible = shaderToolsDialog->isVisible();
UISettings::values.single_window_mode = ui.action_Single_Window_Mode->isChecked();
UISettings::values.fullscreen = ui.action_Fullscreen->isChecked();
UISettings::values.display_titlebar = ui.action_Display_Dock_Widget_Headers->isChecked();

View File

@@ -26,6 +26,7 @@ class GraphicsSurfaceWidget;
class GRenderWindow;
class MicroProfileDialog;
class ProfilerWidget;
class ShaderToolsDialog;
class WaitTreeWidget;
enum class GameListOpenTarget;
@@ -212,6 +213,7 @@ private:
MicroProfileDialog* microProfileDialog;
GraphicsBreakPointsWidget* graphicsBreakpointsWidget;
GraphicsSurfaceWidget* graphicsSurfaceWidget;
ShaderToolsDialog* shaderToolsDialog;
WaitTreeWidget* waitTreeWidget;
QAction* actions_recent_files[max_recent_files_item];

View File

@@ -30,6 +30,9 @@ struct Values {
QByteArray microprofile_geometry;
bool microprofile_visible;
QByteArray shader_tools_geometry;
bool shader_tools_visible;
bool single_window_mode;
bool fullscreen;
bool display_titlebar;