Compare commits
2 Commits
revert-115
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dca38b7b8d | ||
|
|
b3254df4ec |
@@ -55,6 +55,7 @@ add_library(video_core STATIC
|
|||||||
renderer_opengl/renderer_opengl.h
|
renderer_opengl/renderer_opengl.h
|
||||||
renderer_opengl/utils.cpp
|
renderer_opengl/utils.cpp
|
||||||
renderer_opengl/utils.h
|
renderer_opengl/utils.h
|
||||||
|
shader_info.h
|
||||||
surface.cpp
|
surface.cpp
|
||||||
surface.h
|
surface.h
|
||||||
textures/astc.cpp
|
textures/astc.cpp
|
||||||
|
|||||||
@@ -459,6 +459,14 @@ Texture::FullTextureInfo Maxwell3D::GetStageTexture(Regs::ShaderStage stage,
|
|||||||
return tex_info;
|
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 {
|
u32 Maxwell3D::GetRegisterValue(u32 method) const {
|
||||||
ASSERT_MSG(method < Regs::NUM_REGS, "Invalid Maxwell3D register");
|
ASSERT_MSG(method < Regs::NUM_REGS, "Invalid Maxwell3D register");
|
||||||
return regs.reg_array[method];
|
return regs.reg_array[method];
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "video_core/gpu.h"
|
#include "video_core/gpu.h"
|
||||||
#include "video_core/macro_interpreter.h"
|
#include "video_core/macro_interpreter.h"
|
||||||
#include "video_core/memory_manager.h"
|
#include "video_core/memory_manager.h"
|
||||||
|
#include "video_core/shader_info.h"
|
||||||
#include "video_core/textures/texture.h"
|
#include "video_core/textures/texture.h"
|
||||||
|
|
||||||
namespace VideoCore {
|
namespace VideoCore {
|
||||||
@@ -1044,6 +1045,17 @@ public:
|
|||||||
/// Returns the texture information for a specific texture in a specific shader stage.
|
/// Returns the texture information for a specific texture in a specific shader stage.
|
||||||
Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, std::size_t offset) const;
|
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
|
/// Memory for macro code - it's undetermined how big this is, however 1MB is much larger than
|
||||||
/// we've seen used.
|
/// we've seen used.
|
||||||
using MacroMemory = std::array<u32, 0x40000>;
|
using MacroMemory = std::array<u32, 0x40000>;
|
||||||
|
|||||||
@@ -129,6 +129,17 @@ protected:
|
|||||||
return ++modified_ticks;
|
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:
|
private:
|
||||||
/// Returns a list of cached objects from the specified memory region, ordered by access time
|
/// Returns a list of cached objects from the specified memory region, ordered by access time
|
||||||
std::vector<T> GetSortedObjectsFromRegion(VAddr addr, u64 size) {
|
std::vector<T> GetSortedObjectsFromRegion(VAddr addr, u64 size) {
|
||||||
|
|||||||
@@ -4,10 +4,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/engines/fermi_2d.h"
|
#include "video_core/engines/fermi_2d.h"
|
||||||
#include "video_core/gpu.h"
|
#include "video_core/gpu.h"
|
||||||
#include "video_core/memory_manager.h"
|
#include "video_core/memory_manager.h"
|
||||||
|
#include "video_core/shader_info.h"
|
||||||
|
|
||||||
namespace VideoCore {
|
namespace VideoCore {
|
||||||
|
|
||||||
@@ -57,5 +59,13 @@ public:
|
|||||||
|
|
||||||
/// Increase/decrease the number of object in pages touching the specified region
|
/// Increase/decrease the number of object in pages touching the specified region
|
||||||
virtual void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) {}
|
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
|
} // namespace VideoCore
|
||||||
|
|||||||
@@ -373,6 +373,14 @@ bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) {
|
|||||||
return true;
|
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>
|
template <typename Map, typename Interval>
|
||||||
static constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
|
static constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
|
||||||
return boost::make_iterator_range(map.equal_range(interval));
|
return boost::make_iterator_range(map.equal_range(interval));
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ public:
|
|||||||
u32 pixel_stride) override;
|
u32 pixel_stride) override;
|
||||||
bool AccelerateDrawBatch(bool is_indexed) override;
|
bool AccelerateDrawBatch(bool is_indexed) override;
|
||||||
void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) 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
|
/// OpenGL shader generated for a given Maxwell register state
|
||||||
struct MaxwellShader {
|
struct MaxwellShader {
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
#include "video_core/renderer_opengl/gl_shader_cache.h"
|
#include "video_core/renderer_opengl/gl_shader_cache.h"
|
||||||
#include "video_core/renderer_opengl/gl_shader_manager.h"
|
#include "video_core/renderer_opengl/gl_shader_manager.h"
|
||||||
#include "video_core/renderer_opengl/utils.h"
|
#include "video_core/renderer_opengl/utils.h"
|
||||||
|
#include "video_core/shader_info.h"
|
||||||
|
#include "video_core/utils.h"
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
|
||||||
@@ -57,7 +59,6 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
|
|||||||
: addr{addr}, program_type{program_type}, setup{GetShaderCode(addr)} {
|
: addr{addr}, program_type{program_type}, setup{GetShaderCode(addr)} {
|
||||||
|
|
||||||
GLShader::ProgramResult program_result;
|
GLShader::ProgramResult program_result;
|
||||||
GLenum gl_type{};
|
|
||||||
|
|
||||||
switch (program_type) {
|
switch (program_type) {
|
||||||
case Maxwell::ShaderProgram::VertexA:
|
case Maxwell::ShaderProgram::VertexA:
|
||||||
@@ -83,18 +84,10 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
code = program_result.first;
|
||||||
entries = program_result.second;
|
entries = program_result.second;
|
||||||
|
|
||||||
if (program_type != Maxwell::ShaderProgram::Geometry) {
|
BuildProgram();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) {
|
GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) {
|
||||||
@@ -120,6 +113,26 @@ GLint CachedShader::GetUniformLocation(const GLShader::SamplerEntry& sampler) {
|
|||||||
return search->second;
|
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,
|
GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program,
|
||||||
const std::string& glsl_topology, u32 max_vertices,
|
const std::string& glsl_topology, u32 max_vertices,
|
||||||
const std::string& debug_name) {
|
const std::string& debug_name) {
|
||||||
@@ -129,7 +142,7 @@ GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program,
|
|||||||
std::string source = "#version 430 core\n";
|
std::string source = "#version 430 core\n";
|
||||||
source += "layout (" + glsl_topology + ") in;\n";
|
source += "layout (" + glsl_topology + ") in;\n";
|
||||||
source += "#define MAX_VERTEX_INPUT " + std::to_string(max_vertices) + '\n';
|
source += "#define MAX_VERTEX_INPUT " + std::to_string(max_vertices) + '\n';
|
||||||
source += geometry_programs.code;
|
source += code;
|
||||||
|
|
||||||
OGLShader shader;
|
OGLShader shader;
|
||||||
shader.Create(source.c_str(), GL_GEOMETRY_SHADER);
|
shader.Create(source.c_str(), GL_GEOMETRY_SHADER);
|
||||||
@@ -139,6 +152,37 @@ GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program,
|
|||||||
return target_program.handle;
|
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} {}
|
ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer) : RasterizerCache{rasterizer} {}
|
||||||
|
|
||||||
Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) {
|
Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) {
|
||||||
@@ -156,4 +200,17 @@ Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) {
|
|||||||
return shader;
|
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
|
} // namespace OpenGL
|
||||||
|
|||||||
@@ -6,12 +6,15 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/rasterizer_cache.h"
|
#include "video_core/rasterizer_cache.h"
|
||||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||||
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
||||||
|
#include "video_core/shader_info.h"
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
|
||||||
@@ -43,6 +46,9 @@ public:
|
|||||||
|
|
||||||
/// Gets the GL program handle for the shader
|
/// Gets the GL program handle for the shader
|
||||||
GLuint GetProgramHandle(GLenum primitive_mode) {
|
GLuint GetProgramHandle(GLenum primitive_mode) {
|
||||||
|
if (rebuild) {
|
||||||
|
BuildProgram();
|
||||||
|
}
|
||||||
if (program_type != Maxwell::ShaderProgram::Geometry) {
|
if (program_type != Maxwell::ShaderProgram::Geometry) {
|
||||||
return program.handle;
|
return program.handle;
|
||||||
}
|
}
|
||||||
@@ -76,7 +82,16 @@ public:
|
|||||||
/// Gets the GL uniform location for the specified resource, caching as needed
|
/// Gets the GL uniform location for the specified resource, caching as needed
|
||||||
GLint GetUniformLocation(const GLShader::SamplerEntry& sampler);
|
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:
|
private:
|
||||||
|
/// Builds programs from current set code.
|
||||||
|
void BuildProgram();
|
||||||
|
|
||||||
/// Generates a geometry shader or returns one that already exists.
|
/// Generates a geometry shader or returns one that already exists.
|
||||||
GLuint LazyGeometryProgram(OGLProgram& target_program, const std::string& glsl_topology,
|
GLuint LazyGeometryProgram(OGLProgram& target_program, const std::string& glsl_topology,
|
||||||
u32 max_vertices, const std::string& debug_name);
|
u32 max_vertices, const std::string& debug_name);
|
||||||
@@ -86,6 +101,10 @@ private:
|
|||||||
GLShader::ShaderSetup setup;
|
GLShader::ShaderSetup setup;
|
||||||
GLShader::ShaderEntries entries;
|
GLShader::ShaderEntries entries;
|
||||||
|
|
||||||
|
GLenum gl_type{};
|
||||||
|
std::string code;
|
||||||
|
bool rebuild{};
|
||||||
|
|
||||||
// Non-geometry program.
|
// Non-geometry program.
|
||||||
OGLProgram program;
|
OGLProgram program;
|
||||||
|
|
||||||
@@ -93,12 +112,19 @@ private:
|
|||||||
// declared by the hardware. Workaround this issue by generating a different shader per input
|
// declared by the hardware. Workaround this issue by generating a different shader per input
|
||||||
// topology class.
|
// topology class.
|
||||||
struct {
|
struct {
|
||||||
std::string code;
|
|
||||||
OGLProgram points;
|
OGLProgram points;
|
||||||
OGLProgram lines;
|
OGLProgram lines;
|
||||||
OGLProgram lines_adjacency;
|
OGLProgram lines_adjacency;
|
||||||
OGLProgram triangles;
|
OGLProgram triangles;
|
||||||
OGLProgram triangles_adjacency;
|
OGLProgram triangles_adjacency;
|
||||||
|
|
||||||
|
void Release() {
|
||||||
|
points.Release();
|
||||||
|
lines.Release();
|
||||||
|
lines_adjacency.Release();
|
||||||
|
triangles.Release();
|
||||||
|
triangles_adjacency.Release();
|
||||||
|
}
|
||||||
} geometry_programs;
|
} geometry_programs;
|
||||||
|
|
||||||
std::map<u32, GLuint> resource_cache;
|
std::map<u32, GLuint> resource_cache;
|
||||||
@@ -111,6 +137,12 @@ public:
|
|||||||
|
|
||||||
/// Gets the current specified shader stage program
|
/// Gets the current specified shader stage program
|
||||||
Shader GetStageProgram(Maxwell::ShaderProgram 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
|
} // namespace OpenGL
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ GLuint LoadProgram(bool separable_program, T... shaders) {
|
|||||||
|
|
||||||
// Check the program
|
// Check the program
|
||||||
GLint result = GL_FALSE;
|
GLint result = GL_FALSE;
|
||||||
GLint info_log_length;
|
GLint info_log_length{};
|
||||||
glGetProgramiv(program_id, GL_LINK_STATUS, &result);
|
glGetProgramiv(program_id, GL_LINK_STATUS, &result);
|
||||||
glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length);
|
glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length);
|
||||||
|
|
||||||
|
|||||||
29
src/video_core/shader_info.h
Normal file
29
src/video_core/shader_info.h
Normal 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
|
||||||
@@ -48,6 +48,8 @@ add_executable(yuzu
|
|||||||
debugger/console.h
|
debugger/console.h
|
||||||
debugger/profiler.cpp
|
debugger/profiler.cpp
|
||||||
debugger/profiler.h
|
debugger/profiler.h
|
||||||
|
debugger/shader_tools.cpp
|
||||||
|
debugger/shader_tools.h
|
||||||
debugger/wait_tree.cpp
|
debugger/wait_tree.cpp
|
||||||
debugger/wait_tree.h
|
debugger/wait_tree.h
|
||||||
discord.h
|
discord.h
|
||||||
|
|||||||
@@ -467,6 +467,9 @@ void Config::ReadValues() {
|
|||||||
qt_config->value("microProfileDialogGeometry").toByteArray();
|
qt_config->value("microProfileDialogGeometry").toByteArray();
|
||||||
UISettings::values.microprofile_visible =
|
UISettings::values.microprofile_visible =
|
||||||
qt_config->value("microProfileDialogVisible", false).toBool();
|
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->endGroup();
|
||||||
|
|
||||||
qt_config->beginGroup("Paths");
|
qt_config->beginGroup("Paths");
|
||||||
@@ -667,6 +670,8 @@ void Config::SaveValues() {
|
|||||||
qt_config->setValue("gameListHeaderState", UISettings::values.gamelist_header_state);
|
qt_config->setValue("gameListHeaderState", UISettings::values.gamelist_header_state);
|
||||||
qt_config->setValue("microProfileDialogGeometry", UISettings::values.microprofile_geometry);
|
qt_config->setValue("microProfileDialogGeometry", UISettings::values.microprofile_geometry);
|
||||||
qt_config->setValue("microProfileDialogVisible", UISettings::values.microprofile_visible);
|
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->endGroup();
|
||||||
|
|
||||||
qt_config->beginGroup("Paths");
|
qt_config->beginGroup("Paths");
|
||||||
|
|||||||
261
src/yuzu/debugger/shader_tools.cpp
Normal file
261
src/yuzu/debugger/shader_tools.cpp
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
89
src/yuzu/debugger/shader_tools.h
Normal file
89
src/yuzu/debugger/shader_tools.h
Normal 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;
|
||||||
|
};
|
||||||
@@ -79,6 +79,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
|
|||||||
#include "yuzu/debugger/graphics/graphics_breakpoints.h"
|
#include "yuzu/debugger/graphics/graphics_breakpoints.h"
|
||||||
#include "yuzu/debugger/graphics/graphics_surface.h"
|
#include "yuzu/debugger/graphics/graphics_surface.h"
|
||||||
#include "yuzu/debugger/profiler.h"
|
#include "yuzu/debugger/profiler.h"
|
||||||
|
#include "yuzu/debugger/shader_tools.h"
|
||||||
#include "yuzu/debugger/wait_tree.h"
|
#include "yuzu/debugger/wait_tree.h"
|
||||||
#include "yuzu/discord.h"
|
#include "yuzu/discord.h"
|
||||||
#include "yuzu/game_list.h"
|
#include "yuzu/game_list.h"
|
||||||
@@ -254,6 +255,10 @@ void GMainWindow::InitializeDebugWidgets() {
|
|||||||
debug_menu->addAction(microProfileDialog->toggleViewAction());
|
debug_menu->addAction(microProfileDialog->toggleViewAction());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
shaderToolsDialog = new ShaderToolsDialog(debug_context, this);
|
||||||
|
shaderToolsDialog->hide();
|
||||||
|
debug_menu->addAction(shaderToolsDialog->toggleViewAction());
|
||||||
|
|
||||||
graphicsBreakpointsWidget = new GraphicsBreakPointsWidget(debug_context, this);
|
graphicsBreakpointsWidget = new GraphicsBreakPointsWidget(debug_context, this);
|
||||||
addDockWidget(Qt::RightDockWidgetArea, graphicsBreakpointsWidget);
|
addDockWidget(Qt::RightDockWidgetArea, graphicsBreakpointsWidget);
|
||||||
graphicsBreakpointsWidget->hide();
|
graphicsBreakpointsWidget->hide();
|
||||||
@@ -392,6 +397,9 @@ void GMainWindow::RestoreUIState() {
|
|||||||
microProfileDialog->setVisible(UISettings::values.microprofile_visible);
|
microProfileDialog->setVisible(UISettings::values.microprofile_visible);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
shaderToolsDialog->restoreGeometry(UISettings::values.shader_tools_geometry);
|
||||||
|
shaderToolsDialog->setVisible(UISettings::values.shader_tools_visible);
|
||||||
|
|
||||||
game_list->LoadInterfaceLayout();
|
game_list->LoadInterfaceLayout();
|
||||||
|
|
||||||
ui.action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode);
|
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_geometry = microProfileDialog->saveGeometry();
|
||||||
UISettings::values.microprofile_visible = microProfileDialog->isVisible();
|
UISettings::values.microprofile_visible = microProfileDialog->isVisible();
|
||||||
#endif
|
#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.single_window_mode = ui.action_Single_Window_Mode->isChecked();
|
||||||
UISettings::values.fullscreen = ui.action_Fullscreen->isChecked();
|
UISettings::values.fullscreen = ui.action_Fullscreen->isChecked();
|
||||||
UISettings::values.display_titlebar = ui.action_Display_Dock_Widget_Headers->isChecked();
|
UISettings::values.display_titlebar = ui.action_Display_Dock_Widget_Headers->isChecked();
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ class GraphicsSurfaceWidget;
|
|||||||
class GRenderWindow;
|
class GRenderWindow;
|
||||||
class MicroProfileDialog;
|
class MicroProfileDialog;
|
||||||
class ProfilerWidget;
|
class ProfilerWidget;
|
||||||
|
class ShaderToolsDialog;
|
||||||
class WaitTreeWidget;
|
class WaitTreeWidget;
|
||||||
enum class GameListOpenTarget;
|
enum class GameListOpenTarget;
|
||||||
|
|
||||||
@@ -212,6 +213,7 @@ private:
|
|||||||
MicroProfileDialog* microProfileDialog;
|
MicroProfileDialog* microProfileDialog;
|
||||||
GraphicsBreakPointsWidget* graphicsBreakpointsWidget;
|
GraphicsBreakPointsWidget* graphicsBreakpointsWidget;
|
||||||
GraphicsSurfaceWidget* graphicsSurfaceWidget;
|
GraphicsSurfaceWidget* graphicsSurfaceWidget;
|
||||||
|
ShaderToolsDialog* shaderToolsDialog;
|
||||||
WaitTreeWidget* waitTreeWidget;
|
WaitTreeWidget* waitTreeWidget;
|
||||||
|
|
||||||
QAction* actions_recent_files[max_recent_files_item];
|
QAction* actions_recent_files[max_recent_files_item];
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ struct Values {
|
|||||||
QByteArray microprofile_geometry;
|
QByteArray microprofile_geometry;
|
||||||
bool microprofile_visible;
|
bool microprofile_visible;
|
||||||
|
|
||||||
|
QByteArray shader_tools_geometry;
|
||||||
|
bool shader_tools_visible;
|
||||||
|
|
||||||
bool single_window_mode;
|
bool single_window_mode;
|
||||||
bool fullscreen;
|
bool fullscreen;
|
||||||
bool display_titlebar;
|
bool display_titlebar;
|
||||||
|
|||||||
Reference in New Issue
Block a user