Merge branch 'master' into threading
Conflicts: src/core/core.vcxproj.filters src/core/hle/function_wrappers.h src/core/hle/service/gsp.cpp src/core/hle/service/hid.cpp src/core/hle/svc.cpp
This commit is contained in:
commit
1d6ea166c1
47 changed files with 1769 additions and 96 deletions
11
.gitignore
vendored
11
.gitignore
vendored
|
@ -25,3 +25,14 @@ bin/
|
|||
|
||||
# Generated source files
|
||||
src/common/scm_rev.cpp
|
||||
citra_qtRelease.psess
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
|
|
102
CONTRIBUTING.md
Normal file
102
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,102 @@
|
|||
# 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
|
||||
* 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;
|
||||
|
||||
default:
|
||||
// Yes, even break for the last case
|
||||
break;
|
||||
}
|
||||
|
||||
std::vector
|
||||
you_can_declare,
|
||||
a_few,
|
||||
variables,
|
||||
like_this;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
|
@ -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
|
||||
|
||||
|
|
|
@ -2,9 +2,12 @@ set(SRCS
|
|||
bootmanager.cpp
|
||||
debugger/callstack.cpp
|
||||
debugger/disassembler.cpp
|
||||
debugger/graphics.cpp
|
||||
debugger/graphics_cmdlists.cpp
|
||||
debugger/ramview.cpp
|
||||
debugger/registers.cpp
|
||||
hotkeys.cpp
|
||||
key_bindings.cpp
|
||||
main.cpp
|
||||
config/controller_config.cpp
|
||||
config/controller_config_util.cpp)
|
||||
|
@ -15,11 +18,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 +36,7 @@ qt4_wrap_ui(UI_HDRS
|
|||
debugger/disassembler.ui
|
||||
debugger/registers.ui
|
||||
hotkeys.ui
|
||||
key_bindings.ui
|
||||
main.ui
|
||||
config/controller_config.ui)
|
||||
|
||||
|
@ -38,9 +44,12 @@ qt4_wrap_cpp(MOC_SRCS
|
|||
bootmanager.hxx
|
||||
debugger/callstack.hxx
|
||||
debugger/disassembler.hxx
|
||||
debugger/graphics.hxx
|
||||
debugger/graphics_cmdlists.hxx
|
||||
debugger/registers.hxx
|
||||
debugger/ramview.hxx
|
||||
hotkeys.hxx
|
||||
key_bindings.hxx
|
||||
main.hxx
|
||||
config/controller_config.hxx
|
||||
config/controller_config_util.hxx)
|
||||
|
|
|
@ -3,10 +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/hid.h"
|
||||
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
|
@ -119,6 +122,8 @@ GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this
|
|||
setLayout(layout);
|
||||
|
||||
BackupGeometry();
|
||||
|
||||
buttonReg = 0x0;
|
||||
}
|
||||
|
||||
GRenderWindow::~GRenderWindow()
|
||||
|
@ -192,12 +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);
|
||||
*/
|
||||
|
||||
|
||||
buttonReg |= GetKeyBinding(event);
|
||||
HID::SetButtonReg(buttonReg);
|
||||
return;
|
||||
}
|
||||
|
||||
void GRenderWindow::keyReleaseEvent(QKeyEvent* event)
|
||||
|
@ -211,4 +221,7 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event)
|
|||
if (!key_processed)
|
||||
QWidget::keyPressEvent(event);
|
||||
*/
|
||||
|
||||
buttonReg &= 0xffffffff ^ GetKeyBinding(event);
|
||||
HID::SetButtonReg(buttonReg);
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
#include <QThread>
|
||||
#include <QGLWidget>
|
||||
#include <map>
|
||||
#include "common/common.h"
|
||||
#include "common/emu_window.h"
|
||||
|
||||
|
@ -109,4 +110,6 @@ private:
|
|||
EmuThread emu_thread;
|
||||
|
||||
QByteArray geometry;
|
||||
|
||||
u32 buttonReg;
|
||||
};
|
||||
|
|
|
@ -130,11 +130,14 @@
|
|||
<ClCompile Include="config\controller_config.cpp" />
|
||||
<ClCompile Include="config\controller_config_util.cpp" />
|
||||
<ClCompile Include="debugger\callstack.cpp" />
|
||||
<ClCompile Include="debugger\graphics.cpp" />
|
||||
<ClCompile Include="debugger\graphics_cmdlists.cpp" />
|
||||
<ClCompile Include="debugger\registers.cpp" />
|
||||
<ClCompile Include="debugger\disassembler.cpp" />
|
||||
<ClCompile Include="debugger\ramview.cpp" />
|
||||
<ClCompile Include="bootmanager.cpp" />
|
||||
<ClCompile Include="hotkeys.cpp" />
|
||||
<ClCompile Include="key_bindings.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -143,11 +146,14 @@
|
|||
<MOC Include="..\..\externals\qhexedit\qhexedit_p.h" />
|
||||
<MOC Include="..\..\externals\qhexedit\xbytearray.h" />
|
||||
<MOC Include="debugger\callstack.hxx" />
|
||||
<MOC Include="debugger\registers.hxx" />
|
||||
<MOC Include="debugger\disassembler.hxx" />
|
||||
<MOC Include="debugger\graphics.hxx" />
|
||||
<MOC Include="debugger\graphics_cmdlists.hxx" />
|
||||
<MOC Include="debugger\ramview.hxx" />
|
||||
<MOC Include="debugger\registers.hxx" />
|
||||
<MOC Include="bootmanager.hxx" />
|
||||
<MOC Include="hotkeys.hxx" />
|
||||
<MOC Include="key_bindings.hxx" />
|
||||
<MOC Include="main.hxx" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -173,6 +179,7 @@
|
|||
<UIC Include="debugger\registers.ui" />
|
||||
<UIC Include="debugger\disassembler.ui" />
|
||||
<UIC Include="hotkeys.ui" />
|
||||
<UIC Include="key_bindings.ui" />
|
||||
<UIC Include="main.ui" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -36,15 +36,22 @@
|
|||
<ClCompile Include="debugger\callstack.cpp">
|
||||
<Filter>debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="debugger\ramview.cpp">
|
||||
<ClCompile Include="debugger\disassembler.cpp">
|
||||
<Filter>debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="debugger\disassembler.cpp">
|
||||
<ClCompile Include="debugger\graphics.cpp">
|
||||
<Filter>debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="debugger\graphics_cmdlists.cpp">
|
||||
<Filter>debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="debugger\ramview.cpp">
|
||||
<Filter>debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="debugger\registers.cpp">
|
||||
<Filter>debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="key_bindings.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MOC Include="..\..\externals\qhexedit\commands.h">
|
||||
|
@ -65,15 +72,22 @@
|
|||
<MOC Include="debugger\callstack.hxx">
|
||||
<Filter>debugger</Filter>
|
||||
</MOC>
|
||||
<MOC Include="debugger\ramview.hxx">
|
||||
<MOC Include="debugger\disassembler.hxx">
|
||||
<Filter>debugger</Filter>
|
||||
</MOC>
|
||||
<MOC Include="debugger\disassembler.hxx">
|
||||
<MOC Include="debugger\graphics.hxx">
|
||||
<Filter>debugger</Filter>
|
||||
</MOC>
|
||||
<MOC Include="debugger\graphics_cmdlists.hxx">
|
||||
<Filter>debugger</Filter>
|
||||
</MOC>
|
||||
<MOC Include="debugger\ramview.hxx">
|
||||
<Filter>debugger</Filter>
|
||||
</MOC>
|
||||
<MOC Include="debugger\registers.hxx">
|
||||
<Filter>debugger</Filter>
|
||||
</MOC>
|
||||
<MOC Include="key_bindings.hxx" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="version.h" />
|
||||
|
@ -102,6 +116,7 @@
|
|||
<UIC Include="debugger\registers.ui">
|
||||
<Filter>debugger</Filter>
|
||||
</UIC>
|
||||
<UIC Include="key_bindings.ui" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
|
|
83
src/citra_qt/debugger/graphics.cpp
Normal file
83
src/citra_qt/debugger/graphics.cpp
Normal file
|
@ -0,0 +1,83 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "graphics.hxx"
|
||||
#include <QListView>
|
||||
#include <QVBoxLayout>
|
||||
#include <QDebug>
|
||||
|
||||
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<GSP_GPU::GXCommandId, const char*> 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<GSP_GPU::GXCommandId>(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);
|
||||
}
|
43
src/citra_qt/debugger/graphics.hxx
Normal file
43
src/citra_qt/debugger/graphics.hxx
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QDockWidget>
|
||||
|
||||
#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:
|
||||
};
|
146
src/citra_qt/debugger/graphics_cmdlists.cpp
Normal file
146
src/citra_qt/debugger/graphics_cmdlists.cpp
Normal file
|
@ -0,0 +1,146 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "graphics_cmdlists.hxx"
|
||||
#include <QTreeView>
|
||||
|
||||
extern GraphicsDebugger g_debugger;
|
||||
|
||||
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;
|
||||
TreeItem* internal;
|
||||
|
||||
if (!parent.isValid()) {
|
||||
item = root_item;
|
||||
} else {
|
||||
item = (TreeItem*)parent.internalPointer();
|
||||
}
|
||||
|
||||
if (item->children.size() <= row) {
|
||||
internal = item;
|
||||
}
|
||||
else { internal = item->children[row]; }
|
||||
|
||||
|
||||
return createIndex(row, column, internal);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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 2;
|
||||
}
|
||||
|
||||
QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
const TreeItem* item = (const TreeItem*)index.internalPointer();
|
||||
|
||||
if (item->type == TreeItem::COMMAND_LIST)
|
||||
{
|
||||
const GraphicsDebugger::PicaCommandList& cmdlist = command_lists[item->index].second;
|
||||
u32 address = command_lists[item->index].first;
|
||||
|
||||
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')));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void GPUCommandListModel::OnCommandListCalled(const GraphicsDebugger::PicaCommandList& lst, bool is_new)
|
||||
{
|
||||
emit CommandListCalled();
|
||||
}
|
||||
|
||||
|
||||
void GPUCommandListModel::OnCommandListCalledInternal()
|
||||
{
|
||||
beginResetModel();
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pica Command List"), parent)
|
||||
{
|
||||
GPUCommandListModel* model = new GPUCommandListModel(this);
|
||||
g_debugger.RegisterObserver(model);
|
||||
|
||||
QTreeView* tree_widget = new QTreeView;
|
||||
tree_widget->setModel(model);
|
||||
tree_widget->setFont(QFont("monospace"));
|
||||
setWidget(tree_widget);
|
||||
}
|
64
src/citra_qt/debugger/graphics_cmdlists.hxx
Normal file
64
src/citra_qt/debugger/graphics_cmdlists.hxx
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QDockWidget>
|
||||
|
||||
#include "video_core/gpu_debugger.h"
|
||||
|
||||
// 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;
|
||||
|
||||
public:
|
||||
void OnCommandListCalled(const GraphicsDebugger::PicaCommandList& lst, bool is_new) override;
|
||||
|
||||
public slots:
|
||||
void OnCommandListCalledInternal();
|
||||
|
||||
signals:
|
||||
void CommandListCalled();
|
||||
|
||||
private:
|
||||
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<TreeItem*> children;
|
||||
TreeItem* parent;
|
||||
};
|
||||
|
||||
std::vector<std::pair<u32,GraphicsDebugger::PicaCommandList>> command_lists;
|
||||
TreeItem* root_item;
|
||||
};
|
||||
|
||||
class GPUCommandListWidget : public QDockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GPUCommandListWidget(QWidget* parent = 0);
|
||||
|
||||
private:
|
||||
};
|
143
src/citra_qt/key_bindings.cpp
Normal file
143
src/citra_qt/key_bindings.cpp
Normal file
|
@ -0,0 +1,143 @@
|
|||
#include <QKeySequence>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QSettings>
|
||||
#include <QKeyEvent>
|
||||
#include "key_bindings.hxx"
|
||||
#include <map>
|
||||
#include "core/hw/hid.h"
|
||||
|
||||
typedef std::map<QKeySequence, HID::PAD> BindingsMap;
|
||||
|
||||
BindingsMap bindings;
|
||||
|
||||
|
||||
typedef std::map<HID::PAD, QKeySequence> ReverseBindingsMap;
|
||||
|
||||
ReverseBindingsMap reverseBindings;
|
||||
|
||||
|
||||
typedef std::map<HID::PAD, QString> NameMap;
|
||||
|
||||
NameMap names;
|
||||
|
||||
typedef std::map<QString, HID::PAD> ReverseNameMap;
|
||||
|
||||
ReverseNameMap reverseNames;
|
||||
|
||||
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<QString>::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;
|
||||
reverseBindings[pad] = keySeq;
|
||||
}
|
||||
|
||||
void createNameMap() {
|
||||
for (int i = 0; i < HID::numPadItems; 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)]; //TODO: sanitise
|
||||
reverseBindings[reverseNames[item->text(0)]] = item->text(1);
|
||||
return;
|
||||
}
|
||||
|
||||
GKeyBindingsDialog::GKeyBindingsDialog(QWidget* parent) : QDialog(parent)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
|
||||
createNameMap();
|
||||
|
||||
for (NameMap::iterator key = names.begin(); key != names.end(); ++key)
|
||||
{
|
||||
QKeySequence keySeq = reverseBindings[key->first];
|
||||
QStringList columns;
|
||||
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));
|
||||
|
||||
}
|
62
src/citra_qt/key_bindings.hxx
Normal file
62
src/citra_qt/key_bindings.hxx
Normal file
|
@ -0,0 +1,62 @@
|
|||
#include <QDialog>
|
||||
#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);
|
||||
|
||||
|
||||
/**
|
||||
* Sets default key bindings.
|
||||
*
|
||||
*
|
||||
*/
|
||||
void setDefaultKeyBindings();
|
||||
|
||||
|
||||
class GKeyBindingsDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GKeyBindingsDialog(QWidget* parent = NULL);
|
||||
|
||||
private:
|
||||
Ui::key_bindings ui;
|
||||
|
||||
private slots:
|
||||
void updateItem(QTreeWidgetItem * item, int column);
|
||||
};
|
89
src/citra_qt/key_bindings.ui
Normal file
89
src/citra_qt/key_bindings.ui
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>key_bindings</class>
|
||||
<widget class="QDialog" name="key_bindings">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>363</width>
|
||||
<height>388</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Key Bindings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="treeWidget">
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectItems</enum>
|
||||
</property>
|
||||
<property name="headerHidden">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Action</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Key</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Pad</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>key_bindings</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>key_bindings</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
|
@ -13,12 +13,15 @@
|
|||
|
||||
#include "bootmanager.hxx"
|
||||
#include "hotkeys.hxx"
|
||||
#include "key_bindings.hxx"
|
||||
|
||||
//debugger
|
||||
#include "debugger/disassembler.hxx"
|
||||
#include "debugger/registers.hxx"
|
||||
#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"
|
||||
|
@ -47,10 +50,20 @@ GMainWindow::GMainWindow()
|
|||
addDockWidget(Qt::RightDockWidgetArea, callstackWidget);
|
||||
callstackWidget->hide();
|
||||
|
||||
graphicsWidget = new GPUCommandStreamWidget(this);
|
||||
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
|
||||
|
@ -80,7 +93,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 +109,11 @@ 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
|
||||
setDefaultKeyBindings();
|
||||
LoadKeyBindings(settings);
|
||||
|
||||
|
||||
setWindowTitle(render_window->GetWindowTitle().c_str());
|
||||
|
||||
show();
|
||||
|
@ -187,6 +206,13 @@ void GMainWindow::OnOpenHotkeysDialog()
|
|||
}
|
||||
|
||||
|
||||
void GMainWindow::OnOpenKeyBindingsDialog()
|
||||
{
|
||||
GKeyBindingsDialog dialog(this);
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
|
||||
void GMainWindow::ToggleWindowMode()
|
||||
{
|
||||
bool enable = ui.action_Popout_Window_Mode->isChecked();
|
||||
|
|
|
@ -10,6 +10,8 @@ class GRenderWindow;
|
|||
class DisassemblerWidget;
|
||||
class RegistersWidget;
|
||||
class CallstackWidget;
|
||||
class GPUCommandStreamWidget;
|
||||
class GPUCommandListWidget;
|
||||
|
||||
class GMainWindow : public QMainWindow
|
||||
{
|
||||
|
@ -39,6 +41,7 @@ private slots:
|
|||
void OnMenuLoadFile();
|
||||
void OnMenuLoadSymbolMap();
|
||||
void OnOpenHotkeysDialog();
|
||||
void OnOpenKeyBindingsDialog();
|
||||
void OnConfigure();
|
||||
void ToggleWindowMode();
|
||||
|
||||
|
@ -50,6 +53,8 @@ private:
|
|||
DisassemblerWidget* disasmWidget;
|
||||
RegistersWidget* registersWidget;
|
||||
CallstackWidget* callstackWidget;
|
||||
GPUCommandStreamWidget* graphicsWidget;
|
||||
GPUCommandListWidget* graphicsCommandsWidget;
|
||||
};
|
||||
|
||||
#endif // _CITRA_QT_MAIN_HXX_
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
<addaction name="action_Stop"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_Configure"/>
|
||||
<addaction name="action_Key_Bindings"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_View">
|
||||
<property name="title">
|
||||
|
@ -127,6 +128,11 @@
|
|||
<string>Configure &Hotkeys ...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Key_Bindings">
|
||||
<property name="text">
|
||||
<string>Set Key Bindings</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Configure">
|
||||
<property name="text">
|
||||
<string>Configure ...</string>
|
||||
|
|
77
src/citra_qt/ui_key_bindings.h
Normal file
77
src/citra_qt/ui_key_bindings.h
Normal file
|
@ -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 <QtCore/QVariant>
|
||||
#include <QtGui/QAction>
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QButtonGroup>
|
||||
#include <QtGui/QDialog>
|
||||
#include <QtGui/QDialogButtonBox>
|
||||
#include <QtGui/QHeaderView>
|
||||
#include <QtGui/QTreeWidget>
|
||||
#include <QtGui/QVBoxLayout>
|
||||
|
||||
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
|
|
@ -182,6 +182,7 @@
|
|||
<ClInclude Include="mem_arena.h" />
|
||||
<ClInclude Include="msg_handler.h" />
|
||||
<ClInclude Include="platform.h" />
|
||||
<ClInclude Include="register_set.h" />
|
||||
<ClInclude Include="scm_rev.h" />
|
||||
<ClInclude Include="std_condition_variable.h" />
|
||||
<ClInclude Include="std_mutex.h" />
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<ClInclude Include="atomic.h" />
|
||||
<ClInclude Include="atomic_gcc.h" />
|
||||
<ClInclude Include="atomic_win32.h" />
|
||||
<ClInclude Include="bit_field.h" />
|
||||
<ClInclude Include="break_points.h" />
|
||||
<ClInclude Include="chunk_file.h" />
|
||||
<ClInclude Include="common.h" />
|
||||
|
@ -28,6 +29,7 @@
|
|||
<ClInclude Include="memory_util.h" />
|
||||
<ClInclude Include="msg_handler.h" />
|
||||
<ClInclude Include="platform.h" />
|
||||
<ClInclude Include="register_set.h" />
|
||||
<ClInclude Include="std_condition_variable.h" />
|
||||
<ClInclude Include="std_mutex.h" />
|
||||
<ClInclude Include="std_thread.h" />
|
||||
|
@ -39,7 +41,6 @@
|
|||
<ClInclude Include="utf8.h" />
|
||||
<ClInclude Include="symbols.h" />
|
||||
<ClInclude Include="scm_rev.h" />
|
||||
<ClInclude Include="bit_field.h" />
|
||||
<ClInclude Include="thread_queue_list.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -63,10 +63,11 @@ enum LOG_TYPE {
|
|||
NDMA,
|
||||
HLE,
|
||||
RENDER,
|
||||
LCD,
|
||||
GPU,
|
||||
HW,
|
||||
TIME,
|
||||
NETPLAY,
|
||||
HID,
|
||||
|
||||
NUMBER_OF_LOGS // Must be last
|
||||
};
|
||||
|
|
|
@ -67,7 +67,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");
|
||||
|
@ -75,6 +75,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::HID] = new LogContainer("HID", "Human Interface Devices");
|
||||
|
||||
m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str());
|
||||
m_consoleLog = new ConsoleListener();
|
||||
|
|
161
src/common/register_set.h
Normal file
161
src/common/register_set.h
Normal file
|
@ -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<BaseType, DefiningStruct> 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<Id id>
|
||||
* union Struct;
|
||||
* };
|
||||
*
|
||||
* // Define register set object
|
||||
* RegisterSet<u32, CommandIds> registers;
|
||||
*
|
||||
* // define register definition structures
|
||||
* template<>
|
||||
* union Regs::Struct<Regs::Value1> {
|
||||
* 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<Regs::Value1>().some_field = some_value;
|
||||
*
|
||||
* For a register which maps to different indices, e.g. a group of similar registers
|
||||
* registers.Get<Regs::Value1>(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<Id id> union, as described above.
|
||||
* @note RegDefinition::Id needs to have an enum value called NumIds defining the number of registers to be allocated.
|
||||
*/
|
||||
template<typename BaseType, typename RegDefinition>
|
||||
struct RegisterSet {
|
||||
// Register IDs
|
||||
using Id = typename RegDefinition::Id;
|
||||
|
||||
// type used for *this
|
||||
using ThisType = RegisterSet<BaseType, RegDefinition>;
|
||||
|
||||
// Register definition structs, defined in RegDefinition
|
||||
template<Id id>
|
||||
using Struct = typename RegDefinition::template Struct<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<Id id>
|
||||
const Struct<id>& Get() const {
|
||||
return Get<id>(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<Id id>
|
||||
Struct<id>& Get() {
|
||||
return Get<id>(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<Id id>
|
||||
const Struct<id>& Get(const Id& index) const {
|
||||
const int idx = static_cast<size_t>(index);
|
||||
return *reinterpret_cast<const Struct<id>*>(&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<Id id>
|
||||
Struct<id>& Get(const Id& index) {
|
||||
return const_cast<Struct<id>&>(GetThis().Get<id>(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<size_t>(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<BaseType&>(GetThis()[id]);
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
* Returns a const reference to "this".
|
||||
*/
|
||||
const ThisType& GetThis() const {
|
||||
return static_cast<const ThisType&>(*this);
|
||||
}
|
||||
|
||||
BaseType raw[Id::NumIds];
|
||||
};
|
|
@ -38,15 +38,17 @@ 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
|
||||
hle/service/ndm.cpp
|
||||
hle/service/service.cpp
|
||||
hle/service/srv.cpp
|
||||
hw/gpu.cpp
|
||||
hw/hw.cpp
|
||||
hw/lcd.cpp
|
||||
hw/ndma.cpp)
|
||||
hw/ndma.cpp
|
||||
hw/hid.cpp)
|
||||
|
||||
set(HEADERS core.h
|
||||
core_timing.h
|
||||
|
@ -83,6 +85,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
|
||||
|
@ -90,8 +93,9 @@ 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)
|
||||
hw/ndma.h
|
||||
hw/hid.h)
|
||||
|
||||
add_library(core STATIC ${SRCS} ${HEADERS})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -99,6 +99,9 @@
|
|||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<ClCompile />
|
||||
<ClCompile>
|
||||
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile />
|
||||
|
@ -106,6 +109,9 @@
|
|||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<ClCompile />
|
||||
<ClCompile>
|
||||
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile />
|
||||
|
@ -120,6 +126,7 @@
|
|||
<FloatingPointModel>Fast</FloatingPointModel>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
|
||||
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
@ -130,6 +137,9 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
<ClCompile />
|
||||
<ClCompile>
|
||||
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\common\common.vcxproj">
|
||||
|
@ -171,6 +181,7 @@
|
|||
<ClCompile Include="hle\kernel\event.cpp" />
|
||||
<ClCompile Include="hle\kernel\kernel.cpp" />
|
||||
<ClCompile Include="hle\kernel\mutex.cpp" />
|
||||
<ClCompile Include="hle\kernel\shared_memory.cpp" />
|
||||
<ClCompile Include="hle\kernel\thread.cpp" />
|
||||
<ClCompile Include="hle\service\apt.cpp" />
|
||||
<ClCompile Include="hle\service\gsp.cpp" />
|
||||
|
@ -179,9 +190,10 @@
|
|||
<ClCompile Include="hle\service\service.cpp" />
|
||||
<ClCompile Include="hle\service\srv.cpp" />
|
||||
<ClCompile Include="hle\svc.cpp" />
|
||||
<ClCompile Include="hw\gpu.cpp" />
|
||||
<ClCompile Include="hw\hw.cpp" />
|
||||
<ClCompile Include="hw\lcd.cpp" />
|
||||
<ClCompile Include="hw\ndma.cpp" />
|
||||
<ClCompile Include="hw\hid.cpp" />
|
||||
<ClCompile Include="loader.cpp" />
|
||||
<ClCompile Include="mem_map.cpp" />
|
||||
<ClCompile Include="mem_map_funcs.cpp" />
|
||||
|
@ -222,6 +234,7 @@
|
|||
<ClInclude Include="hle\kernel\event.h" />
|
||||
<ClInclude Include="hle\kernel\kernel.h" />
|
||||
<ClInclude Include="hle\kernel\mutex.h" />
|
||||
<ClInclude Include="hle\kernel\shared_memory.h" />
|
||||
<ClInclude Include="hle\kernel\thread.h" />
|
||||
<ClInclude Include="hle\service\apt.h" />
|
||||
<ClInclude Include="hle\service\gsp.h" />
|
||||
|
@ -230,9 +243,10 @@
|
|||
<ClInclude Include="hle\service\service.h" />
|
||||
<ClInclude Include="hle\service\srv.h" />
|
||||
<ClInclude Include="hle\svc.h" />
|
||||
<ClInclude Include="hw\gpu.h" />
|
||||
<ClInclude Include="hw\hw.h" />
|
||||
<ClInclude Include="hw\lcd.h" />
|
||||
<ClInclude Include="hw\ndma.h" />
|
||||
<ClInclude Include="hw\hid.h" />
|
||||
<ClInclude Include="loader.h" />
|
||||
<ClInclude Include="mem_map.h" />
|
||||
<ClInclude Include="system.h" />
|
||||
|
|
|
@ -102,7 +102,7 @@
|
|||
<ClCompile Include="hw\ndma.cpp">
|
||||
<Filter>hw</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hw\lcd.cpp">
|
||||
<ClCompile Include="hw\gpu.cpp">
|
||||
<Filter>hw</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="arm\disassembler\load_symbol_map.cpp">
|
||||
|
@ -165,9 +165,13 @@
|
|||
<ClCompile Include="arm\interpreter\armcopro.cpp">
|
||||
<Filter>arm\interpreter</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hw\hid.cpp">
|
||||
<Filter>hw</Filter>
|
||||
<ClCompile Include="hle\kernel\event.cpp">
|
||||
<Filter>hle\kernel</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hle\kernel\shared_memory.cpp">
|
||||
<Filter>hle\kernel</Filter>
|
||||
<ClCompile Include="hle\service\ndm.cpp">
|
||||
<Filter>hle\service</Filter>
|
||||
</ClCompile>
|
||||
|
@ -250,7 +254,7 @@
|
|||
<ClInclude Include="hw\ndma.h">
|
||||
<Filter>hw</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hw\lcd.h">
|
||||
<ClInclude Include="hw\gpu.h">
|
||||
<Filter>hw</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="arm\disassembler\load_symbol_map.h">
|
||||
|
@ -307,6 +311,12 @@
|
|||
<ClInclude Include="hle\service\ndm.h">
|
||||
<Filter>hle\service</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hw\hid.h">
|
||||
<Filter>hw</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hle\kernel\shared_memory.h">
|
||||
<Filter>hle\kernel</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
|
|
|
@ -116,6 +116,7 @@ public:
|
|||
template <class T>
|
||||
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<T*>(pool[realHandle]);
|
||||
}
|
||||
|
|
48
src/core/hle/kernel/shared_memory.cpp
Normal file
48
src/core/hle/kernel/shared_memory.cpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#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
|
20
src/core/hle/kernel/shared_memory.h
Normal file
20
src/core/hle/kernel/shared_memory.h
Normal file
|
@ -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
|
|
@ -11,10 +11,15 @@
|
|||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/service/gsp.h"
|
||||
|
||||
#include "core/hw/lcd.h"
|
||||
#include "core/hw/gpu.h"
|
||||
|
||||
#include "video_core/gpu_debugger.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 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;
|
||||
|
@ -29,7 +34,6 @@ union GX_CmdBufferHeader {
|
|||
// 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,7 +49,11 @@ 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?
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -56,10 +64,6 @@ namespace GSP_GPU {
|
|||
Handle g_event_handle = 0;
|
||||
u32 g_thread_id = 0;
|
||||
|
||||
enum {
|
||||
CMD_GX_REQUEST_DMA = 0x00000000,
|
||||
};
|
||||
|
||||
enum {
|
||||
REG_FRAMEBUFFER_1 = 0x00400468,
|
||||
REG_FRAMEBUFFER_2 = 0x00400494,
|
||||
|
@ -67,8 +71,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];
|
||||
|
@ -83,13 +87,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;
|
||||
|
||||
|
@ -117,20 +121,49 @@ void RegisterInterruptRelayQueue(Service::Interface* self) {
|
|||
Kernel::SetPermanentLock(event_handle, true);
|
||||
|
||||
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.
|
||||
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<GXCommandId>(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:
|
||||
GPU::Write<u32>(GPU::Registers::CommandListAddress, cmd_buff[1] >> 3);
|
||||
GPU::Write<u32>(GPU::Registers::CommandListSize, cmd_buff[2] >> 3);
|
||||
GPU::Write<u32>(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:
|
||||
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, "unknown command 0x%08X", cmd_buff[0]);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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, nullptr, "GetIPCHandles"},
|
||||
{0x000A0000, GetIPCHandles, "GetIPCHandles" },
|
||||
{0x00110000, nullptr, "EnableAccelerometer"},
|
||||
{0x00130000, nullptr, "EnableGyroscopeLow"},
|
||||
{0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"},
|
||||
|
|
|
@ -59,7 +59,7 @@ Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 siz
|
|||
|
||||
/// Maps a memory block to specified address
|
||||
Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) {
|
||||
DEBUG_LOG(SVC, "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:
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
|
||||
#include "core/core.h"
|
||||
#include "core/mem_map.h"
|
||||
#include "core/hw/lcd.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hw/gpu.h"
|
||||
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
#include "core/hle/kernel/thread.h"
|
||||
|
||||
namespace LCD {
|
||||
namespace GPU {
|
||||
|
||||
Registers g_regs;
|
||||
|
||||
|
@ -59,7 +59,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;
|
||||
}
|
||||
|
@ -76,7 +76,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;
|
||||
}
|
||||
|
@ -84,34 +84,73 @@ const u8* GetFramebufferPointer(const u32 address) {
|
|||
template <typename T>
|
||||
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 Registers::CommandListSize:
|
||||
var = g_regs.command_list_size;
|
||||
break;
|
||||
|
||||
case Registers::CommandListAddress:
|
||||
var = g_regs.command_list_address;
|
||||
break;
|
||||
|
||||
case Registers::ProcessCommandList:
|
||||
var = g_regs.command_processing_enabled;
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Write(u32 addr, const T data) {
|
||||
ERROR_LOG(LCD, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
|
||||
switch (static_cast<Registers::Id>(addr)) {
|
||||
case Registers::CommandListSize:
|
||||
g_regs.command_list_size = data;
|
||||
break;
|
||||
|
||||
case Registers::CommandListAddress:
|
||||
g_regs.command_list_address = data;
|
||||
break;
|
||||
|
||||
case Registers::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(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(GPU, "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:
|
||||
|
@ -142,12 +181,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
|
|
@ -6,12 +6,27 @@
|
|||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace LCD {
|
||||
namespace GPU {
|
||||
|
||||
static const u32 kFrameCycles = 268123480 / 60; ///< 268MHz / 60 frames per second
|
||||
static const u32 kFrameTicks = kFrameCycles / 3; ///< Approximate number of instructions/frame
|
||||
|
||||
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;
|
||||
|
@ -20,6 +35,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;
|
||||
|
@ -51,21 +70,10 @@ 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
|
||||
};
|
||||
|
||||
/// 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
|
||||
};
|
||||
|
35
src/core/hw/hid.cpp
Normal file
35
src/core/hw/hid.cpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include "hid.h"
|
||||
|
||||
//TODO: http://pastebin.com/kkGLQhHV
|
||||
namespace HID {
|
||||
|
||||
template <typename T>
|
||||
inline void Read(T &var, const u32 addr) {
|
||||
ERROR_LOG(HID, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Write(u32 addr, const T data) {
|
||||
ERROR_LOG(HID, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
|
||||
}
|
||||
|
||||
//TODO: replace with an interface that doesnt suck (bravia)
|
||||
void SetButtonReg(u32 buttonData) {
|
||||
Memory::Write32(VADDR_BUTTONS, buttonData);
|
||||
}
|
||||
|
||||
/// Update hardware
|
||||
void Update() {
|
||||
}
|
||||
|
||||
/// Initialize hardware
|
||||
void Init() {
|
||||
NOTICE_LOG(HID, "initialized OK");
|
||||
}
|
||||
|
||||
/// Shutdown hardware
|
||||
void Shutdown() {
|
||||
NOTICE_LOG(HID, "shutdown OK");
|
||||
}
|
||||
|
||||
}
|
73
src/core/hw/hid.h
Normal file
73
src/core/hw/hid.h
Normal file
|
@ -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 {
|
||||
VADDR_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 <typename T>
|
||||
inline void Read(T &var, const u32 addr);
|
||||
|
||||
template <typename T>
|
||||
inline void Write(u32 addr, const T data);
|
||||
|
||||
void SetButtonReg(u32 buttonData);
|
||||
|
||||
/// Update hardware
|
||||
void Update();
|
||||
|
||||
/// Initialize hardware
|
||||
void Init();
|
||||
|
||||
/// Shutdown hardware
|
||||
void Shutdown();
|
||||
}
|
||||
|
|
@ -6,8 +6,10 @@
|
|||
#include "common/log.h"
|
||||
|
||||
#include "core/hw/hw.h"
|
||||
#include "core/hw/lcd.h"
|
||||
#include "core/hw/gpu.h"
|
||||
#include "core/hw/ndma.h"
|
||||
#include "core/hw/hid.h"
|
||||
|
||||
|
||||
namespace HW {
|
||||
|
||||
|
@ -34,7 +36,7 @@ enum {
|
|||
VADDR_CDMA = 0xFFFDA000, // CoreLink DMA-330? Info
|
||||
VADDR_DSP_2 = 0x1ED03000,
|
||||
VADDR_HASH_2 = 0x1EE01000,
|
||||
VADDR_LCD = 0x1EF00000,
|
||||
VADDR_GPU = 0x1EF00000,
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -46,8 +48,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 +66,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,14 +89,16 @@ template void Write<u8>(u32 addr, const u8 data);
|
|||
|
||||
/// Update hardware
|
||||
void Update() {
|
||||
LCD::Update();
|
||||
GPU::Update();
|
||||
NDMA::Update();
|
||||
HID::Update();
|
||||
}
|
||||
|
||||
/// Initialize hardware
|
||||
void Init() {
|
||||
LCD::Init();
|
||||
GPU::Init();
|
||||
NDMA::Init();
|
||||
HID::Init();
|
||||
NOTICE_LOG(HW, "initialized OK");
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
157
src/video_core/gpu_debugger.h
Normal file
157
src/video_core/gpu_debugger.h
Normal file
|
@ -0,0 +1,157 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#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<u32>
|
||||
{
|
||||
Pica::CommandHeader& GetHeader() const
|
||||
{
|
||||
const u32& val = at(1);
|
||||
return *(Pica::CommandHeader*)&val;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector<PicaCommand> PicaCommandList;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 OnCommandListCalled(const PicaCommandList& lst, bool is_new)
|
||||
{
|
||||
ERROR_LOG(GSP, "Command list called: %d", (int)is_new);
|
||||
}
|
||||
|
||||
protected:
|
||||
GraphicsDebugger* GetDebugger() const
|
||||
{
|
||||
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());
|
||||
} );
|
||||
}
|
||||
|
||||
void CommandListCalled(u32 address, u32* command_list, u32 size_in_words)
|
||||
{
|
||||
PicaCommandList cmdlist;
|
||||
for (u32* parse_pointer = command_list; parse_pointer < command_list + size_in_words;)
|
||||
{
|
||||
const Pica::CommandHeader header = static_cast<Pica::CommandHeader>(parse_pointer[1]);
|
||||
|
||||
cmdlist.push_back(PicaCommand());
|
||||
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));
|
||||
|
||||
parse_pointer += size;
|
||||
}
|
||||
|
||||
auto obj = std::pair<u32,PicaCommandList>(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->OnCommandListCalled(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<std::pair<u32,PicaCommandList>>& GetCommandLists() const
|
||||
{
|
||||
return command_lists;
|
||||
}
|
||||
|
||||
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<void (DebuggerObserver*)> func)
|
||||
{
|
||||
std::for_each(observers.begin(),observers.end(), func);
|
||||
}
|
||||
|
||||
std::vector<DebuggerObserver*> observers;
|
||||
|
||||
std::vector<GSP_GPU::GXCommand> gx_command_history;
|
||||
|
||||
// vector of pairs of command lists and their storage address
|
||||
std::vector<std::pair<u32,PicaCommandList>> command_lists;
|
||||
};
|
130
src/video_core/pica.h
Normal file
130
src/video_core/pica.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/register_set.h"
|
||||
|
||||
namespace Pica {
|
||||
|
||||
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<Id id>
|
||||
union Struct;
|
||||
};
|
||||
|
||||
static inline Regs::Id VertexAttributeOffset(int n)
|
||||
{
|
||||
return static_cast<Regs::Id>(0x203 + 3*n);
|
||||
}
|
||||
|
||||
static inline Regs::Id VertexAttributeInfo0(int n)
|
||||
{
|
||||
return static_cast<Regs::Id>(0x204 + 3*n);
|
||||
}
|
||||
|
||||
static inline Regs::Id VertexAttributeInfo1(int n)
|
||||
{
|
||||
return static_cast<Regs::Id>(0x205 + 3*n);
|
||||
}
|
||||
|
||||
union CommandHeader {
|
||||
CommandHeader(u32 h) : hex(h) {}
|
||||
|
||||
u32 hex;
|
||||
|
||||
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<Regs::Id, const char*> 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<Regs::ViewportSizeX> {
|
||||
BitField<0, 24, u32> value;
|
||||
};
|
||||
|
||||
template<>
|
||||
union Regs::Struct<Regs::ViewportSizeY> {
|
||||
BitField<0, 24, u32> value;
|
||||
};
|
||||
|
||||
template<>
|
||||
union Regs::Struct<Regs::VertexDescriptor> {
|
||||
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
|
|
@ -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
|
||||
// ------------------------
|
||||
|
|
|
@ -24,10 +24,12 @@
|
|||
<ClCompile Include="video_core.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="gpu_debugger.h" />
|
||||
<ClInclude Include="pica.h" />
|
||||
<ClInclude Include="renderer_base.h" />
|
||||
<ClInclude Include="renderer_opengl\renderer_opengl.h" />
|
||||
<ClInclude Include="utils.h" />
|
||||
<ClInclude Include="video_core.h" />
|
||||
<ClInclude Include="renderer_opengl\renderer_opengl.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
<ClInclude Include="renderer_opengl\renderer_opengl.h">
|
||||
<Filter>renderer_opengl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="gpu_debugger.h" />
|
||||
<ClInclude Include="pica.h" />
|
||||
<ClInclude Include="renderer_base.h" />
|
||||
<ClInclude Include="utils.h" />
|
||||
<ClInclude Include="video_core.h" />
|
||||
|
|
Loading…
Reference in a new issue