commit 3b11b9652d5b47792521495d9e4bc8343ac3e1d3 Author: Vincent Lejeune Date: Sun Jul 31 22:23:18 2016 +0200 Initial import diff --git a/README.md b/README.md new file mode 100644 index 0000000..7f3c12d --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +rsx-debugger is a Qt debugger app aimed at helping debugging rpcs3 rsx emulation. +It requires Qt Core and the Qt QML modules as additionnal build dependencies. + +To use it, capture a frame inside rpcs3. This will generates a file in the bin/ directory. +At launch rsx-debugger will load any bin/capture.txt file and display the content in a more friendly maneer. + +TODO: +- Provide a "load" menu. +- Display saved surface content. +- Display command dump. + diff --git a/deployment.pri b/deployment.pri new file mode 100644 index 0000000..265ce71 --- /dev/null +++ b/deployment.pri @@ -0,0 +1,13 @@ +unix:!android { + isEmpty(target.path) { + qnx { + target.path = /tmp/$${TARGET}/bin + } else { + target.path = /opt/$${TARGET}/bin + } + export(target.path) + } + INSTALLS += target +} + +export(INSTALLS) diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..8a6dfac --- /dev/null +++ b/main.cpp @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include "state.h" +#include +#include +#include + +QList load_command_trace() +{ + // Unfortunatly QTextStream isn't compatible with std::iostream + std::fstream f("../bin/capture.txt", std::ios::in | std::ios::binary); + + cereal::BinaryInputArchive archive(f); + rsx::frame_capture_data frame_debug; + archive(frame_debug); + + QList st; + for (const rsx::frame_capture_data::draw_state &draw_state : frame_debug.draw_calls) + { + auto *tmp = new qt_rsx_state; + *tmp = draw_state.state; + tmp->_name = QString::fromStdString(draw_state.name); + tmp->_transform_program = QString::fromStdString(draw_state.programs.first); + tmp->_shader_program = QString::fromStdString(draw_state.programs.second); + size_t index_list_size = draw_state.index.size(); + switch (draw_state.state.index_type()) + { + case rsx::index_array_type::u16: + for (size_t i = 0; i < index_list_size / 2; i++) + { + const u16* ptr = reinterpret_cast(draw_state.index.data()); + tmp->_index_list.append(QVariant::fromValue(ptr[i])); + } + break; + case rsx::index_array_type::u32: + for (size_t i = 0; i < index_list_size / 4; i++) + { + const u32* ptr = reinterpret_cast(draw_state.index.data()); + tmp->_index_list.append(QVariant::fromValue(ptr[i])); + } + break; + } + st.append(tmp); + } + + return st; +} + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + QQmlContext* ctx = engine.rootContext(); + QList st = load_command_trace(); + ctx->setContextProperty("stateList", QVariant::fromValue(st)); + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + + + + return app.exec(); +} diff --git a/main.qml b/main.qml new file mode 100644 index 0000000..4ffeab2 --- /dev/null +++ b/main.qml @@ -0,0 +1,476 @@ +import QtQuick 2.7 +import QtQuick.Window 2.2 +import QtQuick.Controls 1.4 + +Window { + visible: true + width: 1920 + height: 1080 + title: qsTr("RSX Debugger") + + SplitView { + id: splitView1 + anchors.fill: parent + ScrollView + { + ListView { + id: listView1 + width: 130 + anchors.fill: parent.fill + model: stateList + delegate: Item { + x: 5 + width: 80 + height: 40 + + MouseArea + { + anchors.fill: parent + onClicked: { + listView1.currentIndex = index + } + } + + Row { + id: row1 + Text { + text: model.modelData.name + anchors.verticalCenter: parent.verticalCenter + } + spacing: 10 + } + } + } + } + + TabView { + id: tabView1 + anchors.fill: parent.fill + Tab { + title: "Transform program" + + TextArea { + id: textArea1 + text: listView1.model[listView1.currentIndex].transformProgram + readOnly: true + } + } + + Tab { + title: "Shader program" + + TextArea { + id: textArea2 + text: listView1.model[listView1.currentIndex].shaderProgram + readOnly: true + } + } + + Tab { + title: "Input Assembly" + + Flow { + GroupBox { + title:"Offseting" + Column { + Label { + text: "Scale: " + listView1.model[listView1.currentIndex].polyOffsetScale + } + Label { + text: "Bias: " + listView1.model[listView1.currentIndex].polyOffsetBias + } + Label { + text: "Point: " + listView1.model[listView1.currentIndex].polyOffsetPoint + } + Label { + text: "Line: " + listView1.model[listView1.currentIndex].polyOffsetLine + } + Label { + text: "Fill: " + listView1.model[listView1.currentIndex].polyOffsetFill + } + } + } + GroupBox { + title:"Viewport" + Column { + GroupBox { + title:"Scale" + Column { + Label { + text:"X: " + listView1.model[listView1.currentIndex].viewportScaleX + } + Label { + text:"Y: " + listView1.model[listView1.currentIndex].viewportScaleY + } + Label { + text:"Z: " + listView1.model[listView1.currentIndex].viewportScaleZ + } + Label { + text:"W: " + listView1.model[listView1.currentIndex].viewportScaleW + } + } + } + GroupBox { + title:"Offset" + Column { + Label { + text:"X: " + listView1.model[listView1.currentIndex].viewportOffsetX + } + Label { + text:"Y: " + listView1.model[listView1.currentIndex].viewportOffsetY + } + Label { + text:"Z: " + listView1.model[listView1.currentIndex].viewportOffsetZ + } + Label { + text:"W: " + listView1.model[listView1.currentIndex].viewportOffsetW + } + } + } + } + } + GroupBox { + title:"Indexing" + Column { + Label { + text: "Vertex base offset: " + listView1.model[listView1.currentIndex].vertexBaseOffset + } + Label { + text: "Vertex base index: " + listView1.model[listView1.currentIndex].vertexBaseIndex + } + Label { + text:"Restart Index enabled: " + listView1.model[listView1.currentIndex].restartIndexEnabled + } + Label { + text:"Restart Index: " + listView1.model[listView1.currentIndex].restartIndex + } + ScrollView { + GroupBox { + title:"Index List" + ListView { + width:100 + height:100 + model: listView1.model[listView1.currentIndex].indexList + delegate: Item { + x: 5 + width: 80 + height: 40 + + Row { + Text { + text: model.modelData + } + spacing: 10 + } + } + } + } + } + } + } + GroupBox { + title:"Fog" + Column { + Label { + text:"fog P0: " + listView1.model[listView1.currentIndex].fogP0 + } + Label { + text:"fog P1: " + listView1.model[listView1.currentIndex].fogP1 + } + } + } + Label { + text:"2 sided lighting: " + listView1.model[listView1.currentIndex].twoSidedLighting + } + Label { + text:"Cull: " + listView1.model[listView1.currentIndex].cullEnabled + } + } + } + + Tab { + title: "Output merge" + Flow { + GroupBox { + title:"Viewport" + Column { + Label { + text:"origin x: " + listView1.model[listView1.currentIndex].ViewportOriginX + } + Label { + text:"origin y: " + listView1.model[listView1.currentIndex].ViewportOriginY + } + Label { + text:"width: " + listView1.model[listView1.currentIndex].ViewportWidth + } + Label { + text:"height: " + listView1.model[listView1.currentIndex].ViewportHeight + } + } + } + GroupBox { + title:"Scissor" + Column { + Label { + text:"origin x: " + listView1.model[listView1.currentIndex].ScissorOriginX + } + Label { + text:"origin y: " + listView1.model[listView1.currentIndex].ScissorOriginY + } + Label { + text:"width: " + listView1.model[listView1.currentIndex].ScissorWidth + } + Label { + text:"height: " + listView1.model[listView1.currentIndex].ScissorHeight + } + } + } + GroupBox { + title:"Logic Op" + Column { + Label { + text: "Enabled: " + listView1.model[listView1.currentIndex].logicOp + } + Label { + text: "Func: " + listView1.model[listView1.currentIndex].logicFunc + } + } + } + GroupBox { + title:"Alpha Test" + Column { + Label { + text: "Enabled: " + listView1.model[listView1.currentIndex].alphaTest + } + Label { + text: "Func: " + listView1.model[listView1.currentIndex].alphaFunc + } + Label { + text: "Ref: " + listView1.model[listView1.currentIndex].alphaRef + } + } + } + GroupBox { + title:"Depth" + Column { + Label { + text:"Test: " + listView1.model[listView1.currentIndex].depthTest + } + Label { + text:"Func: " + listView1.model[listView1.currentIndex].depthFunc + } + Label { + text:"Write: " + listView1.model[listView1.currentIndex].depthWrite + } + Label { + text:"Bound: " + listView1.model[listView1.currentIndex].depthBound + } + } + } + GroupBox { + title:"Stencil Test" + Column { + Label { + text: "Enabled: " + listView1.model[listView1.currentIndex].stencilTest + } + Label { + text: "2 sided: " + listView1.model[listView1.currentIndex].twoSidedStencil + } + } + } + GroupBox { + title:"Color Mask" + Column { + Label { + text: "A: " + listView1.model[listView1.currentIndex].colorMaskA + } + Label { + text: "R: " + listView1.model[listView1.currentIndex].colorMaskR + } + Label { + text: "G: " + listView1.model[listView1.currentIndex].colorMaskG + } + Label { + text: "B: " + listView1.model[listView1.currentIndex].colorMaskB + } + } + } + GroupBox { + title:"Blend" + Column { + Label { + text: "Enabled: " + listView1.model[listView1.currentIndex].blendEnabled + } + Label { + text: "Surface 1: " + listView1.model[listView1.currentIndex].blendSurface1 + } + Label { + text: "Surface 2: " + listView1.model[listView1.currentIndex].blendSurface2 + } + Label { + text: "Surface 3: " + listView1.model[listView1.currentIndex].blendSurface3 + } + GroupBox { + title:"RGB" + Column { + Label { + text: "Equation: " + listView1.model[listView1.currentIndex].blendEquationRGB + } + Label { + text: "Src Factor: " + listView1.model[listView1.currentIndex].blendSFactorRGB + } + Label { + text: "Dst Factor: " + listView1.model[listView1.currentIndex].blendDFactorRGB + } + } + } + GroupBox { + title:"Alpha" + Column { + Label { + text: "Equation: " + listView1.model[listView1.currentIndex].blendEquationA + } + Label { + text: "Src Factor: " + listView1.model[listView1.currentIndex].blendSFactorA + } + Label { + text: "Dst Factor: " + listView1.model[listView1.currentIndex].blendDFactorA + } + } + } + } + } + GroupBox { + title:"Smooth" + Column { + Label { + text: "Line: " + listView1.model[listView1.currentIndex].lineSmoothEnabled + } + Label { + text: "Poly: " + listView1.model[listView1.currentIndex].polySmoothEnabled + } + } + } + } + } + + Tab { + title: "Surface" + Flow + { + GroupBox { + title:"Clip" + Column + { + Label + { + text:"X: " + listView1.model[listView1.currentIndex].originX + } + Label + { + text:"Y: " + listView1.model[listView1.currentIndex].originY + } + Label + { + text:"Width: " + listView1.model[listView1.currentIndex].widthRole + } + + Label + { + text:"Height: " + listView1.model[listView1.currentIndex].heightRole + } + } + } + GroupBox { + title:"Layout" + Column + { + Label + { + text:"Width: " + listView1.model[listView1.currentIndex].surfaceWidth + } + Label + { + text:"Height: " + listView1.model[listView1.currentIndex].surfaceHeight + } + Label + { + text:"Depth format: " + listView1.model[listView1.currentIndex].surfaceDepthFormat + } + GroupBox { + title: "Color" + Column { + Label + { + text:"Format: " + listView1.model[listView1.currentIndex].surfaceColorFormat + } + Label + { + text:"Target: " + listView1.model[listView1.currentIndex].surfaceTarget + } + GroupBox { + title:"Surface A" + Column + { + Label + { + text:"Offset: " + listView1.model[listView1.currentIndex].offsetA + } + Label + { + text:"Pitch: " + listView1.model[listView1.currentIndex].pitchA + } + } + } + GroupBox { + title:"Surface B" + Column + { + Label + { + text:"Offset: " + listView1.model[listView1.currentIndex].offsetB + } + Label + { + text:"Pitch: " + listView1.model[listView1.currentIndex].pitchB + } + } + } + GroupBox { + title:"Surface C" + Column + { + Label + { + text:"Offset: " + listView1.model[listView1.currentIndex].offsetC + } + Label + { + text:"Pitch: " + listView1.model[listView1.currentIndex].pitchC + } + } + } + GroupBox { + title:"Surface D" + Column + { + Label + { + text:"Offset: " + listView1.model[listView1.currentIndex].offsetD + } + Label + { + text:"Pitch: " + listView1.model[listView1.currentIndex].pitchD + } + } + } + } + } + } + } + } + } + } + + } +} diff --git a/qml.qrc b/qml.qrc new file mode 100644 index 0000000..5f6483a --- /dev/null +++ b/qml.qrc @@ -0,0 +1,5 @@ + + + main.qml + + diff --git a/rsx-debugger.pro b/rsx-debugger.pro new file mode 100644 index 0000000..7e5605f --- /dev/null +++ b/rsx-debugger.pro @@ -0,0 +1,24 @@ +TEMPLATE = app + +QT += qml quick +CONFIG += c++11 + +SOURCES += main.cpp \ + ../rpcs3/Emu/RSX/gcm_enums.cpp \ + ../Utilities/StrFmt.cpp + +RESOURCES += qml.qrc + +INCLUDEPATH += ../ \ + ../rpcs3/ \ + ../rsx_program_decompiler/rsx_decompiler/ \ + ../3rdparty/cereal/include/ + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = + +# Default rules for deployment. +include(deployment.pri) + +HEADERS += \ + state.h diff --git a/state.h b/state.h new file mode 100644 index 0000000..f48124c --- /dev/null +++ b/state.h @@ -0,0 +1,208 @@ +#ifndef STATE_H +#define STATE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class qt_rsx_state : public QObject, public rsx::rsx_state +{ + Q_OBJECT + + Q_PROPERTY(quint16 ViewportWidth READ viewport_width CONSTANT) + Q_PROPERTY(quint16 ViewportHeight READ viewport_height CONSTANT) + Q_PROPERTY(quint16 ViewportOriginX READ viewport_origin_x CONSTANT) + Q_PROPERTY(quint16 ViewportOriginY READ viewport_origin_y CONSTANT) + + Q_PROPERTY(quint16 ScissorWidth READ scissor_width CONSTANT) + Q_PROPERTY(quint16 ScissorHeight READ scissor_height CONSTANT) + Q_PROPERTY(quint16 ScissorOriginX READ scissor_origin_x CONSTANT) + Q_PROPERTY(quint16 ScissorOriginY READ scissor_origin_y CONSTANT) + + Q_PROPERTY(quint16 surfaceWidth READ getSurfaceWidth CONSTANT) + Q_PROPERTY(quint16 surfaceHeight READ getSurfaceHeight CONSTANT) + Q_PROPERTY(quint16 widthRole READ surface_clip_width CONSTANT) + Q_PROPERTY(quint16 heightRole READ surface_clip_height CONSTANT) + Q_PROPERTY(quint16 originX READ surface_clip_origin_x CONSTANT) + Q_PROPERTY(quint16 originY READ surface_clip_origin_y CONSTANT) + Q_PROPERTY(QString surfaceTarget READ getSurfaceTarget CONSTANT) + Q_PROPERTY(QString surfaceColorFormat READ getSurfaceColorFormat CONSTANT) + Q_PROPERTY(QString surfaceDepthFormat READ getSurfaceDepthStencilFormat CONSTANT) + + Q_PROPERTY(quint32 offsetA READ surface_a_offset CONSTANT) + Q_PROPERTY(quint32 offsetB READ surface_b_offset CONSTANT) + Q_PROPERTY(quint32 offsetC READ surface_c_offset CONSTANT) + Q_PROPERTY(quint32 offsetD READ surface_d_offset CONSTANT) + Q_PROPERTY(quint32 pitchA READ surface_a_pitch CONSTANT) + Q_PROPERTY(quint32 pitchB READ surface_b_pitch CONSTANT) + Q_PROPERTY(quint32 pitchC READ surface_c_pitch CONSTANT) + Q_PROPERTY(quint32 pitchD READ surface_d_pitch CONSTANT) + + Q_PROPERTY(bool twoSidedLighting READ two_side_light_en CONSTANT) + Q_PROPERTY(float fogP0 READ fog_params_0 CONSTANT) + Q_PROPERTY(float fogP1 READ fog_params_1 CONSTANT) + Q_PROPERTY(bool cullEnabled READ cull_face_enabled CONSTANT) + Q_PROPERTY(bool restartIndexEnabled READ restart_index_enabled CONSTANT) + Q_PROPERTY(quint32 restartIndex READ restart_index CONSTANT) + Q_PROPERTY(float viewportScaleX READ viewport_scale_x CONSTANT) + Q_PROPERTY(float viewportScaleY READ viewport_scale_y CONSTANT) + Q_PROPERTY(float viewportScaleZ READ viewport_scale_z CONSTANT) + Q_PROPERTY(float viewportScaleW READ viewport_scale_w CONSTANT) + Q_PROPERTY(float viewportOffsetX READ viewport_offset_x CONSTANT) + Q_PROPERTY(float viewportOffsetY READ viewport_offset_y CONSTANT) + Q_PROPERTY(float viewportOffsetZ READ viewport_offset_z CONSTANT) + Q_PROPERTY(float viewportOffsetW READ viewport_offset_w CONSTANT) + Q_PROPERTY(quint32 vertexBaseOffset READ vertex_data_base_offset CONSTANT) + Q_PROPERTY(quint32 vertexBaseIndex READ vertex_data_base_index CONSTANT) + Q_PROPERTY(QVariantList indexList READ getIndexList CONSTANT) + + Q_PROPERTY(bool depthTest READ depth_test_enabled CONSTANT) + Q_PROPERTY(QString depthFunc READ getDepthFunc CONSTANT) + Q_PROPERTY(bool depthWrite READ depth_write_enabled CONSTANT) + Q_PROPERTY(bool alphaTest READ alpha_test_enabled CONSTANT) + Q_PROPERTY(QString alphaFunc READ getAlphaFunc CONSTANT) + Q_PROPERTY(bool logicOp READ logic_op_enabled CONSTANT) + Q_PROPERTY(QString logicFunc READ getLogicFunc CONSTANT) + Q_PROPERTY(bool stencilTest READ stencil_test_enabled CONSTANT) + Q_PROPERTY(bool twoSidedStencil READ two_sided_stencil_test_enabled CONSTANT) + Q_PROPERTY(bool colorMaskA READ color_mask_a CONSTANT) + Q_PROPERTY(bool colorMaskR READ color_mask_r CONSTANT) + Q_PROPERTY(bool colorMaskG READ color_mask_g CONSTANT) + Q_PROPERTY(bool colorMaskB READ color_mask_b CONSTANT) + Q_PROPERTY(bool depthBound READ depth_bounds_test_enabled CONSTANT) + Q_PROPERTY(bool ditherEnabled READ dither_enabled CONSTANT) + Q_PROPERTY(bool blendEnabled READ blend_enabled CONSTANT) + Q_PROPERTY(bool blendSurface1 READ blend_enabled_surface_1 CONSTANT) + Q_PROPERTY(bool blendSurface2 READ blend_enabled_surface_2 CONSTANT) + Q_PROPERTY(bool blendSurface3 READ blend_enabled_surface_3 CONSTANT) + Q_PROPERTY(QString blendEquationRGB READ getBlendEquationRGB CONSTANT) + Q_PROPERTY(QString blendEquationA READ getBlendEquationA CONSTANT) + Q_PROPERTY(QString blendSFactorRGB READ getBlendSFactorRGB CONSTANT) + Q_PROPERTY(QString blendSFactorA READ getBlendSFactorA CONSTANT) + Q_PROPERTY(QString blendDFactorRGB READ getBlendDFactorRGB CONSTANT) + Q_PROPERTY(QString blendDFactorA READ getBlendDFactorA CONSTANT) + Q_PROPERTY(bool lineSmoothEnabled READ line_smooth_enabled CONSTANT) + Q_PROPERTY(bool polySmoothEnabled READ line_smooth_enabled CONSTANT) + Q_PROPERTY(bool polyOffsetPoint READ poly_offset_point_enabled CONSTANT) + Q_PROPERTY(bool polyOffsetLine READ poly_offset_line_enabled CONSTANT) + Q_PROPERTY(bool polyOffsetFill READ poly_offset_fill_enabled CONSTANT) + Q_PROPERTY(float polyOffsetScale READ poly_offset_scale CONSTANT) + Q_PROPERTY(float polyOffsetBias READ poly_offset_bias CONSTANT) + Q_PROPERTY(quint16 alphaRef READ alpha_ref CONSTANT) + + Q_PROPERTY(QString name READ getName CONSTANT) + Q_PROPERTY(QString transformProgram READ getTransformProgram CONSTANT) + Q_PROPERTY(QString shaderProgram READ getShaderProgram CONSTANT) + + +public: + QString _name; + QString _transform_program; + QString _shader_program; + QVariantList _index_list; + + QString getName() const + { + return _name; + } + + QString getTransformProgram() const + { + return _transform_program; + } + + QString getShaderProgram() const + { + return _shader_program; + } + + quint16 getSurfaceWidth() const + { + return 1 << surface_log2_width(); + } + + quint16 getSurfaceHeight() const + { + return 1 << surface_log2_height(); + } + + QVariantList getIndexList() const + { + return _index_list; + } + + QString getDepthFunc() const + { + return QString::fromStdString(rsx::to_string(depth_func())); + } + + QString getAlphaFunc() const + { + return QString::fromStdString(rsx::to_string(alpha_func())); + } + + QString getLogicFunc() const + { + return QString::fromStdString(rsx::to_string(logic_operation())); + } + + QString getBlendEquationRGB() const + { + return QString::fromStdString(rsx::to_string(blend_equation_rgb())); + } + + QString getBlendEquationA() const + { + return QString::fromStdString(rsx::to_string(blend_equation_a())); + } + + QString getBlendSFactorRGB() const + { + return QString::fromStdString(rsx::to_string(blend_func_sfactor_rgb())); + } + + QString getBlendSFactorA() const + { + return QString::fromStdString(rsx::to_string(blend_func_sfactor_a())); + } + + QString getBlendDFactorRGB() const + { + return QString::fromStdString(rsx::to_string(blend_func_dfactor_rgb())); + } + + QString getBlendDFactorA() const + { + return QString::fromStdString(rsx::to_string(blend_func_dfactor_a())); + } + + QString getSurfaceTarget() const + { + return QString::fromStdString(rsx::to_string(surface_color_target())); + } + + QString getSurfaceColorFormat() const + { + return QString::fromStdString(rsx::to_string(surface_color())); + } + + QString getSurfaceDepthStencilFormat() const + { + return QString::fromStdString(rsx::to_string(surface_depth_fmt())); + } + + qt_rsx_state& operator=(const rsx::rsx_state& in) + { + rsx::rsx_state::operator =(in); + return *this; + } +}; + +#endif // STATE_H