From 8bfd32e8549928061f30c37d34e712c1a0294f4c Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Mon, 19 May 2014 20:48:14 -0700 Subject: [PATCH 01/29] * Remove -fpermissive --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 114e39207..1c7d98347 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.6) project(citra) -SET(CXX_COMPILE_FLAGS "-std=c++11 -fpermissive") +SET(CXX_COMPILE_FLAGS "-std=c++11") # silence some spam add_definitions(-Wno-attributes) From f3bf03caf843d3caa917648bc8b4887295b701fa Mon Sep 17 00:00:00 2001 From: archshift Date: Tue, 20 May 2014 14:52:02 -0700 Subject: [PATCH 02/29] Added CONTRIBUTING.md with contents from Coding Style, updated README link --- CONTRIBUTING.md | 107 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 +- 2 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..74c84b002 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,107 @@ +# Contributing + +Citra is a brand new project, so we have a great opportunity to keep things clean and well organized early on. As such, coding style is very important when making commits. They aren't very strict rules since we want to be flexible and we understand that under certain circumstances some of them can be counterproductive. Just try to follow as many of them as possible: + +### General Rules +* A lot of code was taken from other projects (e.g. Dolphin, PPSSPP, Gekko, SkyEye). In general, when editing other people's code, follow the style of the module you're in (or better yet, fix the style if it drastically differs from our guide). +* Line width is typically 100 characters, but this isn't strictly enforced. Please do not use 80-characters. +* Don't ever introduce new external dependencies into Core +* Don't use any platform specific code in Core +* Use namespaces often + +### Naming Rules +* Functions + * CamelCase, "_" may also be used for clarity (e.g. ARM_InitCore) +* Variables + * lower_case_underscored + * Prefix "g_" if global + * Prefix "_" if internal + * Prefix "__" if ultra internal +* Classes + * CamelCase, "_" may also be used for clarity (e.g. OGL_VideoInterface) +* Files/Folders + * lower_case_underscored +* Namespaces + * CamelCase, "_" may also be used for clarity (e.g. ARM_InitCore) + +### Indentation/Whitespace Style +Follow the indentation/whitespace style shown below. Do not use tabs, use 4-spaces instead. + +```cpp +namespace Example { + +// Namespace contents are not indented + +// Declare globals at the top +int g_foo = 0; +char* g_some_pointer; // Notice the position of the * + +enum SomeEnum { + COLOR_RED, + COLOR_GREEN, + COLOR_BLUE +}; + +struct Position { + int x, y; +}; + +// Use "typename" rather than "class" here, just to be consistent +template +void FooBar() { + int some_array[] = { + 5, + 25, + 7, + 42 + }; + + if (note == the_space_after_the_if) { + CallAfunction(); + } else { + // Use a space after the // when commenting + } + + // Comment directly above code when possible + if (some_condition) single_statement(); + + // Place a single space after the for loop semicolons + for (int i = 0; i != 25; ++i) { + // This is how we write loops + } + + DoStuff(this, function, call, takes, up, multiple, + lines, like, this); + + if (this || condition_takes_up_multiple && + lines && like && this || everything || + alright || then) { + } + + switch (var) { + // No indentation for case label + case 1: { + int case_var = var + 3; + DoSomething(case_var); + break; + } + case 3: + DoSomething(var); + return; + // Always break, even after a return + break; + + default: + // Yes, even break for the last case + break; + } + + std::vector + you_can_declare, + a_few, + variables, + like_this; +} + +} +``` diff --git a/README.md b/README.md index 79de09d98..e9bd8967e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ For development discussion, please join us @ #citra on [freenode](http://webchat ### Development -If you want to contribute please take a took at the [Coding Style](https://github.com/citra-emu/citra/wiki/Coding-Style), [Roadmap](https://github.com/citra-emu/citra/wiki/Roadmap) and [Developer Information](https://github.com/citra-emu/citra/wiki/Developer-Information) pages. You should as well contact any of the developers in the forum in order to know about the current state of the emulator. +If you want to contribute please take a took at the [Contributor's Guide](CONTRIBUTING.md), [Roadmap](https://github.com/citra-emu/citra/wiki/Roadmap) and [Developer Information](https://github.com/citra-emu/citra/wiki/Developer-Information) pages. You should as well contact any of the developers in the forum in order to know about the current state of the emulator. ### Building From 420b0ba31bb6f9f2d161d148c055dd5804d54f07 Mon Sep 17 00:00:00 2001 From: archshift Date: Tue, 20 May 2014 15:08:27 -0700 Subject: [PATCH 03/29] CONTRIBUTING: Fix some examples, escape underscores --- CONTRIBUTING.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 74c84b002..49742e4e0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,18 +11,18 @@ Citra is a brand new project, so we have a great opportunity to keep things clea ### Naming Rules * Functions - * CamelCase, "_" may also be used for clarity (e.g. ARM_InitCore) + * CamelCase, `_` may also be used for clarity (e.g. `ARM_InitCore`) * Variables - * lower_case_underscored - * Prefix "g_" if global - * Prefix "_" if internal - * Prefix "__" if ultra internal + * lower\_case\_underscored + * Prefix `g_` if global + * Prefix `_` if internal + * Prefix `__` if ultra internal * Classes - * CamelCase, "_" may also be used for clarity (e.g. OGL_VideoInterface) + * CamelCase, `_` may also be used for clarity (e.g. `OGL_VideoInterface`) * Files/Folders - * lower_case_underscored + * lower\_case\_underscored * Namespaces - * CamelCase, "_" may also be used for clarity (e.g. ARM_InitCore) + * CamelCase, `_` may also be used for clarity (e.g. `ARM_InitCore`) ### Indentation/Whitespace Style Follow the indentation/whitespace style shown below. Do not use tabs, use 4-spaces instead. @@ -96,7 +96,7 @@ void FooBar() { break; } - std::vector + std::string you_can_declare, a_few, variables, From 85f31fdfc5f23b9e16c488087ee09112375daa68 Mon Sep 17 00:00:00 2001 From: inspuration Date: Thu, 29 May 2014 01:27:59 -0400 Subject: [PATCH 04/29] Added syscall GetSystemTick, Added User_Input --- src/common/log.h | 1 + src/common/log_manager.cpp | 1 + src/core/core.vcxproj | 2 ++ src/core/core.vcxproj.filters | 6 ++++ src/core/hle/function_wrappers.h | 7 +++++ src/core/hle/svc.cpp | 6 +++- src/core/hw/hw.cpp | 4 +++ src/core/hw/user_input.cpp | 46 ++++++++++++++++++++++++++++ src/core/hw/user_input.h | 52 ++++++++++++++++++++++++++++++++ 9 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 src/core/hw/user_input.cpp create mode 100644 src/core/hw/user_input.h diff --git a/src/common/log.h b/src/common/log.h index 8b39b03a1..4d35e2c8f 100644 --- a/src/common/log.h +++ b/src/common/log.h @@ -64,6 +64,7 @@ enum LOG_TYPE { HW, TIME, NETPLAY, + USER_INPUT, NUMBER_OF_LOGS // Must be last }; diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp index 146472888..17ca9b08b 100644 --- a/src/common/log_manager.cpp +++ b/src/common/log_manager.cpp @@ -73,6 +73,7 @@ LogManager::LogManager() m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay"); m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager"); m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay"); + m_Log[LogTypes::USER_INPUT] = new LogContainer("USER_INPUT", "User Input"); m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str()); m_consoleLog = new ConsoleListener(); diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index f271d336e..2f964bc9e 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -180,6 +180,7 @@ + @@ -229,6 +230,7 @@ + diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index b6c1d5b93..f56264b50 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -165,6 +165,9 @@ arm\interpreter + + hw + @@ -295,6 +298,9 @@ hle\kernel + + hw + diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index 801865d49..fa690ef92 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h @@ -743,3 +743,10 @@ template void WrapI_VVUUS64() { int retval = func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2), PARAM(3), PARAM(4)); RETURN(retval); } + + +//64 bit wrappers + +template void WrapU64_V() { + RETURN(func()); +} \ No newline at end of file diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 90c05cb74..094e003c4 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -226,6 +226,10 @@ Result CreateEvent(void* _event, u32 reset_type) { return 0; } +u64 GetSystemTick(void) { + return Core::g_sys_core->GetTicks(); +} + const HLE::FunctionDef SVC_Table[] = { {0x00, NULL, "Unknown"}, {0x01, WrapI_VUUUUU, "ControlMemory"}, @@ -267,7 +271,7 @@ const HLE::FunctionDef SVC_Table[] = { {0x25, WrapI_VVUUS64, "WaitSynchronizationN"}, {0x26, NULL, "SignalAndWait"}, {0x27, NULL, "DuplicateHandle"}, - {0x28, NULL, "GetSystemTick"}, + { 0x28, WrapU64_V, "GetSystemTick" }, {0x29, NULL, "GetHandleInfo"}, {0x2A, NULL, "GetSystemInfo"}, {0x2B, NULL, "GetProcessInfo"}, diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp index 85669ae7f..9b4fcf0cb 100644 --- a/src/core/hw/hw.cpp +++ b/src/core/hw/hw.cpp @@ -8,6 +8,8 @@ #include "core/hw/hw.h" #include "core/hw/lcd.h" #include "core/hw/ndma.h" +#include "core/hw/user_input.h" + namespace HW { @@ -89,12 +91,14 @@ template void Write(u32 addr, const u8 data); void Update() { LCD::Update(); NDMA::Update(); + USER_INPUT::Update(); } /// Initialize hardware void Init() { LCD::Init(); NDMA::Init(); + USER_INPUT::Init(); NOTICE_LOG(HW, "initialized OK"); } diff --git a/src/core/hw/user_input.cpp b/src/core/hw/user_input.cpp new file mode 100644 index 000000000..eee52d096 --- /dev/null +++ b/src/core/hw/user_input.cpp @@ -0,0 +1,46 @@ +#include "user_input.h" + + +namespace USER_INPUT { + + template + inline void Read(T &var, const u32 addr) { + ERROR_LOG(USER_INPUT, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); + } + + template + inline void Write(u32 addr, const T data) { + ERROR_LOG(NDMA, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); + } + + // Explicitly instantiate template functions because we aren't defining this in the header: + + template void Read(u64 &var, const u32 addr); + template void Read(u32 &var, const u32 addr); + template void Read(u16 &var, const u32 addr); + template void Read(u8 &var, const u32 addr); + + template void Write(u32 addr, const u64 data); + template void Write(u32 addr, const u32 data); + template void Write(u32 addr, const u16 data); + template void Write(u32 addr, const u8 data); + + void setButtonReg(u32 buttonData) { + Write(PADDR_BUTTONS, buttonData); + } + + /// Update hardware + void Update() { + } + + /// Initialize hardware + void Init() { + NOTICE_LOG(USER_INPUT, "initialized OK"); + } + + /// Shutdown hardware + void Shutdown() { + NOTICE_LOG(USER_INPUT, "shutdown OK"); + } + +} \ No newline at end of file diff --git a/src/core/hw/user_input.h b/src/core/hw/user_input.h new file mode 100644 index 000000000..f89f9dc85 --- /dev/null +++ b/src/core/hw/user_input.h @@ -0,0 +1,52 @@ +#pragma once + +#include "common/common_types.h" + + +namespace USER_INPUT { + struct Registers { + u32 buttons; + //u32 pad1; etc... + }; + + extern Registers g_regs; + + enum { + + PAD_A = (1 << 0), + PAD_B = (1 << 1), + PAD_SELECT = (1 << 2), + PAD_START = (1 << 3), + PAD_RIGHT = (1 << 4), + PAD_LEFT = (1 << 5), + PAD_UP = (1 << 6), + PAD_DOWN = (1 << 7), + PAD_R = (1 << 8), + PAD_L = (1 << 9), + PAD_X = (1 << 10), + PAD_Y = (1 << 11), + + PADDR_BUTTONS = 0x1000001c, //TODO: it works using the shared mem mapping with all homebrew tested, however the wiki states 0x10146000 as the paddr + }; + + + enum { + REG_BUTTONS = 0x1EC46000 //does not work due to confusion between shared mem and hardware IO + }; + + template + inline void Read(T &var, const u32 addr); + + template + inline void Write(u32 addr, const T data); + + /// Update hardware + void Update(); + + /// Initialize hardware + void Init(); + + /// Shutdown hardware + void Shutdown(); +} + From 4865be9cef3de9c366ef0769820b933a75f59d97 Mon Sep 17 00:00:00 2001 From: inspuration Date: Thu, 29 May 2014 01:59:09 -0400 Subject: [PATCH 05/29] Working WASD in citra_qt --- src/citra_qt/bootmanager.cpp | 41 ++++++++++++++++++++++++++++++++++++ src/core/hw/user_input.cpp | 4 ++-- src/core/hw/user_input.h | 3 +++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index f85116419..8c5451c08 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -7,6 +7,7 @@ #include "core/core.h" #include "core/loader.h" #include "core/hw/hw.h" +#include "core/hw/user_input.h" #include "video_core/video_core.h" @@ -119,6 +120,8 @@ GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this setLayout(layout); BackupGeometry(); + + buttonReg = 0x0; } GRenderWindow::~GRenderWindow() @@ -198,6 +201,25 @@ void GRenderWindow::keyPressEvent(QKeyEvent* event) if (!key_processed) QWidget::keyPressEvent(event); */ + + + if (event->key() == Qt::Key_W) + { + buttonReg |= USER_INPUT::PAD_UP; + } + else if (event->key() == Qt::Key_A) + { + buttonReg |= USER_INPUT::PAD_LEFT; + } + else if (event->key() == Qt::Key_S) + { + buttonReg |= USER_INPUT::PAD_DOWN; + } + else if (event->key() == Qt::Key_D) + { + buttonReg |= USER_INPUT::PAD_RIGHT; + } + USER_INPUT::setButtonReg(buttonReg); } void GRenderWindow::keyReleaseEvent(QKeyEvent* event) @@ -211,4 +233,23 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) if (!key_processed) QWidget::keyPressEvent(event); */ + + + if (event->key() == Qt::Key_W) + { + buttonReg &= 0xffffffff ^ USER_INPUT::PAD_UP; + } + else if (event->key() == Qt::Key_A) + { + buttonReg &= 0xffffffff ^ USER_INPUT::PAD_LEFT; + } + else if (event->key() == Qt::Key_S) + { + buttonReg &= 0xffffffff ^ USER_INPUT::PAD_DOWN; + } + else if (event->key() == Qt::Key_D) + { + buttonReg &= 0xffffffff ^ USER_INPUT::PAD_RIGHT; + } + USER_INPUT::setButtonReg(buttonReg); } \ No newline at end of file diff --git a/src/core/hw/user_input.cpp b/src/core/hw/user_input.cpp index eee52d096..5cc5c4479 100644 --- a/src/core/hw/user_input.cpp +++ b/src/core/hw/user_input.cpp @@ -10,7 +10,7 @@ namespace USER_INPUT { template inline void Write(u32 addr, const T data) { - ERROR_LOG(NDMA, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); + ERROR_LOG(USER_INPUT, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); } // Explicitly instantiate template functions because we aren't defining this in the header: @@ -26,7 +26,7 @@ namespace USER_INPUT { template void Write(u32 addr, const u8 data); void setButtonReg(u32 buttonData) { - Write(PADDR_BUTTONS, buttonData); + Memory::Write32(PADDR_BUTTONS, buttonData); } /// Update hardware diff --git a/src/core/hw/user_input.h b/src/core/hw/user_input.h index f89f9dc85..b21da5815 100644 --- a/src/core/hw/user_input.h +++ b/src/core/hw/user_input.h @@ -1,6 +1,7 @@ #pragma once #include "common/common_types.h" +#include "core\mem_map.h" namespace USER_INPUT { @@ -40,6 +41,8 @@ namespace USER_INPUT { template inline void Write(u32 addr, const T data); + void setButtonReg(u32 buttonData); + /// Update hardware void Update(); From daf2bace252364d8ee31e36fea90c07c16daceff Mon Sep 17 00:00:00 2001 From: inspuration Date: Thu, 29 May 2014 02:36:19 -0400 Subject: [PATCH 06/29] Fixed a file that was not committed --- src/citra_qt/bootmanager.hxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/citra_qt/bootmanager.hxx b/src/citra_qt/bootmanager.hxx index 1001e1ee4..efbed6b7c 100644 --- a/src/citra_qt/bootmanager.hxx +++ b/src/citra_qt/bootmanager.hxx @@ -109,4 +109,6 @@ private: EmuThread emu_thread; QByteArray geometry; + + u32 buttonReg; }; From 5dc4223a628c25e9158bc9aad736a2e6fc375541 Mon Sep 17 00:00:00 2001 From: inspuration Date: Thu, 29 May 2014 12:06:45 -0400 Subject: [PATCH 07/29] Untabified previous commits, Added preliminary binding support in citra_qt, renamed USER_INPUT to HID --- src/citra_qt/bootmanager.cpp | 52 ++++------------ src/citra_qt/bootmanager.hxx | 3 +- src/citra_qt/citra_qt.vcxproj | 3 + src/citra_qt/citra_qt.vcxproj.filters | 3 + src/citra_qt/key_bindings.cpp | 78 +++++++++++++++++++++++ src/citra_qt/key_bindings.hxx | 50 +++++++++++++++ src/citra_qt/key_bindings.ui | 89 +++++++++++++++++++++++++++ src/citra_qt/main.cpp | 19 +++++- src/citra_qt/main.hxx | 1 + src/citra_qt/main.ui | 6 ++ src/citra_qt/ui_key_bindings.h | 77 +++++++++++++++++++++++ src/common/log.h | 2 +- src/common/log_manager.cpp | 2 +- src/core/core.vcxproj | 5 +- src/core/core.vcxproj.filters | 4 +- src/core/hle/function_wrappers.h | 2 +- src/core/hle/svc.cpp | 4 +- src/core/hw/hid.cpp | 34 ++++++++++ src/core/hw/hid.h | 73 ++++++++++++++++++++++ src/core/hw/hw.cpp | 6 +- src/core/hw/user_input.cpp | 46 -------------- src/core/hw/user_input.h | 55 ----------------- 22 files changed, 459 insertions(+), 155 deletions(-) create mode 100644 src/citra_qt/key_bindings.cpp create mode 100644 src/citra_qt/key_bindings.hxx create mode 100644 src/citra_qt/key_bindings.ui create mode 100644 src/citra_qt/ui_key_bindings.h create mode 100644 src/core/hw/hid.cpp create mode 100644 src/core/hw/hid.h delete mode 100644 src/core/hw/user_input.cpp delete mode 100644 src/core/hw/user_input.h diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 8c5451c08..ba8a71bbf 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -3,11 +3,13 @@ #include "common/common.h" #include "bootmanager.hxx" +#include "key_bindings.hxx" + #include "core/core.h" #include "core/loader.h" #include "core/hw/hw.h" -#include "core/hw/user_input.h" +#include "core/hw/hid.h" #include "video_core/video_core.h" @@ -121,7 +123,7 @@ GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this BackupGeometry(); - buttonReg = 0x0; + buttonReg = 0x0; } GRenderWindow::~GRenderWindow() @@ -195,31 +197,17 @@ void GRenderWindow::keyPressEvent(QKeyEvent* event) /* bool key_processed = false; for (unsigned int channel = 0; channel < 4 && controller_interface(); ++channel) - if (controller_interface()->SetControllerStatus(channel, event->key(), input_common::GCController::PRESSED)) - key_processed = true; + if (controller_interface()->SetControllerStatus(channel, event->key(), input_common::GCController::PRESSED)) + key_processed = true; if (!key_processed) - QWidget::keyPressEvent(event); + QWidget::keyPressEvent(event); */ - if (event->key() == Qt::Key_W) - { - buttonReg |= USER_INPUT::PAD_UP; - } - else if (event->key() == Qt::Key_A) - { - buttonReg |= USER_INPUT::PAD_LEFT; - } - else if (event->key() == Qt::Key_S) - { - buttonReg |= USER_INPUT::PAD_DOWN; - } - else if (event->key() == Qt::Key_D) - { - buttonReg |= USER_INPUT::PAD_RIGHT; - } - USER_INPUT::setButtonReg(buttonReg); + buttonReg |= GetKeyBinding(event); + HID::setButtonReg(buttonReg); + return; } void GRenderWindow::keyReleaseEvent(QKeyEvent* event) @@ -234,22 +222,6 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) QWidget::keyPressEvent(event); */ - - if (event->key() == Qt::Key_W) - { - buttonReg &= 0xffffffff ^ USER_INPUT::PAD_UP; - } - else if (event->key() == Qt::Key_A) - { - buttonReg &= 0xffffffff ^ USER_INPUT::PAD_LEFT; - } - else if (event->key() == Qt::Key_S) - { - buttonReg &= 0xffffffff ^ USER_INPUT::PAD_DOWN; - } - else if (event->key() == Qt::Key_D) - { - buttonReg &= 0xffffffff ^ USER_INPUT::PAD_RIGHT; - } - USER_INPUT::setButtonReg(buttonReg); + buttonReg &= 0xffffffff ^ GetKeyBinding(event); + HID::setButtonReg(buttonReg); } \ No newline at end of file diff --git a/src/citra_qt/bootmanager.hxx b/src/citra_qt/bootmanager.hxx index efbed6b7c..84216cf2a 100644 --- a/src/citra_qt/bootmanager.hxx +++ b/src/citra_qt/bootmanager.hxx @@ -1,5 +1,6 @@ #include #include +#include #include "common/common.h" #include "common/emu_window.h" @@ -110,5 +111,5 @@ private: QByteArray geometry; - u32 buttonReg; + u32 buttonReg; }; diff --git a/src/citra_qt/citra_qt.vcxproj b/src/citra_qt/citra_qt.vcxproj index 3f24bbfbf..c841bab3e 100644 --- a/src/citra_qt/citra_qt.vcxproj +++ b/src/citra_qt/citra_qt.vcxproj @@ -135,6 +135,7 @@ + @@ -148,6 +149,7 @@ + @@ -173,6 +175,7 @@ + diff --git a/src/citra_qt/citra_qt.vcxproj.filters b/src/citra_qt/citra_qt.vcxproj.filters index 2b3838e29..7d4e365a4 100644 --- a/src/citra_qt/citra_qt.vcxproj.filters +++ b/src/citra_qt/citra_qt.vcxproj.filters @@ -45,6 +45,7 @@ debugger + @@ -74,6 +75,7 @@ debugger + @@ -102,6 +104,7 @@ debugger + diff --git a/src/citra_qt/key_bindings.cpp b/src/citra_qt/key_bindings.cpp new file mode 100644 index 000000000..6cd0db86d --- /dev/null +++ b/src/citra_qt/key_bindings.cpp @@ -0,0 +1,78 @@ +#include +#include +#include +#include "key_bindings.hxx" +#include +#include "core/hw/hid.h" + +typedef std::map BindingsMap; + +BindingsMap bindings; + +std::map nameMap; + +void SaveKeyBindings(QSettings& settings) +{ + settings.beginGroup("KeyBindings"); + + for (BindingsMap::iterator group = bindings.begin(); group != bindings.end(); ++group) + { + settings.setValue(group->first.toString(), group->second); + settings.endGroup(); + } + settings.endGroup(); +} + +void LoadKeyBindings(QSettings& settings) +{ + settings.beginGroup("KeyBindings"); + + // Make sure NOT to use a reference here because it would become invalid once we call beginGroup() + QStringList keys = settings.allKeys(); + for (QList::iterator key = keys.begin(); key != keys.end(); ++key) + { + settings.beginGroup(*key); + QKeySequence keyseq = QKeySequence::fromString(settings.value("").toString()); + } + + settings.endGroup(); +} + +HID::PAD GetKeyBinding(QKeyEvent * event) +{ + QKeySequence keySeq = QKeySequence(event->text()); + return bindings[keySeq]; +} + +void RegisterKeyBinding(const QKeySequence keySeq, const HID::PAD pad) +{ + bindings[keySeq] = pad; +} + +void createNameMap() { + for (int i = 0; i < HID::numPadItems; i++){ + nameMap[(HID::PAD)(1 << i)] = QString(HID::PAD_NAMES[i]); + } + +} + +GKeyBindingsDialog::GKeyBindingsDialog(QWidget* parent) : QDialog(parent) +{ + ui.setupUi(this); + + createNameMap(); + + for (BindingsMap::iterator key = bindings.begin(); key != bindings.end(); ++key) + { + QStringList columns; + columns << key->first.toString() << nameMap[key->second]; + QTreeWidgetItem* item = new QTreeWidgetItem(columns); + ui.treeWidget->addTopLevelItem(item); + + } + // TODO: Make context configurable as well (hiding the column for now) + ui.treeWidget->setColumnCount(2); + + ui.treeWidget->resizeColumnToContents(0); + ui.treeWidget->resizeColumnToContents(1); +} diff --git a/src/citra_qt/key_bindings.hxx b/src/citra_qt/key_bindings.hxx new file mode 100644 index 000000000..166bca245 --- /dev/null +++ b/src/citra_qt/key_bindings.hxx @@ -0,0 +1,50 @@ +#include +#include "ui_key_bindings.h" +#include "core/hw/hid.h" + + + +class QSettings; + +/** + * Register a hotkey. + * + * @param key Keyboard button + * @param pad Name of the pad + */ + +void RegisterKeyBinding(const QKeySequence keySeq, const HID::PAD pad); + + +/** + * Saves all key bindings to the settings file. + * + * + */ +void SaveKeyBindings(QSettings& settings); + + +/** +* Get PAD associated with key event +* +* +*/ +HID::PAD GetKeyBinding(QKeyEvent * event); + +/** + * Loads key bindings from the settings file. + * + * + */ +void LoadKeyBindings(QSettings& settings); + +class GKeyBindingsDialog : public QDialog +{ + Q_OBJECT + +public: + GKeyBindingsDialog(QWidget* parent = NULL); + +private: + Ui::key_bindings ui; +}; diff --git a/src/citra_qt/key_bindings.ui b/src/citra_qt/key_bindings.ui new file mode 100644 index 000000000..0b97ec7d7 --- /dev/null +++ b/src/citra_qt/key_bindings.ui @@ -0,0 +1,89 @@ + + + key_bindings + + + + 0 + 0 + 363 + 388 + + + + Key Bindings + + + + + + QAbstractItemView::SelectItems + + + false + + + + Action + + + + + Key + + + + + Pad + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset + + + + + + + + + buttonBox + accepted() + key_bindings + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + key_bindings + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 9be982909..556e9015a 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -13,6 +13,7 @@ #include "bootmanager.hxx" #include "hotkeys.hxx" +#include "key_bindings.hxx" //debugger #include "debugger/disassembler.hxx" @@ -80,7 +81,8 @@ GMainWindow::GMainWindow() connect(ui.action_Pause, SIGNAL(triggered()), this, SLOT(OnPauseGame())); connect(ui.action_Stop, SIGNAL(triggered()), this, SLOT(OnStopGame())); connect(ui.action_Popout_Window_Mode, SIGNAL(triggered(bool)), this, SLOT(ToggleWindowMode())); - connect(ui.action_Hotkeys, SIGNAL(triggered()), this, SLOT(OnOpenHotkeysDialog())); + connect(ui.action_Hotkeys, SIGNAL(triggered()), this, SLOT(OnOpenHotkeysDialog()));\ + connect(ui.action_Key_Bindings, SIGNAL(triggered()), this, SLOT(OnOpenKeyBindingsDialog())); // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views before the CPU continues connect(&render_window->GetEmuThread(), SIGNAL(CPUStepped()), disasmWidget, SLOT(OnCPUStepped()), Qt::BlockingQueuedConnection); @@ -95,6 +97,14 @@ GMainWindow::GMainWindow() connect(GetHotkey("Main Window", "Load File", this), SIGNAL(activated()), this, SLOT(OnMenuLoadFile())); connect(GetHotkey("Main Window", "Start Emulation", this), SIGNAL(activated()), this, SLOT(OnStartGame())); + // Setup key bindings + RegisterKeyBinding(QKeySequence("W"), HID::PAD::PAD_UP); + RegisterKeyBinding(QKeySequence("A"), HID::PAD::PAD_LEFT); + RegisterKeyBinding(QKeySequence("S"), HID::PAD::PAD_DOWN); + RegisterKeyBinding(QKeySequence("D"), HID::PAD::PAD_RIGHT); + LoadKeyBindings(settings); + + setWindowTitle(render_window->GetWindowTitle().c_str()); show(); @@ -187,6 +197,13 @@ void GMainWindow::OnOpenHotkeysDialog() } +void GMainWindow::OnOpenKeyBindingsDialog() +{ + GKeyBindingsDialog dialog(this); + dialog.exec(); +} + + void GMainWindow::ToggleWindowMode() { bool enable = ui.action_Popout_Window_Mode->isChecked(); diff --git a/src/citra_qt/main.hxx b/src/citra_qt/main.hxx index fa122f76e..f6a5043c5 100644 --- a/src/citra_qt/main.hxx +++ b/src/citra_qt/main.hxx @@ -39,6 +39,7 @@ private slots: void OnMenuLoadFile(); void OnMenuLoadSymbolMap(); void OnOpenHotkeysDialog(); + void OnOpenKeyBindingsDialog(); void OnConfigure(); void ToggleWindowMode(); diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui index f3596716f..52372ed8f 100644 --- a/src/citra_qt/main.ui +++ b/src/citra_qt/main.ui @@ -53,6 +53,7 @@ + @@ -127,6 +128,11 @@ Configure &Hotkeys ... + + + Set Key Bindings + + Configure ... diff --git a/src/citra_qt/ui_key_bindings.h b/src/citra_qt/ui_key_bindings.h new file mode 100644 index 000000000..7e1a88946 --- /dev/null +++ b/src/citra_qt/ui_key_bindings.h @@ -0,0 +1,77 @@ +/******************************************************************************** +** Form generated from reading UI file 'key_bindings.ui' +** +** Created by: Qt User Interface Compiler version 4.8.6 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_KEY_BINDINGS_H +#define UI_KEY_BINDINGS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Ui_key_bindings +{ +public: + QVBoxLayout *verticalLayout; + QTreeWidget *treeWidget; + QDialogButtonBox *buttonBox; + + void setupUi(QDialog *key_bindings) + { + if (key_bindings->objectName().isEmpty()) + key_bindings->setObjectName(QString::fromUtf8("key_bindings")); + key_bindings->resize(363, 388); + verticalLayout = new QVBoxLayout(key_bindings); + verticalLayout->setObjectName(QString::fromUtf8("verticalLayout")); + treeWidget = new QTreeWidget(key_bindings); + treeWidget->setObjectName(QString::fromUtf8("treeWidget")); + treeWidget->setSelectionBehavior(QAbstractItemView::SelectItems); + treeWidget->setHeaderHidden(false); + + verticalLayout->addWidget(treeWidget); + + buttonBox = new QDialogButtonBox(key_bindings); + buttonBox->setObjectName(QString::fromUtf8("buttonBox")); + buttonBox->setOrientation(Qt::Horizontal); + buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset); + + verticalLayout->addWidget(buttonBox); + + + retranslateUi(key_bindings); + QObject::connect(buttonBox, SIGNAL(accepted()), key_bindings, SLOT(accept())); + QObject::connect(buttonBox, SIGNAL(rejected()), key_bindings, SLOT(reject())); + + QMetaObject::connectSlotsByName(key_bindings); + } // setupUi + + void retranslateUi(QDialog *key_bindings) + { + key_bindings->setWindowTitle(QApplication::translate("key_bindings", "Key Bindings", 0, QApplication::UnicodeUTF8)); + QTreeWidgetItem *___qtreewidgetitem = treeWidget->headerItem(); + ___qtreewidgetitem->setText(2, QApplication::translate("key_bindings", "Pad", 0, QApplication::UnicodeUTF8)); + ___qtreewidgetitem->setText(1, QApplication::translate("key_bindings", "Key", 0, QApplication::UnicodeUTF8)); + ___qtreewidgetitem->setText(0, QApplication::translate("key_bindings", "Action", 0, QApplication::UnicodeUTF8)); + } // retranslateUi + +}; + +namespace Ui { + class key_bindings: public Ui_key_bindings {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_KEY_BINDINGS_H diff --git a/src/common/log.h b/src/common/log.h index 4d35e2c8f..691a4fba3 100644 --- a/src/common/log.h +++ b/src/common/log.h @@ -64,7 +64,7 @@ enum LOG_TYPE { HW, TIME, NETPLAY, - USER_INPUT, + HID, NUMBER_OF_LOGS // Must be last }; diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp index 17ca9b08b..5b2ef874f 100644 --- a/src/common/log_manager.cpp +++ b/src/common/log_manager.cpp @@ -73,7 +73,7 @@ LogManager::LogManager() m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay"); m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager"); m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay"); - m_Log[LogTypes::USER_INPUT] = new LogContainer("USER_INPUT", "User Input"); + m_Log[LogTypes::HID] = new LogContainer("HID", "Human Interface Devices"); m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str()); m_consoleLog = new ConsoleListener(); diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index 2f964bc9e..ef621b1e8 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -120,6 +120,7 @@ Fast false StreamingSIMDExtensions2 + $(IntDir)%(RelativeDir) @@ -180,7 +181,7 @@ - + @@ -230,7 +231,7 @@ - + diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index f56264b50..3cf702d44 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -165,7 +165,7 @@ arm\interpreter - + hw @@ -298,7 +298,7 @@ hle\kernel - + hw diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index fa690ef92..87d397448 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h @@ -748,5 +748,5 @@ template void WrapI_VVUUS64() { //64 bit wrappers template void WrapU64_V() { - RETURN(func()); + RETURN(func()); } \ No newline at end of file diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 094e003c4..870e87e17 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -227,7 +227,7 @@ Result CreateEvent(void* _event, u32 reset_type) { } u64 GetSystemTick(void) { - return Core::g_sys_core->GetTicks(); + return Core::g_sys_core->GetTicks(); } const HLE::FunctionDef SVC_Table[] = { @@ -271,7 +271,7 @@ const HLE::FunctionDef SVC_Table[] = { {0x25, WrapI_VVUUS64, "WaitSynchronizationN"}, {0x26, NULL, "SignalAndWait"}, {0x27, NULL, "DuplicateHandle"}, - { 0x28, WrapU64_V, "GetSystemTick" }, + { 0x28, WrapU64_V, "GetSystemTick" }, {0x29, NULL, "GetHandleInfo"}, {0x2A, NULL, "GetSystemInfo"}, {0x2B, NULL, "GetProcessInfo"}, diff --git a/src/core/hw/hid.cpp b/src/core/hw/hid.cpp new file mode 100644 index 000000000..9f4867e31 --- /dev/null +++ b/src/core/hw/hid.cpp @@ -0,0 +1,34 @@ +#include "hid.h" + + +namespace HID { + + template + inline void Read(T &var, const u32 addr) { + ERROR_LOG(HID, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); + } + + template + inline void Write(u32 addr, const T data) { + ERROR_LOG(HID, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); + } + + void setButtonReg(u32 buttonData) { + Memory::Write32(PADDR_BUTTONS, buttonData); + } + + /// Update hardware + void Update() { + } + + /// Initialize hardware + void Init() { + NOTICE_LOG(HID, "initialized OK"); + } + + /// Shutdown hardware + void Shutdown() { + NOTICE_LOG(HID, "shutdown OK"); + } + +} \ No newline at end of file diff --git a/src/core/hw/hid.h b/src/core/hw/hid.h new file mode 100644 index 000000000..524b48cca --- /dev/null +++ b/src/core/hw/hid.h @@ -0,0 +1,73 @@ +#pragma once + +#include "common/common_types.h" +#include "core\mem_map.h" + + +namespace HID { + struct Registers { + u32 buttons; + //u32 pad1; etc... + }; + + extern Registers g_regs; + + enum { + PADDR_BUTTONS = 0x1000001c, //TODO: it works using the shared mem mapping with all homebrew tested, however the wiki states 0x10146000 as the paddr + }; + + + enum { + REG_BUTTONS = 0x1EC46000 //does not work due to confusion between shared mem and hardware IO + }; + + const int numPadItems = 12; // figure out a better way :( + + enum PAD { + PAD_A = (1 << 0), + PAD_B = (1 << 1), + PAD_SELECT = (1 << 2), + PAD_START = (1 << 3), + PAD_RIGHT = (1 << 4), + PAD_LEFT = (1 << 5), + PAD_UP = (1 << 6), + PAD_DOWN = (1 << 7), + PAD_R = (1 << 8), + PAD_L = (1 << 9), + PAD_X = (1 << 10), + PAD_Y = (1 << 11), + }; + + char * const PAD_NAMES[] = { + "PAD_A", + "PAD_B", + "PAD_SELECT", + "PAD_START", + "PAD_RIGHT", + "PAD_LEFT", + "PAD_UP", + "PAD_DOWN", + "PAD_R", + "PAD_L", + "PAD_X", + "PAD_Y" + }; + + template + inline void Read(T &var, const u32 addr); + + template + inline void Write(u32 addr, const T data); + + void setButtonReg(u32 buttonData); + + /// Update hardware + void Update(); + + /// Initialize hardware + void Init(); + + /// Shutdown hardware + void Shutdown(); +} + diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp index 9b4fcf0cb..6c809f755 100644 --- a/src/core/hw/hw.cpp +++ b/src/core/hw/hw.cpp @@ -8,7 +8,7 @@ #include "core/hw/hw.h" #include "core/hw/lcd.h" #include "core/hw/ndma.h" -#include "core/hw/user_input.h" +#include "core/hw/hid.h" namespace HW { @@ -91,14 +91,14 @@ template void Write(u32 addr, const u8 data); void Update() { LCD::Update(); NDMA::Update(); - USER_INPUT::Update(); + HID::Update(); } /// Initialize hardware void Init() { LCD::Init(); NDMA::Init(); - USER_INPUT::Init(); + HID::Init(); NOTICE_LOG(HW, "initialized OK"); } diff --git a/src/core/hw/user_input.cpp b/src/core/hw/user_input.cpp deleted file mode 100644 index 5cc5c4479..000000000 --- a/src/core/hw/user_input.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "user_input.h" - - -namespace USER_INPUT { - - template - inline void Read(T &var, const u32 addr) { - ERROR_LOG(USER_INPUT, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); - } - - template - inline void Write(u32 addr, const T data) { - ERROR_LOG(USER_INPUT, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); - } - - // Explicitly instantiate template functions because we aren't defining this in the header: - - template void Read(u64 &var, const u32 addr); - template void Read(u32 &var, const u32 addr); - template void Read(u16 &var, const u32 addr); - template void Read(u8 &var, const u32 addr); - - template void Write(u32 addr, const u64 data); - template void Write(u32 addr, const u32 data); - template void Write(u32 addr, const u16 data); - template void Write(u32 addr, const u8 data); - - void setButtonReg(u32 buttonData) { - Memory::Write32(PADDR_BUTTONS, buttonData); - } - - /// Update hardware - void Update() { - } - - /// Initialize hardware - void Init() { - NOTICE_LOG(USER_INPUT, "initialized OK"); - } - - /// Shutdown hardware - void Shutdown() { - NOTICE_LOG(USER_INPUT, "shutdown OK"); - } - -} \ No newline at end of file diff --git a/src/core/hw/user_input.h b/src/core/hw/user_input.h deleted file mode 100644 index b21da5815..000000000 --- a/src/core/hw/user_input.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include "common/common_types.h" -#include "core\mem_map.h" - - -namespace USER_INPUT { - struct Registers { - u32 buttons; - //u32 pad1; etc... - }; - - extern Registers g_regs; - - enum { - - PAD_A = (1 << 0), - PAD_B = (1 << 1), - PAD_SELECT = (1 << 2), - PAD_START = (1 << 3), - PAD_RIGHT = (1 << 4), - PAD_LEFT = (1 << 5), - PAD_UP = (1 << 6), - PAD_DOWN = (1 << 7), - PAD_R = (1 << 8), - PAD_L = (1 << 9), - PAD_X = (1 << 10), - PAD_Y = (1 << 11), - - PADDR_BUTTONS = 0x1000001c, //TODO: it works using the shared mem mapping with all homebrew tested, however the wiki states 0x10146000 as the paddr - }; - - - enum { - REG_BUTTONS = 0x1EC46000 //does not work due to confusion between shared mem and hardware IO - }; - - template - inline void Read(T &var, const u32 addr); - - template - inline void Write(u32 addr, const T data); - - void setButtonReg(u32 buttonData); - - /// Update hardware - void Update(); - - /// Initialize hardware - void Init(); - - /// Shutdown hardware - void Shutdown(); -} - From 9b6c4ac77d6a1db7fb18258243dafa4ce12c09d1 Mon Sep 17 00:00:00 2001 From: inspuration Date: Thu, 29 May 2014 13:26:33 -0400 Subject: [PATCH 08/29] Bindings are now editable --- src/citra_qt/key_bindings.cpp | 73 +++++++++++++++++++++++++++++++++-- src/citra_qt/key_bindings.hxx | 12 ++++++ src/citra_qt/main.cpp | 5 +-- src/core/core.vcxproj | 9 +++++ 4 files changed, 91 insertions(+), 8 deletions(-) diff --git a/src/citra_qt/key_bindings.cpp b/src/citra_qt/key_bindings.cpp index 6cd0db86d..6ea62125b 100644 --- a/src/citra_qt/key_bindings.cpp +++ b/src/citra_qt/key_bindings.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include "key_bindings.hxx" @@ -9,7 +10,19 @@ typedef std::map BindingsMap; BindingsMap bindings; -std::map nameMap; + +typedef std::map ReverseBindingsMap; + +ReverseBindingsMap reverseBindings; + + +typedef std::map NameMap; + +NameMap names; + +typedef std::map ReverseNameMap; + +ReverseNameMap reverseNames; void SaveKeyBindings(QSettings& settings) { @@ -47,32 +60,84 @@ HID::PAD GetKeyBinding(QKeyEvent * event) void RegisterKeyBinding(const QKeySequence keySeq, const HID::PAD pad) { bindings[keySeq] = pad; + reverseBindings[pad] = keySeq; } void createNameMap() { for (int i = 0; i < HID::numPadItems; i++){ - nameMap[(HID::PAD)(1 << i)] = QString(HID::PAD_NAMES[i]); + names[(HID::PAD)(1 << i)] = QString(HID::PAD_NAMES[i]); + reverseNames[QString(HID::PAD_NAMES[i])] = (HID::PAD)(1 << i); } } +void setDefaultKeyBindings() { + RegisterKeyBinding(QKeySequence("Y"), HID::PAD::PAD_A); + RegisterKeyBinding(QKeySequence("H"), HID::PAD::PAD_B); + RegisterKeyBinding(QKeySequence("Z"), HID::PAD::PAD_SELECT); + RegisterKeyBinding(QKeySequence("X"), HID::PAD::PAD_START); + + RegisterKeyBinding(QKeySequence("W"), HID::PAD::PAD_UP); + RegisterKeyBinding(QKeySequence("A"), HID::PAD::PAD_LEFT); + RegisterKeyBinding(QKeySequence("S"), HID::PAD::PAD_DOWN); + RegisterKeyBinding(QKeySequence("D"), HID::PAD::PAD_RIGHT); + + RegisterKeyBinding(QKeySequence("6"), HID::PAD::PAD_R); + RegisterKeyBinding(QKeySequence("7"), HID::PAD::PAD_L); + RegisterKeyBinding(QKeySequence("U"), HID::PAD::PAD_X); + RegisterKeyBinding(QKeySequence("J"), HID::PAD::PAD_Y); + +} + +//class makes single columns uneditable +class NoEditDelegate : public QStyledItemDelegate { +public: + NoEditDelegate(QObject* parent = 0) : QStyledItemDelegate(parent) {} + virtual QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { + return 0; + } +}; + +void GKeyBindingsDialog::updateItem(QTreeWidgetItem * item, int column) { + bindings[item->text(1)] = reverseNames[item->text(0)]; //sanitise + reverseBindings[reverseNames[item->text(0)]] = item->text(1); + return; +} + GKeyBindingsDialog::GKeyBindingsDialog(QWidget* parent) : QDialog(parent) { ui.setupUi(this); createNameMap(); - for (BindingsMap::iterator key = bindings.begin(); key != bindings.end(); ++key) + for (NameMap::iterator key = names.begin(); key != names.end(); ++key) { + QKeySequence keySeq = reverseBindings[key->first]; QStringList columns; - columns << key->first.toString() << nameMap[key->second]; + columns << key->second << keySeq.toString(); QTreeWidgetItem* item = new QTreeWidgetItem(columns); + item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable); ui.treeWidget->addTopLevelItem(item); } // TODO: Make context configurable as well (hiding the column for now) + + ui.treeWidget->setEditTriggers( + QAbstractItemView::EditKeyPressed + | QAbstractItemView::SelectedClicked + | QAbstractItemView::AnyKeyPressed + ); + connect( + this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), + this, SLOT(OnMouseDoubleClicked(QTreeWidgetItem*, int)) + ); ui.treeWidget->setColumnCount(2); ui.treeWidget->resizeColumnToContents(0); ui.treeWidget->resizeColumnToContents(1); + + connect(ui.treeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)), + this, SLOT(updateItem(QTreeWidgetItem *, int))); + ui.treeWidget->setItemDelegateForColumn(0, new NoEditDelegate(this)); + } diff --git a/src/citra_qt/key_bindings.hxx b/src/citra_qt/key_bindings.hxx index 166bca245..690934a47 100644 --- a/src/citra_qt/key_bindings.hxx +++ b/src/citra_qt/key_bindings.hxx @@ -38,6 +38,15 @@ HID::PAD GetKeyBinding(QKeyEvent * event); */ void LoadKeyBindings(QSettings& settings); + +/** +* Sets default key bindings. +* +* +*/ +void setDefaultKeyBindings(); + + class GKeyBindingsDialog : public QDialog { Q_OBJECT @@ -47,4 +56,7 @@ public: private: Ui::key_bindings ui; + +private slots: + void updateItem(QTreeWidgetItem * item, int column); }; diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 556e9015a..1bdba3443 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -98,10 +98,7 @@ GMainWindow::GMainWindow() connect(GetHotkey("Main Window", "Start Emulation", this), SIGNAL(activated()), this, SLOT(OnStartGame())); // Setup key bindings - RegisterKeyBinding(QKeySequence("W"), HID::PAD::PAD_UP); - RegisterKeyBinding(QKeySequence("A"), HID::PAD::PAD_LEFT); - RegisterKeyBinding(QKeySequence("S"), HID::PAD::PAD_DOWN); - RegisterKeyBinding(QKeySequence("D"), HID::PAD::PAD_RIGHT); + setDefaultKeyBindings(); LoadKeyBindings(settings); diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index ef621b1e8..621aa60b8 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -99,6 +99,9 @@ true + + $(IntDir)%(RelativeDir) + @@ -106,6 +109,9 @@ true + + $(IntDir)%(RelativeDir) + @@ -131,6 +137,9 @@ true + + $(IntDir)%(RelativeDir) + From 53cc3e8f673ddbc1289ed9774906304686421408 Mon Sep 17 00:00:00 2001 From: inspuration Date: Thu, 29 May 2014 14:09:43 -0400 Subject: [PATCH 09/29] Fixed Cmakelists --- src/citra_qt/CMakeLists.txt | 5 +++++ src/citra_qt/key_bindings.cpp | 2 +- src/core/CMakeLists.txt | 6 ++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 549f69217..7a887267d 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -5,6 +5,7 @@ set(SRCS debugger/ramview.cpp debugger/registers.cpp hotkeys.cpp + key_bindings.cpp main.cpp config/controller_config.cpp config/controller_config_util.cpp) @@ -15,11 +16,13 @@ set (HEADERS debugger/ramview.hxx debugger/registers.hxx hotkeys.hxx + key_bindings.hxx main.hxx ui_callstack.h ui_controller_config.h ui_disassembler.h ui_hotkeys.h + ui_key_bindings.h ui_main.h ui_registers.h version.h @@ -31,6 +34,7 @@ qt4_wrap_ui(UI_HDRS debugger/disassembler.ui debugger/registers.ui hotkeys.ui + key_bindings.ui main.ui config/controller_config.ui) @@ -41,6 +45,7 @@ qt4_wrap_cpp(MOC_SRCS debugger/registers.hxx debugger/ramview.hxx hotkeys.hxx + key_bindings.hxx main.hxx config/controller_config.hxx config/controller_config_util.hxx) diff --git a/src/citra_qt/key_bindings.cpp b/src/citra_qt/key_bindings.cpp index 6ea62125b..b49ead464 100644 --- a/src/citra_qt/key_bindings.cpp +++ b/src/citra_qt/key_bindings.cpp @@ -99,7 +99,7 @@ public: }; void GKeyBindingsDialog::updateItem(QTreeWidgetItem * item, int column) { - bindings[item->text(1)] = reverseNames[item->text(0)]; //sanitise + bindings[item->text(1)] = reverseNames[item->text(0)]; //TODO: sanitise reverseBindings[reverseNames[item->text(0)]] = item->text(1); return; } diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 4086b415b..d29183899 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -44,7 +44,8 @@ set(SRCS core.cpp hle/service/srv.cpp hw/hw.cpp hw/lcd.cpp - hw/ndma.cpp) + hw/ndma.cpp + hw/hid.cpp) set(HEADERS core.h core_timing.h @@ -90,6 +91,7 @@ set(HEADERS core.h hle/service/srv.h hw/hw.h hw/lcd.h - hw/ndma.h) + hw/ndma.h + hw/hid.h) add_library(core STATIC ${SRCS} ${HEADERS}) From 6682f9173b799c32ce1f44430722630b4b5a8ef0 Mon Sep 17 00:00:00 2001 From: inspuration Date: Thu, 29 May 2014 16:42:37 -0400 Subject: [PATCH 10/29] Fixed minor suggestions by bunnei --- src/citra_qt/bootmanager.cpp | 4 +- src/core/hle/svc.cpp | 7 +-- src/core/hw/hid.cpp | 45 ++++++++-------- src/core/hw/hid.h | 102 +++++++++++++++++------------------ src/core/hw/hw.cpp | 4 +- 5 files changed, 82 insertions(+), 80 deletions(-) diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index ba8a71bbf..74bd13f9e 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -206,7 +206,7 @@ void GRenderWindow::keyPressEvent(QKeyEvent* event) buttonReg |= GetKeyBinding(event); - HID::setButtonReg(buttonReg); + HID::SetButtonReg(buttonReg); return; } @@ -223,5 +223,5 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) */ buttonReg &= 0xffffffff ^ GetKeyBinding(event); - HID::setButtonReg(buttonReg); + HID::SetButtonReg(buttonReg); } \ No newline at end of file diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 870e87e17..4cf2d96ad 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -226,8 +226,9 @@ Result CreateEvent(void* _event, u32 reset_type) { return 0; } -u64 GetSystemTick(void) { - return Core::g_sys_core->GetTicks(); +//TODO: verify with a kernel dump +u64 GetSystemTick() { + return Core::g_app_core->GetTicks(); } const HLE::FunctionDef SVC_Table[] = { @@ -271,7 +272,7 @@ const HLE::FunctionDef SVC_Table[] = { {0x25, WrapI_VVUUS64, "WaitSynchronizationN"}, {0x26, NULL, "SignalAndWait"}, {0x27, NULL, "DuplicateHandle"}, - { 0x28, WrapU64_V, "GetSystemTick" }, + { 0x28, WrapU64_V, "GetSystemTick" }, {0x29, NULL, "GetHandleInfo"}, {0x2A, NULL, "GetSystemInfo"}, {0x2B, NULL, "GetProcessInfo"}, diff --git a/src/core/hw/hid.cpp b/src/core/hw/hid.cpp index 9f4867e31..b7fefdd21 100644 --- a/src/core/hw/hid.cpp +++ b/src/core/hw/hid.cpp @@ -3,32 +3,33 @@ namespace HID { - template - inline void Read(T &var, const u32 addr) { - ERROR_LOG(HID, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); - } +template +inline void Read(T &var, const u32 addr) { + ERROR_LOG(HID, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); +} - template - inline void Write(u32 addr, const T data) { - ERROR_LOG(HID, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); - } +template +inline void Write(u32 addr, const T data) { + ERROR_LOG(HID, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); +} - void setButtonReg(u32 buttonData) { - Memory::Write32(PADDR_BUTTONS, buttonData); - } +//TODO: replace with an interface that doesnt suck (bravia) +void SetButtonReg(u32 buttonData) { + Memory::Write32(PADDR_BUTTONS, buttonData); +} - /// Update hardware - void Update() { - } +/// Update hardware +void Update() { +} - /// Initialize hardware - void Init() { - NOTICE_LOG(HID, "initialized OK"); - } +/// Initialize hardware +void Init() { + NOTICE_LOG(HID, "initialized OK"); +} - /// Shutdown hardware - void Shutdown() { - NOTICE_LOG(HID, "shutdown OK"); - } +/// Shutdown hardware +void Shutdown() { + NOTICE_LOG(HID, "shutdown OK"); +} } \ No newline at end of file diff --git a/src/core/hw/hid.h b/src/core/hw/hid.h index 524b48cca..e80178bcd 100644 --- a/src/core/hw/hid.h +++ b/src/core/hw/hid.h @@ -5,69 +5,69 @@ namespace HID { - struct Registers { - u32 buttons; - //u32 pad1; etc... - }; +struct Registers { + u32 buttons; + //u32 pad1; etc... +}; - extern Registers g_regs; +extern Registers g_regs; - enum { - PADDR_BUTTONS = 0x1000001c, //TODO: it works using the shared mem mapping with all homebrew tested, however the wiki states 0x10146000 as the paddr - }; +enum { + PADDR_BUTTONS = 0x1000001c, //TODO: it works using the shared mem mapping with all homebrew tested, however the wiki states 0x10146000 as the paddr +}; - enum { - REG_BUTTONS = 0x1EC46000 //does not work due to confusion between shared mem and hardware IO - }; +enum { + REG_BUTTONS = 0x1EC46000 //does not work due to confusion between shared mem and hardware IO +}; - const int numPadItems = 12; // figure out a better way :( +const int numPadItems = 12; // figure out a better way :( - enum PAD { - PAD_A = (1 << 0), - PAD_B = (1 << 1), - PAD_SELECT = (1 << 2), - PAD_START = (1 << 3), - PAD_RIGHT = (1 << 4), - PAD_LEFT = (1 << 5), - PAD_UP = (1 << 6), - PAD_DOWN = (1 << 7), - PAD_R = (1 << 8), - PAD_L = (1 << 9), - PAD_X = (1 << 10), - PAD_Y = (1 << 11), - }; +enum PAD { + PAD_A = (1 << 0), + PAD_B = (1 << 1), + PAD_SELECT = (1 << 2), + PAD_START = (1 << 3), + PAD_RIGHT = (1 << 4), + PAD_LEFT = (1 << 5), + PAD_UP = (1 << 6), + PAD_DOWN = (1 << 7), + PAD_R = (1 << 8), + PAD_L = (1 << 9), + PAD_X = (1 << 10), + PAD_Y = (1 << 11), +}; - char * const PAD_NAMES[] = { - "PAD_A", - "PAD_B", - "PAD_SELECT", - "PAD_START", - "PAD_RIGHT", - "PAD_LEFT", - "PAD_UP", - "PAD_DOWN", - "PAD_R", - "PAD_L", - "PAD_X", - "PAD_Y" - }; +char * const PAD_NAMES[] = { + "PAD_A", + "PAD_B", + "PAD_SELECT", + "PAD_START", + "PAD_RIGHT", + "PAD_LEFT", + "PAD_UP", + "PAD_DOWN", + "PAD_R", + "PAD_L", + "PAD_X", + "PAD_Y" +}; - template - inline void Read(T &var, const u32 addr); +template +inline void Read(T &var, const u32 addr); - template - inline void Write(u32 addr, const T data); +template +inline void Write(u32 addr, const T data); - void setButtonReg(u32 buttonData); +void SetButtonReg(u32 buttonData); - /// Update hardware - void Update(); +/// Update hardware +void Update(); - /// Initialize hardware - void Init(); +/// Initialize hardware +void Init(); - /// Shutdown hardware - void Shutdown(); +/// Shutdown hardware +void Shutdown(); } diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp index 6c809f755..d7705e65b 100644 --- a/src/core/hw/hw.cpp +++ b/src/core/hw/hw.cpp @@ -91,14 +91,14 @@ template void Write(u32 addr, const u8 data); void Update() { LCD::Update(); NDMA::Update(); - HID::Update(); + HID::Update(); } /// Initialize hardware void Init() { LCD::Init(); NDMA::Init(); - HID::Init(); + HID::Init(); NOTICE_LOG(HW, "initialized OK"); } From 3285b3c1682e9953c65232a31957259c82e04d4a Mon Sep 17 00:00:00 2001 From: inspuration Date: Thu, 29 May 2014 16:45:09 -0400 Subject: [PATCH 11/29] changed paddr_buttons to vaddr --- src/core/hw/hid.cpp | 2 +- src/core/hw/hid.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/hw/hid.cpp b/src/core/hw/hid.cpp index b7fefdd21..a1b4b139c 100644 --- a/src/core/hw/hid.cpp +++ b/src/core/hw/hid.cpp @@ -15,7 +15,7 @@ inline void Write(u32 addr, const T data) { //TODO: replace with an interface that doesnt suck (bravia) void SetButtonReg(u32 buttonData) { - Memory::Write32(PADDR_BUTTONS, buttonData); + Memory::Write32(VADDR_BUTTONS, buttonData); } /// Update hardware diff --git a/src/core/hw/hid.h b/src/core/hw/hid.h index e80178bcd..1a89c9b41 100644 --- a/src/core/hw/hid.h +++ b/src/core/hw/hid.h @@ -13,7 +13,7 @@ struct Registers { extern Registers g_regs; enum { - PADDR_BUTTONS = 0x1000001c, //TODO: it works using the shared mem mapping with all homebrew tested, however the wiki states 0x10146000 as the paddr + VADDR_BUTTONS = 0x1000001c, //TODO: it works using the shared mem mapping with all homebrew tested, however the wiki states 0x10146000 as the paddr }; From 0be75c13ee05c43ac4afb702346cc4083e8d2df6 Mon Sep 17 00:00:00 2001 From: Disruption Date: Sun, 1 Jun 2014 21:08:26 +0200 Subject: [PATCH 12/29] Added 'this' reference to num_instructions field so it's properly updated,as before the method was affecting the local method parameter rather than the class field --- src/core/arm/arm_interface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index b73786ccd..34a2eba1b 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -25,7 +25,7 @@ public: */ void Run(int num_instructions) { ExecuteInstructions(num_instructions); - num_instructions += num_instructions; + this->num_instructions += num_instructions; } /// Step CPU by one instruction From bdeadb4ca25f58e08c96c97e1ce753d16035335f Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 1 Jun 2014 15:31:36 -0400 Subject: [PATCH 13/29] Update CONTRIBUTING.md - removed variable naming starting with "_" - removed "Always break, even after a return" from case statements --- CONTRIBUTING.md | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 49742e4e0..cb1067c92 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,4 @@ # Contributing - Citra is a brand new project, so we have a great opportunity to keep things clean and well organized early on. As such, coding style is very important when making commits. They aren't very strict rules since we want to be flexible and we understand that under certain circumstances some of them can be counterproductive. Just try to follow as many of them as possible: ### General Rules @@ -11,18 +10,16 @@ Citra is a brand new project, so we have a great opportunity to keep things clea ### Naming Rules * Functions - * CamelCase, `_` may also be used for clarity (e.g. `ARM_InitCore`) + * CamelCase, "_" may also be used for clarity (e.g. ARM_InitCore) * Variables - * lower\_case\_underscored - * Prefix `g_` if global - * Prefix `_` if internal - * Prefix `__` if ultra internal + * lower_case_underscored + * Prefix "g_" if global * Classes - * CamelCase, `_` may also be used for clarity (e.g. `OGL_VideoInterface`) + * CamelCase, "_" may also be used for clarity (e.g. OGL_VideoInterface) * Files/Folders - * lower\_case\_underscored + * lower_case_underscored * Namespaces - * CamelCase, `_` may also be used for clarity (e.g. `ARM_InitCore`) + * CamelCase, "_" may also be used for clarity (e.g. ARM_InitCore) ### Indentation/Whitespace Style Follow the indentation/whitespace style shown below. Do not use tabs, use 4-spaces instead. @@ -88,15 +85,13 @@ void FooBar() { case 3: DoSomething(var); return; - // Always break, even after a return - break; default: // Yes, even break for the last case break; } - std::string + std::vector you_can_declare, a_few, variables, From 66754b121f021d03028b75fca4ab8b31c65fe726 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 17 May 2014 22:07:06 +0200 Subject: [PATCH 14/29] Pica: Add command list registers. --- src/core/hw/lcd.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++--- src/core/hw/lcd.h | 12 ++++++++++-- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp index b57563a73..61ee99c1f 100644 --- a/src/core/hw/lcd.cpp +++ b/src/core/hw/lcd.cpp @@ -7,11 +7,11 @@ #include "core/core.h" #include "core/mem_map.h" +#include "core/hle/kernel/thread.h" #include "core/hw/lcd.h" #include "video_core/video_core.h" -#include "core/hle/kernel/thread.h" namespace LCD { @@ -89,31 +89,70 @@ inline void Read(T &var, const u32 addr) { case REG_FRAMEBUFFER_TOP_LEFT_1: var = g_regs.framebuffer_top_left_1; break; + case REG_FRAMEBUFFER_TOP_LEFT_2: var = g_regs.framebuffer_top_left_2; break; + case REG_FRAMEBUFFER_TOP_RIGHT_1: var = g_regs.framebuffer_top_right_1; break; + case REG_FRAMEBUFFER_TOP_RIGHT_2: var = g_regs.framebuffer_top_right_2; break; + case REG_FRAMEBUFFER_SUB_LEFT_1: var = g_regs.framebuffer_sub_left_1; break; + case REG_FRAMEBUFFER_SUB_RIGHT_1: var = g_regs.framebuffer_sub_right_1; break; + + case CommandListSize: + var = g_regs.command_list_size; + break; + + case CommandListAddress: + var = g_regs.command_list_address; + break; + + case ProcessCommandList: + var = g_regs.command_processing_enabled; + break; + default: ERROR_LOG(LCD, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); break; } - } template inline void Write(u32 addr, const T data) { - ERROR_LOG(LCD, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); + switch (addr) { + case CommandListSize: + g_regs.command_list_size = data; + break; + + case CommandListAddress: + g_regs.command_list_address = data; + break; + + case ProcessCommandList: + g_regs.command_processing_enabled = data; + if (g_regs.command_processing_enabled & 1) + { + // u32* buffer = (u32*)Memory::GetPointer(g_regs.command_list_address << 3); + ERROR_LOG(LCD, "Beginning %x bytes of commands from address %x", g_regs.command_list_size, g_regs.command_list_address << 3); + // TODO: Process command list! + } + break; + + default: + ERROR_LOG(LCD, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); + break; + } } // Explicitly instantiate template functions because we aren't defining this in the header: diff --git a/src/core/hw/lcd.h b/src/core/hw/lcd.h index 2dd3b4adc..2ae852d7c 100644 --- a/src/core/hw/lcd.h +++ b/src/core/hw/lcd.h @@ -17,6 +17,10 @@ struct Registers { u32 framebuffer_sub_left_2; u32 framebuffer_sub_right_1; u32 framebuffer_sub_right_2; + + u32 command_list_size; + u32 command_list_address; + u32 command_processing_enabled; }; extern Registers g_regs; @@ -24,7 +28,7 @@ extern Registers g_regs; enum { TOP_ASPECT_X = 0x5, TOP_ASPECT_Y = 0x3, - + TOP_HEIGHT = 240, TOP_WIDTH = 400, BOTTOM_WIDTH = 320, @@ -57,12 +61,16 @@ enum { REG_FRAMEBUFFER_SUB_LEFT_2 = 0x1EF0056C, // Sub LCD, second framebuffer REG_FRAMEBUFFER_SUB_RIGHT_1 = 0x1EF00594, // Sub LCD, unused first framebuffer REG_FRAMEBUFFER_SUB_RIGHT_2 = 0x1EF00598, // Sub LCD, unused second framebuffer + + CommandListSize = 0x1EF018E0, + CommandListAddress = 0x1EF018E8, + ProcessCommandList = 0x1EF018F0, }; /// Framebuffer location enum FramebufferLocation { FRAMEBUFFER_LOCATION_UNKNOWN, ///< Framebuffer location is unknown - FRAMEBUFFER_LOCATION_FCRAM, ///< Framebuffer is in the GSP heap + FRAMEBUFFER_LOCATION_FCRAM, ///< Framebuffer is in the GSP heap FRAMEBUFFER_LOCATION_VRAM, ///< Framebuffer is in VRAM }; From 89410903896645c360a452ec94d1d899f1774902 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 17 May 2014 22:26:45 +0200 Subject: [PATCH 15/29] GSP: Define more GX commands. --- src/core/hle/service/gsp.cpp | 51 ++++++++++++++++++++++++++---------- src/core/hle/service/gsp.h | 17 ++++++++++++ 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp.cpp index 50cee2c41..3dda4c934 100644 --- a/src/core/hle/service/gsp.cpp +++ b/src/core/hle/service/gsp.cpp @@ -12,23 +12,24 @@ #include "core/hw/lcd.h" +#include "video_core/gpu_debugger.h" + //////////////////////////////////////////////////////////////////////////////////////////////////// /// GSP shared memory GX command buffer header union GX_CmdBufferHeader { u32 hex; - // Current command index. This index is updated by GSP module after loading the command data, - // right before the command is processed. When this index is updated by GSP module, the total + // Current command index. This index is updated by GSP module after loading the command data, + // right before the command is processed. When this index is updated by GSP module, the total // commands field is decreased by one as well. BitField<0,8,u32> index; - + // Total commands to process, must not be value 0 when GSP module handles commands. This must be - // <=15 when writing a command to shared memory. This is incremented by the application when - // writing a command to shared memory, after increasing this value TriggerCmdReqQueue is only + // <=15 when writing a command to shared memory. This is incremented by the application when + // writing a command to shared memory, after increasing this value TriggerCmdReqQueue is only // used if this field is value 1. BitField<8,8,u32> number_commands; - }; /// Gets the address of the start (header) of a command buffer in GSP shared memory @@ -45,6 +46,7 @@ static inline u8* GX_GetCmdBufferPointer(u32 thread_id, u32 offset=0) { void GX_FinishCommand(u32 thread_id) { GX_CmdBufferHeader* header = (GX_CmdBufferHeader*)GX_GetCmdBufferPointer(thread_id); header->number_commands = header->number_commands - 1; + // TODO: Increment header->index? } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -54,10 +56,6 @@ namespace GSP_GPU { u32 g_thread_id = 0; -enum { - CMD_GX_REQUEST_DMA = 0x00000000, -}; - enum { REG_FRAMEBUFFER_1 = 0x00400468, REG_FRAMEBUFFER_2 = 0x00400494, @@ -72,7 +70,7 @@ void ReadHWRegs(Service::Interface* self) { u32 reg_addr = cmd_buff[1]; u32 size = cmd_buff[2]; u32* dst = (u32*)Memory::GetPointer(cmd_buff[0x41]); - + switch (reg_addr) { // NOTE: Calling SetFramebufferLocation here is a hack... Not sure the correct way yet to set @@ -101,25 +99,50 @@ void RegisterInterruptRelayQueue(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); u32 flags = cmd_buff[1]; u32 event_handle = cmd_buff[3]; // TODO(bunnei): Implement event handling + cmd_buff[2] = g_thread_id; // ThreadID } + /// This triggers handling of the GX command written to the command buffer in shared memory. void TriggerCmdReqQueue(Service::Interface* self) { GX_CmdBufferHeader* header = (GX_CmdBufferHeader*)GX_GetCmdBufferPointer(g_thread_id); u32* cmd_buff = (u32*)GX_GetCmdBufferPointer(g_thread_id, 0x20 + (header->index * 0x20)); - switch (cmd_buff[0]) { + switch (static_cast(cmd_buff[0])) { // GX request DMA - typically used for copying memory from GSP heap to VRAM - case CMD_GX_REQUEST_DMA: + case GXCommandId::REQUEST_DMA: memcpy(Memory::GetPointer(cmd_buff[2]), Memory::GetPointer(cmd_buff[1]), cmd_buff[3]); break; + case GXCommandId::SET_COMMAND_LIST_LAST: + LCD::Write(LCD::CommandListAddress, cmd_buff[1] >> 3); + LCD::Write(LCD::CommandListSize, cmd_buff[2] >> 3); + LCD::Write(LCD::ProcessCommandList, 1); // TODO: Not sure if we are supposed to always write this + break; + + case GXCommandId::SET_MEMORY_FILL: + break; + + case GXCommandId::SET_DISPLAY_TRANSFER: + break; + + case GXCommandId::SET_TEXTURE_COPY: + break; + + case GXCommandId::SET_COMMAND_LIST_FIRST: + { + //u32* buf0_data = (u32*)Memory::GetPointer(cmd_buff[1]); + //u32* buf1_data = (u32*)Memory::GetPointer(cmd_buff[3]); + //u32* buf2_data = (u32*)Memory::GetPointer(cmd_buff[5]); + break; + } + default: ERROR_LOG(GSP, "TriggerCmdReqQueue unknown command 0x%08X", cmd_buff[0]); } - + GX_FinishCommand(g_thread_id); } diff --git a/src/core/hle/service/gsp.h b/src/core/hle/service/gsp.h index eb5786cd1..214de140f 100644 --- a/src/core/hle/service/gsp.h +++ b/src/core/hle/service/gsp.h @@ -11,6 +11,23 @@ namespace GSP_GPU { +enum class GXCommandId : u32 { + REQUEST_DMA = 0x00000000, + SET_COMMAND_LIST_LAST = 0x00000001, + SET_MEMORY_FILL = 0x00000002, // TODO: Confirm? (lictru uses 0x01000102) + SET_DISPLAY_TRANSFER = 0x00000003, + SET_TEXTURE_COPY = 0x00000004, + SET_COMMAND_LIST_FIRST = 0x00000005, +}; + +union GXCommand { + struct { + GXCommandId id; + }; + + u32 data[0x20]; +}; + /// Interface to "srv:" service class Interface : public Service::Interface { public: From 944dfe2f865631fb1402b4be99f6d3e7f81f189c Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 17 May 2014 22:34:55 +0200 Subject: [PATCH 16/29] Add initial graphics debugger interface. --- src/core/hle/service/gsp.cpp | 6 ++ src/video_core/gpu_debugger.h | 97 +++++++++++++++++++++++ src/video_core/video_core.vcxproj | 5 +- src/video_core/video_core.vcxproj.filters | 3 +- 4 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 src/video_core/gpu_debugger.h diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp.cpp index 3dda4c934..a42759053 100644 --- a/src/core/hle/service/gsp.cpp +++ b/src/core/hle/service/gsp.cpp @@ -16,6 +16,9 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// +// Main graphics debugger object - TODO: Here is probably not the best place for this +GraphicsDebugger g_debugger; + /// GSP shared memory GX command buffer header union GX_CmdBufferHeader { u32 hex; @@ -45,6 +48,9 @@ static inline u8* GX_GetCmdBufferPointer(u32 thread_id, u32 offset=0) { /// Finishes execution of a GSP command void GX_FinishCommand(u32 thread_id) { GX_CmdBufferHeader* header = (GX_CmdBufferHeader*)GX_GetCmdBufferPointer(thread_id); + + g_debugger.GXCommandProcessed(GX_GetCmdBufferPointer(thread_id, 0x20 + (header->index * 0x20))); + header->number_commands = header->number_commands - 1; // TODO: Increment header->index? } diff --git a/src/video_core/gpu_debugger.h b/src/video_core/gpu_debugger.h new file mode 100644 index 000000000..ace9de95f --- /dev/null +++ b/src/video_core/gpu_debugger.h @@ -0,0 +1,97 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +#include "common/log.h" + +#include "core/hle/service/gsp.h" + + +class GraphicsDebugger +{ +public: + // Base class for all objects which need to be notified about GPU events + class DebuggerObserver + { + public: + DebuggerObserver() : observed(nullptr) { } + + virtual ~DebuggerObserver() + { + if (observed) + observed->UnregisterObserver(this); + } + + /** + * Called when a GX command has been processed and is ready for being + * read via GraphicsDebugger::ReadGXCommandHistory. + * @param total_command_count Total number of commands in the GX history + * @note All methods in this class are called from the GSP thread + */ + virtual void GXCommandProcessed(int total_command_count) + { + const GSP_GPU::GXCommand& cmd = observed->ReadGXCommandHistory(total_command_count-1); + ERROR_LOG(GSP, "Received command: id=%x", cmd.id); + } + + protected: + GraphicsDebugger* GetDebugger() + { + return observed; + } + + private: + GraphicsDebugger* observed; + bool in_destruction; + + friend class GraphicsDebugger; + }; + + void GXCommandProcessed(u8* command_data) + { + gx_command_history.push_back(GSP_GPU::GXCommand()); + GSP_GPU::GXCommand& cmd = gx_command_history[gx_command_history.size()-1]; + + const int cmd_length = sizeof(GSP_GPU::GXCommand); + memcpy(cmd.data, command_data, cmd_length); + + ForEachObserver([this](DebuggerObserver* observer) { + observer->GXCommandProcessed(this->gx_command_history.size()); + } ); + } + + const GSP_GPU::GXCommand& ReadGXCommandHistory(int index) const + { + // TODO: Is this thread-safe? + return gx_command_history[index]; + } + + void RegisterObserver(DebuggerObserver* observer) + { + // TODO: Check for duplicates + observers.push_back(observer); + observer->observed = this; + } + + void UnregisterObserver(DebuggerObserver* observer) + { + std::remove(observers.begin(), observers.end(), observer); + observer->observed = nullptr; + } + +private: + void ForEachObserver(std::function func) + { + std::for_each(observers.begin(),observers.end(), func); + } + + std::vector observers; + + std::vector gx_command_history; +}; diff --git a/src/video_core/video_core.vcxproj b/src/video_core/video_core.vcxproj index d8c53271e..a4df92386 100644 --- a/src/video_core/video_core.vcxproj +++ b/src/video_core/video_core.vcxproj @@ -24,10 +24,11 @@ + - + @@ -128,4 +129,4 @@ - \ No newline at end of file + diff --git a/src/video_core/video_core.vcxproj.filters b/src/video_core/video_core.vcxproj.filters index 4eb2ef0a4..cc173a718 100644 --- a/src/video_core/video_core.vcxproj.filters +++ b/src/video_core/video_core.vcxproj.filters @@ -16,6 +16,7 @@ renderer_opengl + @@ -23,4 +24,4 @@ - \ No newline at end of file + From 5cc0497f8e9ecd20bf38a5e493ca171ac8105159 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 17 May 2014 22:38:10 +0200 Subject: [PATCH 17/29] citra-qt: Add GX command history viewer. --- src/citra_qt/CMakeLists.txt | 2 + src/citra_qt/citra_qt.vcxproj | 6 +- src/citra_qt/citra_qt.vcxproj.filters | 16 ++++-- src/citra_qt/debugger/graphics.cpp | 83 +++++++++++++++++++++++++++ src/citra_qt/debugger/graphics.hxx | 43 ++++++++++++++ src/citra_qt/main.cpp | 6 ++ src/citra_qt/main.hxx | 2 + 7 files changed, 151 insertions(+), 7 deletions(-) create mode 100644 src/citra_qt/debugger/graphics.cpp create mode 100644 src/citra_qt/debugger/graphics.hxx diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 549f69217..1968e34d3 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -2,6 +2,7 @@ set(SRCS bootmanager.cpp debugger/callstack.cpp debugger/disassembler.cpp + debugger/graphics.cpp debugger/ramview.cpp debugger/registers.cpp hotkeys.cpp @@ -38,6 +39,7 @@ qt4_wrap_cpp(MOC_SRCS bootmanager.hxx debugger/callstack.hxx debugger/disassembler.hxx + debugger/graphics.hxx debugger/registers.hxx debugger/ramview.hxx hotkeys.hxx diff --git a/src/citra_qt/citra_qt.vcxproj b/src/citra_qt/citra_qt.vcxproj index 3f24bbfbf..a1b24f676 100644 --- a/src/citra_qt/citra_qt.vcxproj +++ b/src/citra_qt/citra_qt.vcxproj @@ -130,6 +130,7 @@ + @@ -143,9 +144,10 @@ - + + @@ -182,4 +184,4 @@ - \ No newline at end of file + diff --git a/src/citra_qt/citra_qt.vcxproj.filters b/src/citra_qt/citra_qt.vcxproj.filters index 2b3838e29..faa4d9f52 100644 --- a/src/citra_qt/citra_qt.vcxproj.filters +++ b/src/citra_qt/citra_qt.vcxproj.filters @@ -36,10 +36,13 @@ debugger - + debugger - + + debugger + + debugger @@ -65,10 +68,13 @@ debugger - + debugger - + + debugger + + debugger @@ -106,4 +112,4 @@ - \ No newline at end of file + diff --git a/src/citra_qt/debugger/graphics.cpp b/src/citra_qt/debugger/graphics.cpp new file mode 100644 index 000000000..9aaade8f9 --- /dev/null +++ b/src/citra_qt/debugger/graphics.cpp @@ -0,0 +1,83 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "graphics.hxx" +#include +#include +#include + +extern GraphicsDebugger g_debugger; + +GPUCommandStreamItemModel::GPUCommandStreamItemModel(QObject* parent) : QAbstractListModel(parent), command_count(0) +{ + connect(this, SIGNAL(GXCommandFinished(int)), this, SLOT(OnGXCommandFinishedInternal(int))); +} + +int GPUCommandStreamItemModel::rowCount(const QModelIndex& parent) const +{ + return command_count; +} + +QVariant GPUCommandStreamItemModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + int command_index = index.row(); + const GSP_GPU::GXCommand& command = GetDebugger()->ReadGXCommandHistory(command_index); + if (role == Qt::DisplayRole) + { + std::map command_names; + command_names[GSP_GPU::GXCommandId::REQUEST_DMA] = "REQUEST_DMA"; + command_names[GSP_GPU::GXCommandId::SET_COMMAND_LIST_FIRST] = "SET_COMMAND_LIST_FIRST"; + command_names[GSP_GPU::GXCommandId::SET_MEMORY_FILL] = "SET_MEMORY_FILL"; + command_names[GSP_GPU::GXCommandId::SET_DISPLAY_TRANSFER] = "SET_DISPLAY_TRANSFER"; + command_names[GSP_GPU::GXCommandId::SET_TEXTURE_COPY] = "SET_TEXTURE_COPY"; + command_names[GSP_GPU::GXCommandId::SET_COMMAND_LIST_LAST] = "SET_COMMAND_LIST_LAST"; + QString str = QString("%1 %2 %3 %4 %5 %6 %7 %8 %9").arg(command_names[static_cast(command.id)]) + .arg(command.data[0], 8, 16, QLatin1Char('0')) + .arg(command.data[1], 8, 16, QLatin1Char('0')) + .arg(command.data[2], 8, 16, QLatin1Char('0')) + .arg(command.data[3], 8, 16, QLatin1Char('0')) + .arg(command.data[4], 8, 16, QLatin1Char('0')) + .arg(command.data[5], 8, 16, QLatin1Char('0')) + .arg(command.data[6], 8, 16, QLatin1Char('0')) + .arg(command.data[7], 8, 16, QLatin1Char('0')); + return QVariant(str); + } + else + { + return QVariant(); + } +} + +void GPUCommandStreamItemModel::GXCommandProcessed(int total_command_count) +{ + emit GXCommandFinished(total_command_count); +} + +void GPUCommandStreamItemModel::OnGXCommandFinishedInternal(int total_command_count) +{ + if (total_command_count == 0) + return; + + int prev_command_count = command_count; + command_count = total_command_count; + emit dataChanged(index(prev_command_count,0), index(total_command_count-1,0)); +} + + +GPUCommandStreamWidget::GPUCommandStreamWidget(QWidget* parent) : QDockWidget(tr("Graphics Debugger"), parent) +{ + // TODO: set objectName! + + GPUCommandStreamItemModel* command_model = new GPUCommandStreamItemModel(this); + g_debugger.RegisterObserver(command_model); + + QListView* command_list = new QListView; + command_list->setModel(command_model); + command_list->setFont(QFont("monospace")); + + setWidget(command_list); +} diff --git a/src/citra_qt/debugger/graphics.hxx b/src/citra_qt/debugger/graphics.hxx new file mode 100644 index 000000000..72656f93c --- /dev/null +++ b/src/citra_qt/debugger/graphics.hxx @@ -0,0 +1,43 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "video_core/gpu_debugger.h" + +class GPUCommandStreamItemModel : public QAbstractListModel, public GraphicsDebugger::DebuggerObserver +{ + Q_OBJECT + +public: + GPUCommandStreamItemModel(QObject* parent); + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + +public: + void GXCommandProcessed(int total_command_count) override; + +public slots: + void OnGXCommandFinishedInternal(int total_command_count); + +signals: + void GXCommandFinished(int total_command_count); + +private: + int command_count; +}; + +class GPUCommandStreamWidget : public QDockWidget +{ + Q_OBJECT + +public: + GPUCommandStreamWidget(QWidget* parent = 0); + +private: +}; diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 9be982909..79367c3ed 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -19,6 +19,7 @@ #include "debugger/registers.hxx" #include "debugger/callstack.hxx" #include "debugger/ramview.hxx" +#include "debugger/graphics.hxx" #include "core/system.h" #include "core/loader.h" @@ -47,10 +48,15 @@ GMainWindow::GMainWindow() addDockWidget(Qt::RightDockWidgetArea, callstackWidget); callstackWidget->hide(); + graphicsWidget = new GPUCommandStreamWidget(this); + addDockWidget(Qt::RightDockWidgetArea, graphicsWidget); + callstackWidget->hide(); + QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); debug_menu->addAction(disasmWidget->toggleViewAction()); debug_menu->addAction(registersWidget->toggleViewAction()); debug_menu->addAction(callstackWidget->toggleViewAction()); + debug_menu->addAction(graphicsWidget->toggleViewAction()); // Set default UI state // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half diff --git a/src/citra_qt/main.hxx b/src/citra_qt/main.hxx index fa122f76e..100bdbd00 100644 --- a/src/citra_qt/main.hxx +++ b/src/citra_qt/main.hxx @@ -10,6 +10,7 @@ class GRenderWindow; class DisassemblerWidget; class RegistersWidget; class CallstackWidget; +class GPUCommandStreamWidget; class GMainWindow : public QMainWindow { @@ -50,6 +51,7 @@ private: DisassemblerWidget* disasmWidget; RegistersWidget* registersWidget; CallstackWidget* callstackWidget; + GPUCommandStreamWidget* graphicsWidget; }; #endif // _CITRA_QT_MAIN_HXX_ From 7c5f1647be2e31cc469d9e1919d31d627f0a75da Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 17 May 2014 22:50:33 +0200 Subject: [PATCH 18/29] Rename LCD to GPU. --- src/common/log.h | 2 +- src/common/log_manager.cpp | 2 +- src/core/CMakeLists.txt | 4 ++-- src/core/core.vcxproj | 6 +++--- src/core/core.vcxproj.filters | 6 +++--- src/core/hle/service/gsp.cpp | 16 ++++++++-------- src/core/hw/{lcd.cpp => gpu.cpp} | 18 +++++++++--------- src/core/hw/{lcd.h => gpu.h} | 2 +- src/core/hw/hw.cpp | 16 ++++++++-------- src/core/hw/ndma.cpp | 4 ++-- .../renderer_opengl/renderer_opengl.cpp | 6 +++--- 11 files changed, 41 insertions(+), 41 deletions(-) rename src/core/hw/{lcd.cpp => gpu.cpp} (92%) rename src/core/hw/{lcd.h => gpu.h} (99%) diff --git a/src/common/log.h b/src/common/log.h index 8b39b03a1..d0da68aad 100644 --- a/src/common/log.h +++ b/src/common/log.h @@ -60,7 +60,7 @@ enum LOG_TYPE { NDMA, HLE, RENDER, - LCD, + GPU, HW, TIME, NETPLAY, diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp index 146472888..b4a761c75 100644 --- a/src/common/log_manager.cpp +++ b/src/common/log_manager.cpp @@ -65,7 +65,7 @@ LogManager::LogManager() m_Log[LogTypes::WII_IPC_ES] = new LogContainer("WII_IPC_ES", "WII IPC ES"); m_Log[LogTypes::WII_IPC_FILEIO] = new LogContainer("WII_IPC_FILEIO", "WII IPC FILEIO"); m_Log[LogTypes::RENDER] = new LogContainer("RENDER", "RENDER"); - m_Log[LogTypes::LCD] = new LogContainer("LCD", "LCD"); + m_Log[LogTypes::GPU] = new LogContainer("GPU", "GPU"); m_Log[LogTypes::SVC] = new LogContainer("SVC", "Supervisor Call HLE"); m_Log[LogTypes::NDMA] = new LogContainer("NDMA", "NDMA"); m_Log[LogTypes::HLE] = new LogContainer("HLE", "High Level Emulation"); diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 4086b415b..1c1a2eeb3 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -42,8 +42,8 @@ set(SRCS core.cpp hle/service/hid.cpp hle/service/service.cpp hle/service/srv.cpp + hw/gpu.cpp hw/hw.cpp - hw/lcd.cpp hw/ndma.cpp) set(HEADERS core.h @@ -88,8 +88,8 @@ set(HEADERS core.h hle/service/hid.h hle/service/service.h hle/service/srv.h + hw/gpu.h hw/hw.h - hw/lcd.h hw/ndma.h) add_library(core STATIC ${SRCS} ${HEADERS}) diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index f271d336e..8a3ad83ea 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -177,8 +177,8 @@ + - @@ -226,8 +226,8 @@ + - @@ -239,4 +239,4 @@ - \ No newline at end of file + diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index b6c1d5b93..f7b342f98 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -102,7 +102,7 @@ hw - + hw @@ -244,7 +244,7 @@ hw - + hw @@ -299,4 +299,4 @@ - \ No newline at end of file + diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp.cpp index a42759053..d51e6c66d 100644 --- a/src/core/hle/service/gsp.cpp +++ b/src/core/hle/service/gsp.cpp @@ -10,7 +10,7 @@ #include "core/hle/hle.h" #include "core/hle/service/gsp.h" -#include "core/hw/lcd.h" +#include "core/hw/gpu.h" #include "video_core/gpu_debugger.h" @@ -69,8 +69,8 @@ enum { /// Read a GSP GPU hardware register void ReadHWRegs(Service::Interface* self) { - static const u32 framebuffer_1[] = {LCD::PADDR_VRAM_TOP_LEFT_FRAME1, LCD::PADDR_VRAM_TOP_RIGHT_FRAME1}; - static const u32 framebuffer_2[] = {LCD::PADDR_VRAM_TOP_LEFT_FRAME2, LCD::PADDR_VRAM_TOP_RIGHT_FRAME2}; + static const u32 framebuffer_1[] = {GPU::PADDR_VRAM_TOP_LEFT_FRAME1, GPU::PADDR_VRAM_TOP_RIGHT_FRAME1}; + static const u32 framebuffer_2[] = {GPU::PADDR_VRAM_TOP_LEFT_FRAME2, GPU::PADDR_VRAM_TOP_RIGHT_FRAME2}; u32* cmd_buff = Service::GetCommandBuffer(); u32 reg_addr = cmd_buff[1]; @@ -85,13 +85,13 @@ void ReadHWRegs(Service::Interface* self) { // Top framebuffer 1 addresses case REG_FRAMEBUFFER_1: - LCD::SetFramebufferLocation(LCD::FRAMEBUFFER_LOCATION_VRAM); + GPU::SetFramebufferLocation(GPU::FRAMEBUFFER_LOCATION_VRAM); memcpy(dst, framebuffer_1, size); break; // Top framebuffer 2 addresses case REG_FRAMEBUFFER_2: - LCD::SetFramebufferLocation(LCD::FRAMEBUFFER_LOCATION_VRAM); + GPU::SetFramebufferLocation(GPU::FRAMEBUFFER_LOCATION_VRAM); memcpy(dst, framebuffer_2, size); break; @@ -123,9 +123,9 @@ void TriggerCmdReqQueue(Service::Interface* self) { break; case GXCommandId::SET_COMMAND_LIST_LAST: - LCD::Write(LCD::CommandListAddress, cmd_buff[1] >> 3); - LCD::Write(LCD::CommandListSize, cmd_buff[2] >> 3); - LCD::Write(LCD::ProcessCommandList, 1); // TODO: Not sure if we are supposed to always write this + GPU::Write(GPU::CommandListAddress, cmd_buff[1] >> 3); + GPU::Write(GPU::CommandListSize, cmd_buff[2] >> 3); + GPU::Write(GPU::ProcessCommandList, 1); // TODO: Not sure if we are supposed to always write this break; case GXCommandId::SET_MEMORY_FILL: diff --git a/src/core/hw/lcd.cpp b/src/core/hw/gpu.cpp similarity index 92% rename from src/core/hw/lcd.cpp rename to src/core/hw/gpu.cpp index 61ee99c1f..632e1aaac 100644 --- a/src/core/hw/lcd.cpp +++ b/src/core/hw/gpu.cpp @@ -8,12 +8,12 @@ #include "core/core.h" #include "core/mem_map.h" #include "core/hle/kernel/thread.h" -#include "core/hw/lcd.h" +#include "core/hw/gpu.h" #include "video_core/video_core.h" -namespace LCD { +namespace GPU { Registers g_regs; @@ -61,7 +61,7 @@ const FramebufferLocation GetFramebufferLocation() { } else if ((g_regs.framebuffer_top_right_1 & ~Memory::FCRAM_MASK) == Memory::FCRAM_PADDR) { return FRAMEBUFFER_LOCATION_FCRAM; } else { - ERROR_LOG(LCD, "unknown framebuffer location!"); + ERROR_LOG(GPU, "unknown framebuffer location!"); } return FRAMEBUFFER_LOCATION_UNKNOWN; } @@ -78,7 +78,7 @@ const u8* GetFramebufferPointer(const u32 address) { case FRAMEBUFFER_LOCATION_VRAM: return (const u8*)Memory::GetPointer(Memory::VirtualAddressFromPhysical_VRAM(address)); default: - ERROR_LOG(LCD, "unknown framebuffer location"); + ERROR_LOG(GPU, "unknown framebuffer location"); } return NULL; } @@ -123,7 +123,7 @@ inline void Read(T &var, const u32 addr) { break; default: - ERROR_LOG(LCD, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); + ERROR_LOG(GPU, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); break; } } @@ -144,13 +144,13 @@ inline void Write(u32 addr, const T data) { if (g_regs.command_processing_enabled & 1) { // u32* buffer = (u32*)Memory::GetPointer(g_regs.command_list_address << 3); - ERROR_LOG(LCD, "Beginning %x bytes of commands from address %x", g_regs.command_list_size, g_regs.command_list_address << 3); + ERROR_LOG(GPU, "Beginning %x bytes of commands from address %x", g_regs.command_list_size, g_regs.command_list_address << 3); // TODO: Process command list! } break; default: - ERROR_LOG(LCD, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); + ERROR_LOG(GPU, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); break; } } @@ -183,12 +183,12 @@ void Update() { void Init() { g_last_ticks = Core::g_app_core->GetTicks(); SetFramebufferLocation(FRAMEBUFFER_LOCATION_FCRAM); - NOTICE_LOG(LCD, "initialized OK"); + NOTICE_LOG(GPU, "initialized OK"); } /// Shutdown hardware void Shutdown() { - NOTICE_LOG(LCD, "shutdown OK"); + NOTICE_LOG(GPU, "shutdown OK"); } } // namespace diff --git a/src/core/hw/lcd.h b/src/core/hw/gpu.h similarity index 99% rename from src/core/hw/lcd.h rename to src/core/hw/gpu.h index 2ae852d7c..c81b1bb3f 100644 --- a/src/core/hw/lcd.h +++ b/src/core/hw/gpu.h @@ -6,7 +6,7 @@ #include "common/common_types.h" -namespace LCD { +namespace GPU { struct Registers { u32 framebuffer_top_left_1; diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp index 85669ae7f..ed70486e6 100644 --- a/src/core/hw/hw.cpp +++ b/src/core/hw/hw.cpp @@ -6,7 +6,7 @@ #include "common/log.h" #include "core/hw/hw.h" -#include "core/hw/lcd.h" +#include "core/hw/gpu.h" #include "core/hw/ndma.h" namespace HW { @@ -34,7 +34,7 @@ enum { VADDR_CDMA = 0xFFFDA000, // CoreLink DMA-330? Info VADDR_DSP_2 = 0x1ED03000, VADDR_HASH_2 = 0x1EE01000, - VADDR_LCD = 0x1EF00000, + VADDR_GPU = 0x1EF00000, }; template @@ -46,8 +46,8 @@ inline void Read(T &var, const u32 addr) { // NDMA::Read(var, addr); // break; - case VADDR_LCD: - LCD::Read(var, addr); + case VADDR_GPU: + GPU::Read(var, addr); break; default: @@ -64,8 +64,8 @@ inline void Write(u32 addr, const T data) { // NDMA::Write(addr, data); // break; - case VADDR_LCD: - LCD::Write(addr, data); + case VADDR_GPU: + GPU::Write(addr, data); break; default: @@ -87,13 +87,13 @@ template void Write(u32 addr, const u8 data); /// Update hardware void Update() { - LCD::Update(); + GPU::Update(); NDMA::Update(); } /// Initialize hardware void Init() { - LCD::Init(); + GPU::Init(); NDMA::Init(); NOTICE_LOG(HW, "initialized OK"); } diff --git a/src/core/hw/ndma.cpp b/src/core/hw/ndma.cpp index 52e459ebd..f6aa72d16 100644 --- a/src/core/hw/ndma.cpp +++ b/src/core/hw/ndma.cpp @@ -37,12 +37,12 @@ void Update() { /// Initialize hardware void Init() { - NOTICE_LOG(LCD, "initialized OK"); + NOTICE_LOG(GPU, "initialized OK"); } /// Shutdown hardware void Shutdown() { - NOTICE_LOG(LCD, "shutdown OK"); + NOTICE_LOG(GPU, "shutdown OK"); } } // namespace diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index bb5eb34aa..70af47c59 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -2,7 +2,7 @@ // Licensed under GPLv2 // Refer to the license.txt file included. -#include "core/hw/lcd.h" +#include "core/hw/gpu.h" #include "video_core/video_core.h" #include "video_core/renderer_opengl/renderer_opengl.h" @@ -77,8 +77,8 @@ void RendererOpenGL::FlipFramebuffer(const u8* in, u8* out) { */ void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect) { - FlipFramebuffer(LCD::GetFramebufferPointer(LCD::g_regs.framebuffer_top_left_1), m_xfb_top_flipped); - FlipFramebuffer(LCD::GetFramebufferPointer(LCD::g_regs.framebuffer_sub_left_1), m_xfb_bottom_flipped); + FlipFramebuffer(GPU::GetFramebufferPointer(GPU::g_regs.framebuffer_top_left_1), m_xfb_top_flipped); + FlipFramebuffer(GPU::GetFramebufferPointer(GPU::g_regs.framebuffer_sub_left_1), m_xfb_bottom_flipped); // Blit the top framebuffer // ------------------------ From 3240b6ef31ffe60d0f6f6f4b93a6476dd62f2399 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 17 May 2014 23:01:58 +0200 Subject: [PATCH 19/29] GPU: Cleanup register definitions. --- src/core/hle/service/gsp.cpp | 6 +++--- src/core/hw/gpu.cpp | 26 +++++++++++++------------- src/core/hw/gpu.h | 30 +++++++++++++++--------------- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp.cpp index d51e6c66d..15e9d19a5 100644 --- a/src/core/hle/service/gsp.cpp +++ b/src/core/hle/service/gsp.cpp @@ -123,9 +123,9 @@ void TriggerCmdReqQueue(Service::Interface* self) { break; case GXCommandId::SET_COMMAND_LIST_LAST: - GPU::Write(GPU::CommandListAddress, cmd_buff[1] >> 3); - GPU::Write(GPU::CommandListSize, cmd_buff[2] >> 3); - GPU::Write(GPU::ProcessCommandList, 1); // TODO: Not sure if we are supposed to always write this + GPU::Write(GPU::Registers::CommandListAddress, cmd_buff[1] >> 3); + GPU::Write(GPU::Registers::CommandListSize, cmd_buff[2] >> 3); + GPU::Write(GPU::Registers::ProcessCommandList, 1); // TODO: Not sure if we are supposed to always write this break; case GXCommandId::SET_MEMORY_FILL: diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index 632e1aaac..ec2d0e156 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -86,39 +86,39 @@ const u8* GetFramebufferPointer(const u32 address) { template inline void Read(T &var, const u32 addr) { switch (addr) { - case REG_FRAMEBUFFER_TOP_LEFT_1: + case Registers::FramebufferTopLeft1: var = g_regs.framebuffer_top_left_1; break; - case REG_FRAMEBUFFER_TOP_LEFT_2: + case Registers::FramebufferTopLeft2: var = g_regs.framebuffer_top_left_2; break; - case REG_FRAMEBUFFER_TOP_RIGHT_1: + case Registers::FramebufferTopRight1: var = g_regs.framebuffer_top_right_1; break; - case REG_FRAMEBUFFER_TOP_RIGHT_2: + case Registers::FramebufferTopRight2: var = g_regs.framebuffer_top_right_2; break; - case REG_FRAMEBUFFER_SUB_LEFT_1: + case Registers::FramebufferSubLeft1: var = g_regs.framebuffer_sub_left_1; break; - case REG_FRAMEBUFFER_SUB_RIGHT_1: + case Registers::FramebufferSubRight1: var = g_regs.framebuffer_sub_right_1; break; - case CommandListSize: + case Registers::CommandListSize: var = g_regs.command_list_size; break; - case CommandListAddress: + case Registers::CommandListAddress: var = g_regs.command_list_address; break; - case ProcessCommandList: + case Registers::ProcessCommandList: var = g_regs.command_processing_enabled; break; @@ -130,16 +130,16 @@ inline void Read(T &var, const u32 addr) { template inline void Write(u32 addr, const T data) { - switch (addr) { - case CommandListSize: + switch (static_cast(addr)) { + case Registers::CommandListSize: g_regs.command_list_size = data; break; - case CommandListAddress: + case Registers::CommandListAddress: g_regs.command_list_address = data; break; - case ProcessCommandList: + case Registers::ProcessCommandList: g_regs.command_processing_enabled = data; if (g_regs.command_processing_enabled & 1) { diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h index c81b1bb3f..f26f25e98 100644 --- a/src/core/hw/gpu.h +++ b/src/core/hw/gpu.h @@ -9,6 +9,21 @@ namespace GPU { struct Registers { + enum Id : u32 { + FramebufferTopLeft1 = 0x1EF00468, // Main LCD, first framebuffer for 3D left + FramebufferTopLeft2 = 0x1EF0046C, // Main LCD, second framebuffer for 3D left + FramebufferTopRight1 = 0x1EF00494, // Main LCD, first framebuffer for 3D right + FramebufferTopRight2 = 0x1EF00498, // Main LCD, second framebuffer for 3D right + FramebufferSubLeft1 = 0x1EF00568, // Sub LCD, first framebuffer + FramebufferSubLeft2 = 0x1EF0056C, // Sub LCD, second framebuffer + FramebufferSubRight1 = 0x1EF00594, // Sub LCD, unused first framebuffer + FramebufferSubRight2 = 0x1EF00598, // Sub LCD, unused second framebuffer + + CommandListSize = 0x1EF018E0, + CommandListAddress = 0x1EF018E8, + ProcessCommandList = 0x1EF018F0, + }; + u32 framebuffer_top_left_1; u32 framebuffer_top_left_2; u32 framebuffer_top_right_1; @@ -52,21 +67,6 @@ enum { PADDR_VRAM_SUB_FRAME2 = 0x18249CF0, }; -enum { - REG_FRAMEBUFFER_TOP_LEFT_1 = 0x1EF00468, // Main LCD, first framebuffer for 3D left - REG_FRAMEBUFFER_TOP_LEFT_2 = 0x1EF0046C, // Main LCD, second framebuffer for 3D left - REG_FRAMEBUFFER_TOP_RIGHT_1 = 0x1EF00494, // Main LCD, first framebuffer for 3D right - REG_FRAMEBUFFER_TOP_RIGHT_2 = 0x1EF00498, // Main LCD, second framebuffer for 3D right - REG_FRAMEBUFFER_SUB_LEFT_1 = 0x1EF00568, // Sub LCD, first framebuffer - REG_FRAMEBUFFER_SUB_LEFT_2 = 0x1EF0056C, // Sub LCD, second framebuffer - REG_FRAMEBUFFER_SUB_RIGHT_1 = 0x1EF00594, // Sub LCD, unused first framebuffer - REG_FRAMEBUFFER_SUB_RIGHT_2 = 0x1EF00598, // Sub LCD, unused second framebuffer - - CommandListSize = 0x1EF018E0, - CommandListAddress = 0x1EF018E8, - ProcessCommandList = 0x1EF018F0, -}; - /// Framebuffer location enum FramebufferLocation { FRAMEBUFFER_LOCATION_UNKNOWN, ///< Framebuffer location is unknown From 930a4a3f9e07ce9f3d085442742f13d84f00e2bf Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 17 May 2014 23:07:51 +0200 Subject: [PATCH 20/29] video core: added PICA definitions file. --- src/video_core/pica.h | 35 +++++++++++++++++++++++ src/video_core/video_core.vcxproj | 1 + src/video_core/video_core.vcxproj.filters | 1 + 3 files changed, 37 insertions(+) create mode 100644 src/video_core/pica.h diff --git a/src/video_core/pica.h b/src/video_core/pica.h new file mode 100644 index 000000000..dab861408 --- /dev/null +++ b/src/video_core/pica.h @@ -0,0 +1,35 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/bit_field.h" +#include "common/common_types.h" + +namespace Pica { + +enum class CommandId : u32 +{ + ViewportSizeX = 0x41, + ViewportInvSizeX = 0x42, + ViewportSizeY = 0x43, + ViewportInvSizeY = 0x44, + ViewportCorner = 0x68, + DepthBufferFormat = 0x116, + ColorBufferFormat = 0x117, + DepthBufferAddress = 0x11C, + ColorBufferAddress = 0x11D, + ColorBufferSize = 0x11E, +}; + +union CommandHeader { + u32 hex; + + BitField< 0, 16, CommandId> cmd_id; + BitField<16, 4, u32> parameter_mask; + BitField<20, 11, u32> extra_data_length; + BitField<31, 1, u32> group_commands; +}; + +} diff --git a/src/video_core/video_core.vcxproj b/src/video_core/video_core.vcxproj index a4df92386..d77be2bef 100644 --- a/src/video_core/video_core.vcxproj +++ b/src/video_core/video_core.vcxproj @@ -25,6 +25,7 @@ + diff --git a/src/video_core/video_core.vcxproj.filters b/src/video_core/video_core.vcxproj.filters index cc173a718..b89ac1ac4 100644 --- a/src/video_core/video_core.vcxproj.filters +++ b/src/video_core/video_core.vcxproj.filters @@ -17,6 +17,7 @@ renderer_opengl + From 90fd4e111cc74dd06beba60c653404bf08f757a0 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sun, 18 May 2014 17:28:30 +0200 Subject: [PATCH 21/29] GPU debugger: Add functionality to inspect command lists. --- src/core/hle/service/gsp.cpp | 4 +++ src/video_core/gpu_debugger.h | 54 ++++++++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp.cpp index 15e9d19a5..aabcb48db 100644 --- a/src/core/hle/service/gsp.cpp +++ b/src/core/hle/service/gsp.cpp @@ -126,6 +126,10 @@ void TriggerCmdReqQueue(Service::Interface* self) { GPU::Write(GPU::Registers::CommandListAddress, cmd_buff[1] >> 3); GPU::Write(GPU::Registers::CommandListSize, cmd_buff[2] >> 3); GPU::Write(GPU::Registers::ProcessCommandList, 1); // TODO: Not sure if we are supposed to always write this + + // TODO: Move this to GPU + // TODO: Not sure what units the size is measured in + g_debugger.CommandListCalled(cmd_buff[1], (u32*)Memory::GetPointer(cmd_buff[1]), cmd_buff[2]); break; case GXCommandId::SET_MEMORY_FILL: diff --git a/src/video_core/gpu_debugger.h b/src/video_core/gpu_debugger.h index ace9de95f..4dafd3146 100644 --- a/src/video_core/gpu_debugger.h +++ b/src/video_core/gpu_debugger.h @@ -11,11 +11,23 @@ #include "common/log.h" #include "core/hle/service/gsp.h" - +#include "pica.h" class GraphicsDebugger { public: + // A few utility structs used to expose data + // A vector of commands represented by their raw byte sequence + struct PicaCommand : public std::vector + { + Pica::CommandHeader& GetHeader() + { + return *(Pica::CommandHeader*)&(front()); + } + }; + + typedef std::vector PicaCommandList; + // Base class for all objects which need to be notified about GPU events class DebuggerObserver { @@ -40,6 +52,16 @@ public: ERROR_LOG(GSP, "Received command: id=%x", cmd.id); } + /** + * @param lst command list which triggered this call + * @param is_new true if the command list was called for the first time + * @todo figure out how to make sure called functions don't keep references around beyond their life time + */ + virtual void CommandListCalled(const PicaCommandList& lst, bool is_new) + { + ERROR_LOG(GSP, "Command list called: %d", (int)is_new); + } + protected: GraphicsDebugger* GetDebugger() { @@ -66,12 +88,39 @@ public: } ); } + void CommandListCalled(u32 address, u32* command_list, u32 size_in_words) + { + // TODO: Decoding fun + + // For now, just treating the whole command list as a single command + PicaCommandList cmdlist; + cmdlist.push_back(PicaCommand()); + auto& cmd = cmdlist[0]; + cmd.reserve(size_in_words); + std::copy(command_list, command_list+size_in_words, std::back_inserter(cmd)); + + auto obj = std::pair(address, cmdlist); + auto it = std::find(command_lists.begin(), command_lists.end(), obj); + bool is_new = (it == command_lists.end()); + if (is_new) + command_lists.push_back(obj); + + ForEachObserver([&](DebuggerObserver* observer) { + observer->CommandListCalled(obj.second, is_new); + } ); + } + const GSP_GPU::GXCommand& ReadGXCommandHistory(int index) const { // TODO: Is this thread-safe? return gx_command_history[index]; } + const std::vector>& GetCommandLists() const + { + return command_lists; + } + void RegisterObserver(DebuggerObserver* observer) { // TODO: Check for duplicates @@ -94,4 +143,7 @@ private: std::vector observers; std::vector gx_command_history; + + // vector of pairs of command lists and their storage address + std::vector> command_lists; }; From 9fbfd928a1f5a1c6efd80165350a3f3dd20cadb9 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sun, 18 May 2014 17:52:22 +0200 Subject: [PATCH 22/29] citra-qt: Add command list view. --- src/citra_qt/CMakeLists.txt | 2 + src/citra_qt/citra_qt.vcxproj | 2 + src/citra_qt/citra_qt.vcxproj.filters | 6 ++ src/citra_qt/debugger/graphics_cmdlists.cpp | 65 +++++++++++++++++++++ src/citra_qt/debugger/graphics_cmdlists.hxx | 44 ++++++++++++++ src/citra_qt/main.cpp | 6 ++ src/citra_qt/main.hxx | 2 + src/video_core/gpu_debugger.h | 4 +- 8 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 src/citra_qt/debugger/graphics_cmdlists.cpp create mode 100644 src/citra_qt/debugger/graphics_cmdlists.hxx diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 1968e34d3..7f880df8b 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -3,6 +3,7 @@ set(SRCS debugger/callstack.cpp debugger/disassembler.cpp debugger/graphics.cpp + debugger/graphics_cmdlists.cpp debugger/ramview.cpp debugger/registers.cpp hotkeys.cpp @@ -40,6 +41,7 @@ qt4_wrap_cpp(MOC_SRCS debugger/callstack.hxx debugger/disassembler.hxx debugger/graphics.hxx + debugger/graphics_cmdlists.hxx debugger/registers.hxx debugger/ramview.hxx hotkeys.hxx diff --git a/src/citra_qt/citra_qt.vcxproj b/src/citra_qt/citra_qt.vcxproj index a1b24f676..c99c8eeee 100644 --- a/src/citra_qt/citra_qt.vcxproj +++ b/src/citra_qt/citra_qt.vcxproj @@ -131,6 +131,7 @@ + @@ -146,6 +147,7 @@ + diff --git a/src/citra_qt/citra_qt.vcxproj.filters b/src/citra_qt/citra_qt.vcxproj.filters index faa4d9f52..903082c3c 100644 --- a/src/citra_qt/citra_qt.vcxproj.filters +++ b/src/citra_qt/citra_qt.vcxproj.filters @@ -42,6 +42,9 @@ debugger + + debugger + debugger @@ -74,6 +77,9 @@ debugger + + debugger + debugger diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp new file mode 100644 index 000000000..576882e8a --- /dev/null +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -0,0 +1,65 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "graphics_cmdlists.hxx" +#include + +extern GraphicsDebugger g_debugger; + +GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(parent), row_count(0) +{ + connect(this, SIGNAL(CommandListCalled()), this, SLOT(OnCommandListCalledInternal()), Qt::UniqueConnection); +} + +int GPUCommandListModel::rowCount(const QModelIndex& parent) const +{ + return row_count; +} + +QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + int idx = index.row(); + if (role == Qt::DisplayRole) + { + QString content; + const GraphicsDebugger::PicaCommandList& cmdlist = command_list[idx].second; + for (int i = 0; i < cmdlist.size(); ++i) + { + const GraphicsDebugger::PicaCommand& cmd = cmdlist[i]; + for (int j = 0; j < cmd.size(); ++j) + content.append(QString("%1 ").arg(cmd[j], 8, 16, QLatin1Char('0'))); + } + return QVariant(content); + } + return QVariant(); +} + +void GPUCommandListModel::OnCommandListCalled(const GraphicsDebugger::PicaCommandList& lst, bool is_new) +{ + emit CommandListCalled(); +} + + +void GPUCommandListModel::OnCommandListCalledInternal() +{ + beginResetModel(); + + command_list = GetDebugger()->GetCommandLists(); + row_count = command_list.size(); + + endResetModel(); +} + +GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pica Command List"), parent) +{ + GPUCommandListModel* model = new GPUCommandListModel(this); + g_debugger.RegisterObserver(model); + + QListView* list_widget = new QListView; + list_widget->setModel(model); + setWidget(list_widget); +} diff --git a/src/citra_qt/debugger/graphics_cmdlists.hxx b/src/citra_qt/debugger/graphics_cmdlists.hxx new file mode 100644 index 000000000..bac23c643 --- /dev/null +++ b/src/citra_qt/debugger/graphics_cmdlists.hxx @@ -0,0 +1,44 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "video_core/gpu_debugger.h" + +class GPUCommandListModel : public QAbstractListModel, public GraphicsDebugger::DebuggerObserver +{ + Q_OBJECT + +public: + GPUCommandListModel(QObject* parent); + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + +public: + void OnCommandListCalled(const GraphicsDebugger::PicaCommandList& lst, bool is_new) override; + +public slots: + void OnCommandListCalledInternal(); + +signals: + void CommandListCalled(); + +private: + int row_count; + std::vector> command_list; +}; + +class GPUCommandListWidget : public QDockWidget +{ + Q_OBJECT + +public: + GPUCommandListWidget(QWidget* parent = 0); + +private: +}; diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 79367c3ed..087716c01 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -20,6 +20,7 @@ #include "debugger/callstack.hxx" #include "debugger/ramview.hxx" #include "debugger/graphics.hxx" +#include "debugger/graphics_cmdlists.hxx" #include "core/system.h" #include "core/loader.h" @@ -52,11 +53,16 @@ GMainWindow::GMainWindow() addDockWidget(Qt::RightDockWidgetArea, graphicsWidget); callstackWidget->hide(); + graphicsCommandsWidget = new GPUCommandListWidget(this); + addDockWidget(Qt::RightDockWidgetArea, graphicsCommandsWidget); + callstackWidget->hide(); + QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); debug_menu->addAction(disasmWidget->toggleViewAction()); debug_menu->addAction(registersWidget->toggleViewAction()); debug_menu->addAction(callstackWidget->toggleViewAction()); debug_menu->addAction(graphicsWidget->toggleViewAction()); + debug_menu->addAction(graphicsCommandsWidget->toggleViewAction()); // Set default UI state // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half diff --git a/src/citra_qt/main.hxx b/src/citra_qt/main.hxx index 100bdbd00..6bcb37a30 100644 --- a/src/citra_qt/main.hxx +++ b/src/citra_qt/main.hxx @@ -11,6 +11,7 @@ class DisassemblerWidget; class RegistersWidget; class CallstackWidget; class GPUCommandStreamWidget; +class GPUCommandListWidget; class GMainWindow : public QMainWindow { @@ -52,6 +53,7 @@ private: RegistersWidget* registersWidget; CallstackWidget* callstackWidget; GPUCommandStreamWidget* graphicsWidget; + GPUCommandListWidget* graphicsCommandsWidget; }; #endif // _CITRA_QT_MAIN_HXX_ diff --git a/src/video_core/gpu_debugger.h b/src/video_core/gpu_debugger.h index 4dafd3146..7ad595493 100644 --- a/src/video_core/gpu_debugger.h +++ b/src/video_core/gpu_debugger.h @@ -57,7 +57,7 @@ public: * @param is_new true if the command list was called for the first time * @todo figure out how to make sure called functions don't keep references around beyond their life time */ - virtual void CommandListCalled(const PicaCommandList& lst, bool is_new) + virtual void OnCommandListCalled(const PicaCommandList& lst, bool is_new) { ERROR_LOG(GSP, "Command list called: %d", (int)is_new); } @@ -106,7 +106,7 @@ public: command_lists.push_back(obj); ForEachObserver([&](DebuggerObserver* observer) { - observer->CommandListCalled(obj.second, is_new); + observer->OnCommandListCalled(obj.second, is_new); } ); } From 8f1c9984722adaa06736ef9f18d8de6ca83f4bb4 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sun, 18 May 2014 19:59:36 +0200 Subject: [PATCH 23/29] Refine command list debugging functionality and its qt interface. --- src/citra_qt/debugger/graphics_cmdlists.cpp | 98 +++++++++++++++++---- src/citra_qt/debugger/graphics_cmdlists.hxx | 28 +++++- src/video_core/gpu_debugger.h | 23 +++-- src/video_core/pica.h | 2 + 4 files changed, 124 insertions(+), 27 deletions(-) diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index 576882e8a..d07645e78 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -3,18 +3,57 @@ // Refer to the license.txt file included. #include "graphics_cmdlists.hxx" -#include +#include extern GraphicsDebugger g_debugger; -GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(parent), row_count(0) +GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractItemModel(parent) { + root_item = new TreeItem(TreeItem::ROOT, 0, NULL, this); + connect(this, SIGNAL(CommandListCalled()), this, SLOT(OnCommandListCalledInternal()), Qt::UniqueConnection); } +QModelIndex GPUCommandListModel::index(int row, int column, const QModelIndex& parent) const +{ + TreeItem* item; + + if (!parent.isValid()) { + item = root_item; + } else { + item = (TreeItem*)parent.internalPointer(); + } + + return createIndex(row, column, item->children[row]); +} + +QModelIndex GPUCommandListModel::parent(const QModelIndex& child) const +{ + if (!child.isValid()) + return QModelIndex(); + + TreeItem* item = (TreeItem*)child.internalPointer(); + + if (item->parent == NULL) + return QModelIndex(); + + return createIndex(item->parent->index, 0, item->parent); +} + int GPUCommandListModel::rowCount(const QModelIndex& parent) const { - return row_count; + TreeItem* item; + if (!parent.isValid()) { + item = root_item; + } else { + item = (TreeItem*)parent.internalPointer(); + } + return item->children.size(); +} + +int GPUCommandListModel::columnCount(const QModelIndex& parent) const +{ + return 1; } QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const @@ -22,19 +61,33 @@ QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const if (!index.isValid()) return QVariant(); - int idx = index.row(); - if (role == Qt::DisplayRole) + const TreeItem* item = (const TreeItem*)index.internalPointer(); + + if (item->type == TreeItem::COMMAND_LIST) { - QString content; - const GraphicsDebugger::PicaCommandList& cmdlist = command_list[idx].second; - for (int i = 0; i < cmdlist.size(); ++i) + const GraphicsDebugger::PicaCommandList& cmdlist = command_lists[item->index].second; + u32 address = command_lists[item->index].first; + + if (role == Qt::DisplayRole) { - const GraphicsDebugger::PicaCommand& cmd = cmdlist[i]; + return QVariant(QString("0x%1 bytes at 0x%2").arg(cmdlist.size(), 0, 16).arg(address, 8, 16, QLatin1Char('0'))); + } + } + else + { + // index refers to a specific command + const GraphicsDebugger::PicaCommandList& cmdlist = command_lists[item->parent->index].second; + const GraphicsDebugger::PicaCommand& cmd = cmdlist[item->index]; + + if (role == Qt::DisplayRole) { + QString content; for (int j = 0; j < cmd.size(); ++j) content.append(QString("%1 ").arg(cmd[j], 8, 16, QLatin1Char('0'))); + + return QVariant(content); } - return QVariant(content); } + return QVariant(); } @@ -48,8 +101,22 @@ void GPUCommandListModel::OnCommandListCalledInternal() { beginResetModel(); - command_list = GetDebugger()->GetCommandLists(); - row_count = command_list.size(); + command_lists = GetDebugger()->GetCommandLists(); + + // delete root item and rebuild tree + delete root_item; + root_item = new TreeItem(TreeItem::ROOT, 0, NULL, this); + + for (int command_list_idx = 0; command_list_idx < command_lists.size(); ++command_list_idx) { + TreeItem* command_list_item = new TreeItem(TreeItem::COMMAND_LIST, command_list_idx, root_item, root_item); + root_item->children.push_back(command_list_item); + + const GraphicsDebugger::PicaCommandList& command_list = command_lists[command_list_idx].second; + for (int command_idx = 0; command_idx < command_list.size(); ++command_idx) { + TreeItem* command_item = new TreeItem(TreeItem::COMMAND, command_idx, command_list_item, command_list_item); + command_list_item->children.push_back(command_item); + } + } endResetModel(); } @@ -59,7 +126,8 @@ GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pi GPUCommandListModel* model = new GPUCommandListModel(this); g_debugger.RegisterObserver(model); - QListView* list_widget = new QListView; - list_widget->setModel(model); - setWidget(list_widget); + QTreeView* tree_widget = new QTreeView; + tree_widget->setModel(model); + tree_widget->setFont(QFont("monospace")); + setWidget(tree_widget); } diff --git a/src/citra_qt/debugger/graphics_cmdlists.hxx b/src/citra_qt/debugger/graphics_cmdlists.hxx index bac23c643..b4e6e3c8a 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.hxx +++ b/src/citra_qt/debugger/graphics_cmdlists.hxx @@ -4,18 +4,22 @@ #pragma once -#include +#include #include #include "video_core/gpu_debugger.h" -class GPUCommandListModel : public QAbstractListModel, public GraphicsDebugger::DebuggerObserver +// TODO: Rename class, since it's not actually a list model anymore... +class GPUCommandListModel : public QAbstractItemModel, public GraphicsDebugger::DebuggerObserver { Q_OBJECT public: GPUCommandListModel(QObject* parent); + QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex& child) const; + int columnCount(const QModelIndex& parent = QModelIndex()) const; int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; @@ -29,8 +33,24 @@ signals: void CommandListCalled(); private: - int row_count; - std::vector> command_list; + struct TreeItem : public QObject + { + enum Type { + ROOT, + COMMAND_LIST, + COMMAND + }; + + TreeItem(Type type, int index, TreeItem* item_parent, QObject* parent) : QObject(parent), type(type), index(index), parent(item_parent) {} + + Type type; + int index; + std::vector children; + TreeItem* parent; + }; + + std::vector> command_lists; + TreeItem* root_item; }; class GPUCommandListWidget : public QDockWidget diff --git a/src/video_core/gpu_debugger.h b/src/video_core/gpu_debugger.h index 7ad595493..5ece0a8b7 100644 --- a/src/video_core/gpu_debugger.h +++ b/src/video_core/gpu_debugger.h @@ -22,7 +22,8 @@ public: { Pica::CommandHeader& GetHeader() { - return *(Pica::CommandHeader*)&(front()); + u32& val = at(1); + return *(Pica::CommandHeader*)&val; } }; @@ -90,14 +91,20 @@ public: void CommandListCalled(u32 address, u32* command_list, u32 size_in_words) { - // TODO: Decoding fun - - // For now, just treating the whole command list as a single command PicaCommandList cmdlist; - cmdlist.push_back(PicaCommand()); - auto& cmd = cmdlist[0]; - cmd.reserve(size_in_words); - std::copy(command_list, command_list+size_in_words, std::back_inserter(cmd)); + for (u32* parse_pointer = command_list; parse_pointer < command_list + size_in_words;) + { + const Pica::CommandHeader header = static_cast(parse_pointer[1]); + + cmdlist.push_back(PicaCommand()); + auto& cmd = cmdlist.back(); + + size_t size = 2 + header.extra_data_length; + cmd.reserve(size); + std::copy(parse_pointer, parse_pointer + size, std::back_inserter(cmd)); + + parse_pointer += size; + } auto obj = std::pair(address, cmdlist); auto it = std::find(command_lists.begin(), command_lists.end(), obj); diff --git a/src/video_core/pica.h b/src/video_core/pica.h index dab861408..8ebe0dc3c 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -24,6 +24,8 @@ enum class CommandId : u32 }; union CommandHeader { + CommandHeader(u32 h) : hex(h) {} + u32 hex; BitField< 0, 16, CommandId> cmd_id; From 2cf87fb10a4fc10921e9e7a5f2ce1738589f2a82 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sun, 18 May 2014 21:18:38 +0200 Subject: [PATCH 24/29] Further refine GPU command list debugging. --- src/citra_qt/debugger/graphics_cmdlists.cpp | 14 ++++++++++---- src/video_core/gpu_debugger.h | 1 + src/video_core/pica.h | 16 ++++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index d07645e78..195197ef5 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -53,7 +53,7 @@ int GPUCommandListModel::rowCount(const QModelIndex& parent) const int GPUCommandListModel::columnCount(const QModelIndex& parent) const { - return 1; + return 2; } QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const @@ -68,7 +68,7 @@ QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const const GraphicsDebugger::PicaCommandList& cmdlist = command_lists[item->index].second; u32 address = command_lists[item->index].first; - if (role == Qt::DisplayRole) + if (role == Qt::DisplayRole && index.column() == 0) { return QVariant(QString("0x%1 bytes at 0x%2").arg(cmdlist.size(), 0, 16).arg(address, 8, 16, QLatin1Char('0'))); } @@ -78,11 +78,17 @@ QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const // index refers to a specific command const GraphicsDebugger::PicaCommandList& cmdlist = command_lists[item->parent->index].second; const GraphicsDebugger::PicaCommand& cmd = cmdlist[item->index]; + const Pica::CommandHeader& header = cmd.GetHeader(); if (role == Qt::DisplayRole) { QString content; - for (int j = 0; j < cmd.size(); ++j) - content.append(QString("%1 ").arg(cmd[j], 8, 16, QLatin1Char('0'))); + if (index.column() == 0) { + content = Pica::command_names[header.cmd_id]; + content.append(" "); + } else if (index.column() == 1) { + for (int j = 0; j < cmd.size(); ++j) + content.append(QString("%1 ").arg(cmd[j], 8, 16, QLatin1Char('0'))); + } return QVariant(content); } diff --git a/src/video_core/gpu_debugger.h b/src/video_core/gpu_debugger.h index 5ece0a8b7..6a1e04244 100644 --- a/src/video_core/gpu_debugger.h +++ b/src/video_core/gpu_debugger.h @@ -100,6 +100,7 @@ public: auto& cmd = cmdlist.back(); size_t size = 2 + header.extra_data_length; + size = (size + 1) / 2 * 2; // align to 8 bytes cmd.reserve(size); std::copy(parse_pointer, parse_pointer + size, std::back_inserter(cmd)); diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 8ebe0dc3c..7cbc45f98 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -4,6 +4,9 @@ #pragma once +#include +#include + #include "common/bit_field.h" #include "common/common_types.h" @@ -34,4 +37,17 @@ union CommandHeader { BitField<31, 1, u32> group_commands; }; +static std::map command_names = { + {CommandId::ViewportSizeX, "ViewportSizeX" }, + {CommandId::ViewportInvSizeX, "ViewportInvSizeX" }, + {CommandId::ViewportSizeY, "ViewportSizeY" }, + {CommandId::ViewportInvSizeY, "ViewportInvSizeY" }, + {CommandId::ViewportCorner, "ViewportCorner" }, + {CommandId::DepthBufferFormat, "DepthBufferFormat" }, + {CommandId::ColorBufferFormat, "ColorBufferFormat" }, + {CommandId::DepthBufferAddress, "DepthBufferAddress" }, + {CommandId::ColorBufferAddress, "ColorBufferAddress" }, + {CommandId::ColorBufferSize, "ColorBufferSize" }, +}; + } From d8148eaa6b9dbb81bc3d71f07663ed929e4d577e Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sun, 18 May 2014 22:50:41 +0200 Subject: [PATCH 25/29] Pica: Use some template magic to define register structures efficiently. --- src/common/common.vcxproj | 3 +- src/common/common.vcxproj.filters | 5 +- src/common/register_set.h | 161 ++++++++++++++++++++++++++++++ src/video_core/pica.h | 127 ++++++++++++++++++----- 4 files changed, 268 insertions(+), 28 deletions(-) create mode 100644 src/common/register_set.h diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index 86295a480..1f5c714c3 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -182,6 +182,7 @@ + @@ -221,4 +222,4 @@ - \ No newline at end of file + diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index 84cfa8837..e8c4ce360 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters @@ -4,6 +4,7 @@ + @@ -28,6 +29,7 @@ + @@ -39,7 +41,6 @@ - @@ -65,4 +66,4 @@ - \ No newline at end of file + diff --git a/src/common/register_set.h b/src/common/register_set.h new file mode 100644 index 000000000..0418551b3 --- /dev/null +++ b/src/common/register_set.h @@ -0,0 +1,161 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +// Copyright 2014 Tony Wasserka +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the owner nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/* + * Standardized way to define a group of registers and corresponding data structures. To define + * a new register set, first define struct containing an enumeration called "Id" containing + * all register IDs and a template union called "Struct". Specialize the Struct union for any + * register ID which needs to be accessed in a specialized way. You can then declare the object + * containing all register values using the RegisterSet type, where + * BaseType is the underlying type of each register (e.g. u32). + * Of course, you'll usually want to implement the Struct template such that they are of the same + * size as BaseType. However, it's also possible to make it larger, e.g. when you want to describe + * multiple registers with the same structure. + * + * Example: + * + * struct Regs { + * enum Id : u32 { + * Value1 = 0, + * Value2 = 1, + * Value3 = 2, + * NumIds = 3 + * }; + * + * // declare register definition structures + * template + * union Struct; + * }; + * + * // Define register set object + * RegisterSet registers; + * + * // define register definition structures + * template<> + * union Regs::Struct { + * BitField<0, 4, u32> some_field; + * BitField<4, 3, u32> some_other_field; + * }; + * + * Usage in external code (within SomeNamespace scope): + * + * For a register which maps to a single index: + * registers.Get().some_field = some_value; + * + * For a register which maps to different indices, e.g. a group of similar registers + * registers.Get(index).some_field = some_value; + * + * + * @tparam BaseType Base type used for storing individual registers, e.g. u32 + * @tparam RegDefinition Class defining an enumeration called "Id" and a template union, as described above. + * @note RegDefinition::Id needs to have an enum value called NumIds defining the number of registers to be allocated. + */ +template +struct RegisterSet { + // Register IDs + using Id = typename RegDefinition::Id; + + // type used for *this + using ThisType = RegisterSet; + + // Register definition structs, defined in RegDefinition + template + using Struct = typename RegDefinition::template Struct; + + + /* + * Lookup register with the given id and return it as the corresponding structure type. + * @note This just forwards the arguments to Get(Id). + */ + template + const Struct& Get() const { + return Get(id); + } + + /* + * Lookup register with the given id and return it as the corresponding structure type. + * @note This just forwards the arguments to Get(Id). + */ + template + Struct& Get() { + return Get(id); + } + + /* + * Lookup register with the given index and return it as the corresponding structure type. + * @todo Is this portable with regards to structures larger than BaseType? + * @note if index==id, you don't need to specify the function parameter. + */ + template + const Struct& Get(const Id& index) const { + const int idx = static_cast(index); + return *reinterpret_cast*>(&raw[idx]); + } + + /* + * Lookup register with the given index and return it as the corresponding structure type. + * @note This just forwards the arguments to the const version of Get(Id). + * @note if index==id, you don't need to specify the function parameter. + */ + template + Struct& Get(const Id& index) { + return const_cast&>(GetThis().Get(index)); + } + + /* + * Plain array access. + * @note If you want to have this casted to a register defininition struct, use Get() instead. + */ + const BaseType& operator[] (const Id& id) const { + return raw[static_cast(id)]; + } + + /* + * Plain array access. + * @note If you want to have this casted to a register defininition struct, use Get() instead. + * @note This operator just forwards its argument to the const version. + */ + BaseType& operator[] (const Id& id) { + return const_cast(GetThis()[id]); + } + +private: + /* + * Returns a const reference to "this". + */ + const ThisType& GetThis() const { + return static_cast(*this); + } + + BaseType raw[Id::NumIds]; +}; diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 7cbc45f98..f0fa3aba9 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -9,45 +9,122 @@ #include "common/bit_field.h" #include "common/common_types.h" +#include "common/register_set.h" namespace Pica { -enum class CommandId : u32 -{ - ViewportSizeX = 0x41, - ViewportInvSizeX = 0x42, - ViewportSizeY = 0x43, - ViewportInvSizeY = 0x44, - ViewportCorner = 0x68, - DepthBufferFormat = 0x116, - ColorBufferFormat = 0x117, - DepthBufferAddress = 0x11C, - ColorBufferAddress = 0x11D, - ColorBufferSize = 0x11E, +struct Regs { + enum Id : u32 { + ViewportSizeX = 0x41, + ViewportInvSizeX = 0x42, + ViewportSizeY = 0x43, + ViewportInvSizeY = 0x44, + ViewportCorner = 0x68, + DepthBufferFormat = 0x116, + ColorBufferFormat = 0x117, + DepthBufferAddress = 0x11C, + ColorBufferAddress = 0x11D, + ColorBufferSize = 0x11E, + + VertexArrayBaseAddr = 0x200, + VertexDescriptor = 0x201, // 0x202 + VertexAttributeOffset = 0x203, // 0x206,0x209,0x20C,0x20F,0x212,0x215,0x218,0x21B,0x21E,0x221,0x224 + VertexAttributeInfo0 = 0x204, // 0x207,0x20A,0x20D,0x210,0x213,0x216,0x219,0x21C,0x21F,0x222,0x225 + VertexAttributeInfo1 = 0x205, // 0x208,0x20B,0x20E,0x211,0x214,0x217,0x21A,0x21D,0x220,0x223,0x226 + + NumIds = 0x300, + }; + + template + union Struct; }; +static inline Regs::Id VertexAttributeOffset(int n) +{ + return static_cast(0x203 + 3*n); +} + +static inline Regs::Id VertexAttributeInfo0(int n) +{ + return static_cast(0x204 + 3*n); +} + +static inline Regs::Id VertexAttributeInfo1(int n) +{ + return static_cast(0x205 + 3*n); +} + union CommandHeader { CommandHeader(u32 h) : hex(h) {} u32 hex; - BitField< 0, 16, CommandId> cmd_id; + BitField< 0, 16, Regs::Id> cmd_id; BitField<16, 4, u32> parameter_mask; BitField<20, 11, u32> extra_data_length; BitField<31, 1, u32> group_commands; }; -static std::map command_names = { - {CommandId::ViewportSizeX, "ViewportSizeX" }, - {CommandId::ViewportInvSizeX, "ViewportInvSizeX" }, - {CommandId::ViewportSizeY, "ViewportSizeY" }, - {CommandId::ViewportInvSizeY, "ViewportInvSizeY" }, - {CommandId::ViewportCorner, "ViewportCorner" }, - {CommandId::DepthBufferFormat, "DepthBufferFormat" }, - {CommandId::ColorBufferFormat, "ColorBufferFormat" }, - {CommandId::DepthBufferAddress, "DepthBufferAddress" }, - {CommandId::ColorBufferAddress, "ColorBufferAddress" }, - {CommandId::ColorBufferSize, "ColorBufferSize" }, +static std::map command_names = { + {Regs::ViewportSizeX, "ViewportSizeX" }, + {Regs::ViewportInvSizeX, "ViewportInvSizeX" }, + {Regs::ViewportSizeY, "ViewportSizeY" }, + {Regs::ViewportInvSizeY, "ViewportInvSizeY" }, + {Regs::ViewportCorner, "ViewportCorner" }, + {Regs::DepthBufferFormat, "DepthBufferFormat" }, + {Regs::ColorBufferFormat, "ColorBufferFormat" }, + {Regs::DepthBufferAddress, "DepthBufferAddress" }, + {Regs::ColorBufferAddress, "ColorBufferAddress" }, + {Regs::ColorBufferSize, "ColorBufferSize" }, }; -} +template<> +union Regs::Struct { + BitField<0, 24, u32> value; +}; + +template<> +union Regs::Struct { + BitField<0, 24, u32> value; +}; + +template<> +union Regs::Struct { + enum class Format : u64 { + BYTE = 0, + UBYTE = 1, + SHORT = 2, + FLOAT = 3, + }; + + BitField< 0, 2, Format> format0; + BitField< 2, 2, u64> size0; // number of elements minus 1 + BitField< 4, 2, Format> format1; + BitField< 6, 2, u64> size1; + BitField< 8, 2, Format> format2; + BitField<10, 2, u64> size2; + BitField<12, 2, Format> format3; + BitField<14, 2, u64> size3; + BitField<16, 2, Format> format4; + BitField<18, 2, u64> size4; + BitField<20, 2, Format> format5; + BitField<22, 2, u64> size5; + BitField<24, 2, Format> format6; + BitField<26, 2, u64> size6; + BitField<28, 2, Format> format7; + BitField<30, 2, u64> size7; + BitField<32, 2, Format> format8; + BitField<34, 2, u64> size8; + BitField<36, 2, Format> format9; + BitField<38, 2, u64> size9; + BitField<40, 2, Format> format10; + BitField<42, 2, u64> size10; + BitField<44, 2, Format> format11; + BitField<46, 2, u64> size11; + + BitField<48, 12, u64> attribute_mask; + BitField<60, 4, u64> num_attributes; // number of total attributes minus 1 +}; + + +} // namespace From b7be03fd2cf96a1cc91baa9ef906ca0e5f9c6893 Mon Sep 17 00:00:00 2001 From: inspuration Date: Mon, 9 Jun 2014 14:42:01 -0400 Subject: [PATCH 26/29] Added preliminary support for shared memory objects and handles. --- src/core/CMakeLists.txt | 2 ++ src/core/core.vcxproj | 2 ++ src/core/core.vcxproj.filters | 6 ++++ src/core/hle/kernel/kernel.h | 1 + src/core/hle/kernel/shared_memory.cpp | 48 +++++++++++++++++++++++++++ src/core/hle/kernel/shared_memory.h | 20 +++++++++++ src/core/hle/service/gsp.cpp | 1 + src/core/hle/service/hid.cpp | 9 ++++- src/core/hle/svc.cpp | 2 +- src/core/hw/hid.cpp | 2 +- 10 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 src/core/hle/kernel/shared_memory.cpp create mode 100644 src/core/hle/kernel/shared_memory.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index d29183899..c6b32da93 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -37,6 +37,7 @@ set(SRCS core.cpp hle/kernel/kernel.cpp hle/kernel/mutex.cpp hle/kernel/thread.cpp + hle/kernel/shared_memory.cpp hle/service/apt.cpp hle/service/gsp.cpp hle/service/hid.cpp @@ -82,6 +83,7 @@ set(HEADERS core.h hle/svc.h hle/kernel/kernel.h hle/kernel/mutex.h + hle/kernel/shared_memory.h hle/kernel/thread.h hle/function_wrappers.h hle/service/apt.h diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index 621aa60b8..2989d001a 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -180,6 +180,7 @@ + @@ -230,6 +231,7 @@ + diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index 3cf702d44..bd86cc332 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -168,6 +168,9 @@ hw + + hle\kernel + @@ -301,6 +304,9 @@ hw + + hle\kernel + diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 7cd79c2c4..3c9a40286 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -94,6 +94,7 @@ public: template T *GetFast(Handle handle) { const Handle realHandle = handle - HANDLE_OFFSET; + //bravia note: there is a weird bug caused here which puts the processor into thumb mode _dbg_assert_(KERNEL, realHandle >= 0 && realHandle < MAX_COUNT && occupied[realHandle]); return static_cast(pool[realHandle]); } diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp new file mode 100644 index 000000000..dc9c66ea1 --- /dev/null +++ b/src/core/hle/kernel/shared_memory.cpp @@ -0,0 +1,48 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include + +#include "common/common.h" + +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/thread.h" + +namespace Kernel { + +class SharedMemory : public Object { +public: + const char* GetTypeName() { return "SharedMemory"; } + + static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; } + Kernel::HandleType GetHandleType() const { return Kernel::HandleType::SharedMemory; } + + //TODO: implement +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + + + +/** +* Creates a mutex +* @param handle Reference to handle for the newly created mutex +* @param initial_locked Specifies if the mutex should be locked initially +*/ +SharedMemory* CreateSharedMemory(Handle& handle) { + SharedMemory* mem = new SharedMemory; + handle = Kernel::g_object_pool.Create(mem); + + return mem; +} + + +Handle CreateSharedMemory() { + Handle handle; + SharedMemory* mem = CreateSharedMemory(handle); + return handle; +} + +} // namespace diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h new file mode 100644 index 000000000..993e0a856 --- /dev/null +++ b/src/core/hle/kernel/shared_memory.h @@ -0,0 +1,20 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" + +namespace Kernel { + +/** +* Creates a shared memory object +* @param handle Reference to handle for the newly created mutex +* @param +*/ +Handle CreateSharedMemory(); + +} // namespace diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp.cpp index 50cee2c41..e59479f15 100644 --- a/src/core/hle/service/gsp.cpp +++ b/src/core/hle/service/gsp.cpp @@ -102,6 +102,7 @@ void RegisterInterruptRelayQueue(Service::Interface* self) { u32 flags = cmd_buff[1]; u32 event_handle = cmd_buff[3]; // TODO(bunnei): Implement event handling cmd_buff[2] = g_thread_id; // ThreadID + //TODO(bravia): Implement shared memory handling } /// This triggers handling of the GX command written to the command buffer in shared memory. diff --git a/src/core/hle/service/hid.cpp b/src/core/hle/service/hid.cpp index 5542e5bf2..4bada30b5 100644 --- a/src/core/hle/service/hid.cpp +++ b/src/core/hle/service/hid.cpp @@ -6,14 +6,21 @@ #include "core/hle/hle.h" #include "core/hle/service/hid.h" +#include "core/hle/kernel/shared_memory.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace HID_User namespace HID_User { +void GetIPCHandles(Service::Interface* self) { + u32* cmd_buff = Service::GetCommandBuffer(); + Handle memHandle = Kernel::CreateSharedMemory(); + cmd_buff[3] = memHandle; //TODO: return something coherent along with RegisterInterruptRelayQueue for mem handles +} + const Interface::FunctionInfo FunctionTable[] = { - {0x000A0000, NULL, "GetIPCHandles"}, + {0x000A0000, GetIPCHandles, "GetIPCHandles" }, {0x00110000, NULL, "EnableAccelerometer"}, {0x00130000, NULL, "EnableGyroscopeLow"}, {0x00150000, NULL, "GetGyroscopeLowRawToDpsCoefficient"}, diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 4cf2d96ad..c58ab594b 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -67,7 +67,7 @@ Result ControlMemory(void* _outaddr, u32 operation, u32 addr0, u32 addr1, u32 si /// Maps a memory block to specified address Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) { - DEBUG_LOG(SVC, "MapMemoryBlock called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", + DEBUG_LOG(SVC, "MapMemoryBlock called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", memblock, addr, mypermissions, otherpermission); switch (mypermissions) { case MEMORY_PERMISSION_NORMAL: diff --git a/src/core/hw/hid.cpp b/src/core/hw/hid.cpp index a1b4b139c..8197b8394 100644 --- a/src/core/hw/hid.cpp +++ b/src/core/hw/hid.cpp @@ -1,6 +1,6 @@ #include "hid.h" - +//TODO: http://pastebin.com/kkGLQhHV namespace HID { template From fc191a34904e8c6a0e4c40425457a5b389d4b529 Mon Sep 17 00:00:00 2001 From: inspuration Date: Mon, 9 Jun 2014 15:52:51 -0400 Subject: [PATCH 27/29] Fixed build errors and runtime errors in new gpu debugger menus. --- src/citra_qt/debugger/graphics_cmdlists.cpp | 9 ++++++++- src/video_core/gpu_debugger.h | 6 +++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index 195197ef5..081c63ff0 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -17,6 +17,7 @@ GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractItemModel(p QModelIndex GPUCommandListModel::index(int row, int column, const QModelIndex& parent) const { TreeItem* item; + TreeItem* internal; if (!parent.isValid()) { item = root_item; @@ -24,7 +25,13 @@ QModelIndex GPUCommandListModel::index(int row, int column, const QModelIndex& p item = (TreeItem*)parent.internalPointer(); } - return createIndex(row, column, item->children[row]); + if (item->children.size() <= row) { + internal = item; + } + else { internal = item->children[row]; } + + + return createIndex(row, column, internal); } QModelIndex GPUCommandListModel::parent(const QModelIndex& child) const diff --git a/src/video_core/gpu_debugger.h b/src/video_core/gpu_debugger.h index 6a1e04244..13edb9a47 100644 --- a/src/video_core/gpu_debugger.h +++ b/src/video_core/gpu_debugger.h @@ -20,9 +20,9 @@ public: // A vector of commands represented by their raw byte sequence struct PicaCommand : public std::vector { - Pica::CommandHeader& GetHeader() + Pica::CommandHeader& GetHeader() const { - u32& val = at(1); + const u32& val = at(1); return *(Pica::CommandHeader*)&val; } }; @@ -64,7 +64,7 @@ public: } protected: - GraphicsDebugger* GetDebugger() + GraphicsDebugger* GetDebugger() const { return observed; } From ff95b7ea2446aa91c6a43758894a87e6368a34e7 Mon Sep 17 00:00:00 2001 From: inspuration Date: Mon, 9 Jun 2014 16:29:22 -0400 Subject: [PATCH 28/29] updated gitignore --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 10ad35373..092e70089 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,8 @@ bin/ # Generated source files src/common/scm_rev.cpp +citra_qtRelease.psess +citra_qtRelease140529.vspx +msvcp100d.dll +Performance1.psess +Report20140529-0000.vspx From 53d6c7a0785de40f1000ebbffe6614097e78f8ac Mon Sep 17 00:00:00 2001 From: inspuration Date: Mon, 9 Jun 2014 22:14:11 -0400 Subject: [PATCH 29/29] Updated gitignore --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 092e70089..704ce0e47 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,9 @@ citra_qtRelease140529.vspx msvcp100d.dll Performance1.psess Report20140529-0000.vspx +src/citra_qt/ui_callstack.h +src/citra_qt/ui_controller_config.h +src/citra_qt/ui_disassembler.h +src/citra_qt/ui_hotkeys.h +src/citra_qt/ui_main.h +src/citra_qt/ui_registers.h