aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/citra/resource.hbin898 -> 431 bytes
-rw-r--r--src/citra_qt/CMakeLists.txt6
-rw-r--r--src/citra_qt/bootmanager.cpp2
-rw-r--r--src/citra_qt/bootmanager.h2
-rw-r--r--src/citra_qt/debugger/callstack.cpp2
-rw-r--r--src/citra_qt/main.cpp2
-rw-r--r--src/citra_qt/main.ui17
-rw-r--r--src/common/emu_window.cpp2
-rw-r--r--src/common/file_util.cpp2
-rw-r--r--src/common/swap.h2
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/arm/disassembler/arm_disasm.cpp2
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp32
-rw-r--r--src/core/arm/dyncom/arm_dyncom_thumb.cpp2
-rw-r--r--src/core/arm/interpreter/armsupp.cpp2
-rw-r--r--src/core/arm/skyeye_common/armdefs.h6
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp_helper.h4
-rw-r--r--src/core/core_timing.cpp2
-rw-r--r--src/core/core_timing.h2
-rw-r--r--src/core/file_sys/archive_extsavedata.cpp4
-rw-r--r--src/core/file_sys/archive_extsavedata.h4
-rw-r--r--src/core/file_sys/archive_savedata.cpp2
-rw-r--r--src/core/hle/kernel/resource_limit.h8
-rw-r--r--src/core/hle/kernel/semaphore.cpp2
-rw-r--r--src/core/hle/kernel/thread.cpp8
-rw-r--r--src/core/hle/kernel/thread.h2
-rw-r--r--src/core/hle/kernel/timer.cpp2
-rw-r--r--src/core/hle/kernel/vm_manager.cpp245
-rw-r--r--src/core/hle/kernel/vm_manager.h200
-rw-r--r--src/core/hle/service/apt/apt.cpp4
-rw-r--r--src/core/hle/service/apt/apt.h8
-rw-r--r--src/core/hle/service/boss_p.h2
-rw-r--r--src/core/hle/service/boss_u.h2
-rw-r--r--src/core/hle/service/cam_u.cpp2
-rw-r--r--src/core/hle/service/cfg/cfg.cpp4
-rw-r--r--src/core/hle/service/fs/archive.cpp6
-rw-r--r--src/core/hle/service/fs/fs_user.cpp6
-rw-r--r--src/core/hle/service/gsp_gpu.cpp24
-rw-r--r--src/core/hle/service/hid/hid.cpp2
-rw-r--r--src/core/hle/service/hid/hid_spvr.cpp2
-rw-r--r--src/core/hle/service/hid/hid_user.h2
-rw-r--r--src/core/hle/service/ptm/ptm.h6
-rw-r--r--src/core/hle/service/ptm/ptm_play.cpp2
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/hle/service/soc_u.cpp30
-rw-r--r--src/core/hle/svc.cpp4
-rw-r--r--src/core/hw/gpu.cpp10
-rw-r--r--src/core/hw/lcd.cpp2
-rw-r--r--src/core/hw/lcd.h2
-rw-r--r--src/core/loader/3dsx.cpp2
-rw-r--r--src/core/mem_map.cpp55
-rw-r--r--src/core/mem_map.h8
-rw-r--r--src/core/memory.cpp12
-rw-r--r--src/core/memory.h2
-rw-r--r--src/core/memory_setup.h7
-rw-r--r--src/video_core/command_processor.cpp78
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp2
-rw-r--r--src/video_core/math.h2
-rw-r--r--src/video_core/pica.h86
-rw-r--r--src/video_core/rasterizer.cpp78
-rw-r--r--src/video_core/renderer_opengl/generated/gl_3_2_core.c16
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp12
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h3
-rw-r--r--src/video_core/renderer_opengl/gl_shaders.h24
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp13
-rw-r--r--src/video_core/renderer_opengl/gl_state.h4
-rw-r--r--src/video_core/renderer_opengl/pica_to_gl.h31
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp2
-rw-r--r--src/video_core/vertex_shader.cpp33
69 files changed, 908 insertions, 252 deletions
diff --git a/src/citra/resource.h b/src/citra/resource.h
index 0d42c8a8..12789642 100644
--- a/src/citra/resource.h
+++ b/src/citra/resource.h
Binary files differ
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index efccdbec..c0577938 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -89,15 +89,15 @@ if (Qt5_FOUND AND MSVC)
)
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
set(PLATFORMS ${DLL_DEST}platforms/)
-
+
# windows commandline expects the / to be \ so switch them
string(REPLACE "/" "\\" Qt5_DLL_DIR ${Qt5_DLL_DIR})
string(REPLACE "/" "\\" Qt5_PLATFORMS_DIR ${Qt5_PLATFORMS_DIR})
string(REPLACE "/" "\\" DLL_DEST ${DLL_DEST})
string(REPLACE "/" "\\" PLATFORMS ${PLATFORMS})
-
+
# /NJH /NJS /NDL /NFL /NC /NS /NP - Silence any output
- # cmake adds an extra check for command success which doesn't work too well with robocopy
+ # cmake adds an extra check for command success which doesn't work too well with robocopy
# so trick it into thinking the command was successful with the || cmd /c "exit /b 0"
add_custom_command(TARGET citra-qt POST_BUILD
COMMAND robocopy ${Qt5_DLL_DIR} ${DLL_DEST} ${Qt5_DLLS} /NJH /NJS /NDL /NFL /NC /NS /NP || cmd /c "exit /b 0"
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 72b55e94..3db09c65 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -57,7 +57,7 @@ void EmuThread::run() {
Core::SingleStep();
emit DebugModeEntered();
yieldCurrentThread();
-
+
was_active = false;
} else {
std::unique_lock<std::mutex> lock(running_mutex);
diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h
index 16809eaa..47512431 100644
--- a/src/citra_qt/bootmanager.h
+++ b/src/citra_qt/bootmanager.h
@@ -80,7 +80,7 @@ signals:
* @warning When connecting to this signal from other threads, make sure to specify either Qt::QueuedConnection (invoke slot within the destination object's message thread) or even Qt::BlockingQueuedConnection (additionally block source thread until slot returns)
*/
void DebugModeEntered();
-
+
/**
* Emitted right before the CPU continues execution
*
diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp
index 94e20471..6799ce84 100644
--- a/src/citra_qt/debugger/callstack.cpp
+++ b/src/citra_qt/debugger/callstack.cpp
@@ -39,7 +39,7 @@ void CallstackWidget::OnDebugModeEntered()
{
ret_addr = Memory::Read32(addr);
call_addr = ret_addr - 4; //get call address???
-
+
if (Memory::GetPointer(call_addr) == nullptr)
break;
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index f6010459..8041816a 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -127,7 +127,7 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
ui.action_Use_Hardware_Renderer->setChecked(Settings::values.use_hw_renderer);
SetHardwareRendererEnabled(ui.action_Use_Hardware_Renderer->isChecked());
-
+
ui.action_Single_Window_Mode->setChecked(settings.value("singleWindowMode", true).toBool());
ToggleWindowMode();
diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui
index 0942c28c..9a809ee6 100644
--- a/src/citra_qt/main.ui
+++ b/src/citra_qt/main.ui
@@ -24,7 +24,20 @@
<bool>true</bool>
</property>
<widget class="QWidget" name="centralwidget">
- <layout class="QHBoxLayout" name="horizontalLayout"/>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ </layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
@@ -92,7 +105,7 @@
</action>
<action name="action_Start">
<property name="enabled">
- <bool>false</bool>
+ <bool>false</bool>
</property>
<property name="text">
<string>&amp;Start</string>
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp
index f5b6c730..43facb85 100644
--- a/src/common/emu_window.cpp
+++ b/src/common/emu_window.cpp
@@ -32,7 +32,7 @@ std::tuple<unsigned,unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsig
new_x = std::max(new_x, framebuffer_layout.bottom_screen.left);
new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1);
-
+
new_y = std::max(new_y, framebuffer_layout.bottom_screen.top);
new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom-1);
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 7cdd1484..24648ea3 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -16,7 +16,7 @@
#include <io.h>
#include <direct.h> // getcwd
#include <tchar.h>
-
+
// 64 bit offsets for windows
#define fseeko _fseeki64
#define ftello _ftelli64
diff --git a/src/common/swap.h b/src/common/swap.h
index 7e37655b..588cebc7 100644
--- a/src/common/swap.h
+++ b/src/common/swap.h
@@ -135,7 +135,7 @@ template <>
inline void swap<8>(u8* data) {
*reinterpret_cast<u64*>(data) = swap64(data);
}
-
+
} // Namespace Common
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 42b4be93..bbc28516 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -36,6 +36,7 @@ set(SRCS
hle/kernel/shared_memory.cpp
hle/kernel/thread.cpp
hle/kernel/timer.cpp
+ hle/kernel/vm_manager.cpp
hle/service/ac_u.cpp
hle/service/act_u.cpp
hle/service/am_app.cpp
@@ -147,6 +148,7 @@ set(HEADERS
hle/kernel/shared_memory.h
hle/kernel/thread.h
hle/kernel/timer.h
+ hle/kernel/vm_manager.h
hle/result.h
hle/service/ac_u.h
hle/service/act_u.h
diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp
index 913dc145..f6d44d85 100644
--- a/src/core/arm/disassembler/arm_disasm.cpp
+++ b/src/core/arm/disassembler/arm_disasm.cpp
@@ -813,7 +813,7 @@ Opcode ARM_Disasm::Decode11(uint32_t insn) {
// SWI
return OP_SWI;
}
-
+
uint8_t bit4 = (insn >> 4) & 0x1;
uint8_t cpnum = (insn >> 8) & 0xf;
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index b5d1b43c..b00eb49a 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -134,7 +134,7 @@ static unsigned int DPO(Immediate)(ARMul_State* cpu, unsigned int sht_oper) {
unsigned int immed_8 = BITS(sht_oper, 0, 7);
unsigned int rotate_imm = BITS(sht_oper, 8, 11);
unsigned int shifter_operand = ROTATE_RIGHT_32(immed_8, rotate_imm * 2);
- if (rotate_imm == 0)
+ if (rotate_imm == 0)
cpu->shifter_carry_out = cpu->CFlag;
else
cpu->shifter_carry_out = BIT(shifter_operand, 31);
@@ -521,7 +521,7 @@ static void MLnS(ImmediateOffset)(ARMul_State* cpu, unsigned int inst, unsigned
addr = CHECK_READ_REG15_WA(cpu, Rn) + offset_8;
else
addr = CHECK_READ_REG15_WA(cpu, Rn) - offset_8;
-
+
virt_addr = addr;
}
@@ -550,7 +550,7 @@ static void MLnS(ImmediatePreIndexed)(ARMul_State* cpu, unsigned int inst, unsig
if (U_BIT)
addr = rn + offset_8;
- else
+ else
addr = rn - offset_8;
virt_addr = addr;
@@ -1306,8 +1306,8 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index)
inst_cream->Rd = BITS(inst, 12, 15);
inst_cream->shifter_operand = BITS(inst, 0, 11);
inst_cream->shtop_func = get_shtop(inst);
-
- if (inst_cream->Rd == 15)
+
+ if (inst_cream->Rd == 15)
inst_base->br = INDIRECT_BRANCH;
return inst_base;
@@ -1350,7 +1350,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index)
inst_cream->shifter_operand = BITS(inst, 0, 11);
inst_cream->shtop_func = get_shtop(inst);
- if (inst_cream->Rd == 15)
+ if (inst_cream->Rd == 15)
inst_base->br = INDIRECT_BRANCH;
return inst_base;
}
@@ -3269,7 +3269,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(yield)(unsigned int inst, int index)
#define VFP_INTERPRETER_STRUCT
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
#undef VFP_INTERPRETER_STRUCT
-
+
#define VFP_INTERPRETER_TRANS
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
#undef VFP_INTERPRETER_TRANS
@@ -3478,9 +3478,9 @@ const transop_fp_t arm_instruction_trans[] = {
INTERPRETER_TRANSLATE(bbl),
// All the thumb instructions should be placed the end of table
- INTERPRETER_TRANSLATE(b_2_thumb),
- INTERPRETER_TRANSLATE(b_cond_thumb),
- INTERPRETER_TRANSLATE(bl_1_thumb),
+ INTERPRETER_TRANSLATE(b_2_thumb),
+ INTERPRETER_TRANSLATE(b_cond_thumb),
+ INTERPRETER_TRANSLATE(bl_1_thumb),
INTERPRETER_TRANSLATE(bl_2_thumb),
INTERPRETER_TRANSLATE(blx_1_thumb)
};
@@ -4338,7 +4338,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
}
}
if (BIT(inst, 13)) {
- if (cpu->Mode == USER32MODE)
+ if (cpu->Mode == USER32MODE)
cpu->Reg[13] = ReadMemory32(cpu, addr);
else
cpu->Reg_usr[0] = ReadMemory32(cpu, addr);
@@ -4346,7 +4346,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
addr += 4;
}
if (BIT(inst, 14)) {
- if (cpu->Mode == USER32MODE)
+ if (cpu->Mode == USER32MODE)
cpu->Reg[14] = ReadMemory32(cpu, addr);
else
cpu->Reg_usr[1] = ReadMemory32(cpu, addr);
@@ -5148,7 +5148,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
REV16_INST:
REVSH_INST:
{
-
+
if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
rev_inst* const inst_cream = (rev_inst*)inst_base->component;
@@ -5721,7 +5721,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
if (do_swap)
rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16));
-
+
const s32 product1 = (s16)(rn_val & 0xFFFF) * (s16)(rm_val & 0xFFFF);
const s32 product2 = (s16)((rn_val >> 16) & 0xFFFF) * (s16)((rm_val >> 16) & 0xFFFF);
s64 result;
@@ -6583,7 +6583,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
{
u32 lo_val = 0;
u32 hi_val = 0;
-
+
// UHADD16
if (op2 == 0x00) {
lo_val = (rn_val & 0xFFFF) + (rm_val & 0xFFFF);
@@ -6772,7 +6772,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
u16 lo_val = 0;
u16 hi_val = 0;
-
+
// UQADD16
if (op2 == 0x00) {
lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, rm_val & 0xFFFF);
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
index cdaf2145..2fc8170b 100644
--- a/src/core/arm/dyncom/arm_dyncom_thumb.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
@@ -184,7 +184,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
case 9: // LDR Rd,[PC,#imm8]
*ainstr = 0xE59F0000 // base
| ((tinstr & 0x0700) << (12 - 8)) // Rd
- |((tinstr & 0x00FF) << (2 - 0)); // off8
+ |((tinstr & 0x00FF) << (2 - 0)); // off8
break;
case 10:
diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp
index 1b078dc7..83f7f3e2 100644
--- a/src/core/arm/interpreter/armsupp.cpp
+++ b/src/core/arm/interpreter/armsupp.cpp
@@ -628,7 +628,7 @@ void WriteCP15Register(ARMul_State* cpu, u32 value, u32 crn, u32 opcode_1, u32 c
cpu->CP15[CP15_DATA_SYNC_BARRIER] = value;
else if (opcode_2 == 5)
cpu->CP15[CP15_DATA_MEMORY_BARRIER] = value;
-
+
}
else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2)
{
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h
index 08ece69b..d2c90110 100644
--- a/src/core/arm/skyeye_common/armdefs.h
+++ b/src/core/arm/skyeye_common/armdefs.h
@@ -1,16 +1,16 @@
/* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h
index ccc0212a..2007d6dc 100644
--- a/src/core/arm/skyeye_common/vfp/vfp_helper.h
+++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h
@@ -18,10 +18,10 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-/*
+/*
* The following code is derivative from Linux Android kernel vfp
* floating point support.
- *
+ *
* Copyright (C) 2004 ARM Limited.
* Written by Deep Blue Solutions Limited.
*
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index f70c84c3..e53c2e60 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -549,7 +549,7 @@ std::string GetScheduledEventsSummary() {
const char* name = event_types[event->type].name;
if (!name)
name = "[unknown]";
- text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)event->time,
+ text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)event->time,
(u32)(event->userdata >> 32), (u32)(event->userdata));
event = event->next;
}
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 01519608..64f5b06d 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -87,7 +87,7 @@ void UnregisterAllEvents();
/// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from disk,
/// when we implement state saves.
/**
- * Schedules an event to run after the specified number of cycles,
+ * Schedules an event to run after the specified number of cycles,
* with an optional parameter to be passed to the callback handler.
* This must be run ONLY from within the cpu thread.
* @param cycles_into_future The number of cycles after which this event will be fired
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp
index 38d498d0..975aafb3 100644
--- a/src/core/file_sys/archive_extsavedata.cpp
+++ b/src/core/file_sys/archive_extsavedata.cpp
@@ -30,8 +30,8 @@ std::string GetExtSaveDataPath(const std::string& mount_point, const Path& path)
std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) {
if (shared)
return Common::StringFromFormat("%sdata/%s/extdata/", mount_point.c_str(), SYSTEM_ID.c_str());
-
- return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(),
+
+ return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(),
SYSTEM_ID.c_str(), SDCARD_ID.c_str());
}
diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h
index c77c04e4..ef0b27bd 100644
--- a/src/core/file_sys/archive_extsavedata.h
+++ b/src/core/file_sys/archive_extsavedata.h
@@ -35,14 +35,14 @@ public:
private:
/**
* This holds the full directory path for this archive, it is only set after a successful call
- * to Open, this is formed as <base extsavedatapath>/<type>/<high>/<low>.
+ * to Open, this is formed as <base extsavedatapath>/<type>/<high>/<low>.
* See GetExtSaveDataPath for the code that extracts this data from an archive path.
*/
std::string mount_point;
};
/**
- * Constructs a path to the concrete ExtData archive in the host filesystem based on the
+ * Constructs a path to the concrete ExtData archive in the host filesystem based on the
* input Path and base mount point.
* @param mount_point The base mount point of the ExtSaveData archives.
* @param path The path that identifies the requested concrete ExtSaveData archive.
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp
index 8dff5196..a9230937 100644
--- a/src/core/file_sys/archive_savedata.cpp
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -21,7 +21,7 @@
namespace FileSys {
static std::string GetSaveDataContainerPath(const std::string& sdmc_directory) {
- return Common::StringFromFormat("%sNintendo 3DS/%s/%s/title/", sdmc_directory.c_str(),
+ return Common::StringFromFormat("%sNintendo 3DS/%s/%s/title/", sdmc_directory.c_str(),
SYSTEM_ID.c_str(), SDCARD_ID.c_str());
}
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
index 201ec0db..1b8249c7 100644
--- a/src/core/hle/kernel/resource_limit.h
+++ b/src/core/hle/kernel/resource_limit.h
@@ -81,13 +81,13 @@ public:
s32 max_timers = 0;
s32 max_shared_mems = 0;
s32 max_address_arbiters = 0;
-
+
/// Max CPU time that the processes in this category can utilize
s32 max_cpu_time = 0;
- // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind that
- // APPLICATION resource limits should not be affected by the objects created by service modules.
- // Currently we have no way of distinguishing if a Create was called by the running application,
+ // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind that
+ // APPLICATION resource limits should not be affected by the objects created by service modules.
+ // Currently we have no way of distinguishing if a Create was called by the running application,
// or by a service module. Approach this once we have separated the service modules into their own processes
/// Current memory that the processes in this category are using
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index dbb4c9b7..96d61ed3 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -42,7 +42,7 @@ void Semaphore::Acquire() {
ResultVal<s32> Semaphore::Release(s32 release_count) {
if (max_count - available_count < release_count)
- return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel,
+ return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel,
ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
s32 previous_count = available_count;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 690d33b5..22c795ad 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -100,7 +100,7 @@ void Thread::Stop() {
}
status = THREADSTATUS_DEAD;
-
+
WakeupAllWaitingThreads();
// Clean up any dangling references in objects that this thread was waiting for
@@ -169,7 +169,7 @@ static void PriorityBoostStarvedThreads() {
}
}
-/**
+/**
* Switches the CPU's active thread context to that of the specified thread
* @param new_thread The thread to switch to
*/
@@ -353,7 +353,7 @@ void Thread::ResumeFromWait() {
GetObjectId());
return;
}
-
+
ready_queue.push_back(current_priority, this);
status = THREADSTATUS_READY;
}
@@ -504,7 +504,7 @@ void Reschedule() {
} else if (next) {
LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId());
}
-
+
SwitchContext(next);
}
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 38992817..2c65419c 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -94,7 +94,7 @@ public:
* @return The thread's ID
*/
u32 GetThreadId() const { return thread_id; }
-
+
/**
* Release an acquired wait object
* @param wait_object WaitObject to release
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index 25d066bf..8aa4110a 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -88,7 +88,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
if (timer->interval_delay != 0) {
// Reschedule the timer with the interval delay
u64 interval_microseconds = timer->interval_delay / 1000;
- CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,
+ CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,
timer_callback_event_type, timer_handle);
}
}
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
new file mode 100644
index 00000000..b2dd2154
--- /dev/null
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -0,0 +1,245 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+
+#include "core/hle/kernel/vm_manager.h"
+#include "core/memory_setup.h"
+
+namespace Kernel {
+
+bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
+ ASSERT(base + size == next.base);
+ if (permissions != next.permissions ||
+ meminfo_state != next.meminfo_state ||
+ type != next.type) {
+ return false;
+ }
+ if (type == VMAType::AllocatedMemoryBlock &&
+ (backing_block != next.backing_block || offset + size != next.offset)) {
+ return false;
+ }
+ if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) {
+ return false;
+ }
+ if (type == VMAType::MMIO && paddr + size != next.paddr) {
+ return false;
+ }
+ return true;
+}
+
+VMManager::VMManager() {
+ Reset();
+}
+
+void VMManager::Reset() {
+ vma_map.clear();
+
+ // Initialize the map with a single free region covering the entire managed space.
+ VirtualMemoryArea initial_vma;
+ initial_vma.size = MAX_ADDRESS;
+ vma_map.emplace(initial_vma.base, initial_vma);
+
+ UpdatePageTableForVMA(initial_vma);
+}
+
+VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
+ return std::prev(vma_map.upper_bound(target));
+}
+
+ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
+ std::shared_ptr<std::vector<u8>> block, u32 offset, u32 size, MemoryState state) {
+ ASSERT(block != nullptr);
+ ASSERT(offset + size <= block->size());
+
+ // This is the appropriately sized VMA that will turn into our allocation.
+ CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
+ VirtualMemoryArea& final_vma = vma_handle->second;
+ ASSERT(final_vma.size == size);
+
+ final_vma.type = VMAType::AllocatedMemoryBlock;
+ final_vma.permissions = VMAPermission::ReadWrite;
+ final_vma.meminfo_state = state;
+ final_vma.backing_block = block;
+ final_vma.offset = offset;
+ UpdatePageTableForVMA(final_vma);
+
+ return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
+}
+
+ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8 * memory, u32 size, MemoryState state) {
+ ASSERT(memory != nullptr);
+
+ // This is the appropriately sized VMA that will turn into our allocation.
+ CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
+ VirtualMemoryArea& final_vma = vma_handle->second;
+ ASSERT(final_vma.size == size);
+
+ final_vma.type = VMAType::BackingMemory;
+ final_vma.permissions = VMAPermission::ReadWrite;
+ final_vma.meminfo_state = state;
+ final_vma.backing_memory = memory;
+ UpdatePageTableForVMA(final_vma);
+
+ return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
+}
+
+ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state) {
+ // This is the appropriately sized VMA that will turn into our allocation.
+ CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
+ VirtualMemoryArea& final_vma = vma_handle->second;
+ ASSERT(final_vma.size == size);
+
+ final_vma.type = VMAType::MMIO;
+ final_vma.permissions = VMAPermission::ReadWrite;
+ final_vma.meminfo_state = state;
+ final_vma.paddr = paddr;
+ UpdatePageTableForVMA(final_vma);
+
+ return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
+}
+
+void VMManager::Unmap(VMAHandle vma_handle) {
+ VMAIter iter = StripIterConstness(vma_handle);
+
+ VirtualMemoryArea& vma = iter->second;
+ vma.type = VMAType::Free;
+ vma.permissions = VMAPermission::None;
+ vma.meminfo_state = MemoryState::Free;
+
+ vma.backing_block = nullptr;
+ vma.offset = 0;
+ vma.backing_memory = nullptr;
+ vma.paddr = 0;
+
+ UpdatePageTableForVMA(vma);
+
+ MergeAdjacent(iter);
+}
+
+void VMManager::Reprotect(VMAHandle vma_handle, VMAPermission new_perms) {
+ VMAIter iter = StripIterConstness(vma_handle);
+
+ VirtualMemoryArea& vma = iter->second;
+ vma.permissions = new_perms;
+ UpdatePageTableForVMA(vma);
+
+ MergeAdjacent(iter);
+}
+
+VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle & iter) {
+ // This uses a neat C++ trick to convert a const_iterator to a regular iterator, given
+ // non-const access to its container.
+ return vma_map.erase(iter, iter); // Erases an empty range of elements
+}
+
+ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) {
+ ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: %8X", size);
+ ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: %08X", base);
+
+ VMAIter vma_handle = StripIterConstness(FindVMA(base));
+ if (vma_handle == vma_map.end()) {
+ // Target address is outside the range managed by the kernel
+ return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
+ ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E01BF5
+ }
+
+ VirtualMemoryArea& vma = vma_handle->second;
+ if (vma.type != VMAType::Free) {
+ // Region is already allocated
+ return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
+ ErrorSummary::InvalidState, ErrorLevel::Usage); // 0xE0A01BF5
+ }
+
+ u32 start_in_vma = base - vma.base;
+ u32 end_in_vma = start_in_vma + size;
+
+ if (end_in_vma > vma.size) {
+ // Requested allocation doesn't fit inside VMA
+ return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
+ ErrorSummary::InvalidState, ErrorLevel::Usage); // 0xE0A01BF5
+ }
+
+ if (end_in_vma != vma.size) {
+ // Split VMA at the end of the allocated region
+ SplitVMA(vma_handle, end_in_vma);
+ }
+ if (start_in_vma != 0) {
+ // Split VMA at the start of the allocated region
+ vma_handle = SplitVMA(vma_handle, start_in_vma);
+ }
+
+ return MakeResult<VMAIter>(vma_handle);
+}
+
+VMManager::VMAIter VMManager::SplitVMA(VMAIter vma_handle, u32 offset_in_vma) {
+ VirtualMemoryArea& old_vma = vma_handle->second;
+ VirtualMemoryArea new_vma = old_vma; // Make a copy of the VMA
+
+ // For now, don't allow no-op VMA splits (trying to split at a boundary) because it's probably
+ // a bug. This restriction might be removed later.
+ ASSERT(offset_in_vma < old_vma.size);
+ ASSERT(offset_in_vma > 0);
+
+ old_vma.size = offset_in_vma;
+ new_vma.base += offset_in_vma;
+ new_vma.size -= offset_in_vma;
+
+ switch (new_vma.type) {
+ case VMAType::Free:
+ break;
+ case VMAType::AllocatedMemoryBlock:
+ new_vma.offset += offset_in_vma;
+ break;
+ case VMAType::BackingMemory:
+ new_vma.backing_memory += offset_in_vma;
+ break;
+ case VMAType::MMIO:
+ new_vma.paddr += offset_in_vma;
+ break;
+ }
+
+ ASSERT(old_vma.CanBeMergedWith(new_vma));
+
+ return vma_map.emplace_hint(std::next(vma_handle), new_vma.base, new_vma);
+}
+
+VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) {
+ VMAIter next_vma = std::next(iter);
+ if (next_vma != vma_map.end() && iter->second.CanBeMergedWith(next_vma->second)) {
+ iter->second.size += next_vma->second.size;
+ vma_map.erase(next_vma);
+ }
+
+ if (iter != vma_map.begin()) {
+ VMAIter prev_vma = std::prev(iter);
+ if (prev_vma->second.CanBeMergedWith(iter->second)) {
+ prev_vma->second.size += iter->second.size;
+ vma_map.erase(iter);
+ iter = prev_vma;
+ }
+ }
+
+ return iter;
+}
+
+void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
+ switch (vma.type) {
+ case VMAType::Free:
+ Memory::UnmapRegion(vma.base, vma.size);
+ break;
+ case VMAType::AllocatedMemoryBlock:
+ Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_block->data() + vma.offset);
+ break;
+ case VMAType::BackingMemory:
+ Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_memory);
+ break;
+ case VMAType::MMIO:
+ // TODO(yuriks): Add support for MMIO handlers.
+ Memory::MapIoRegion(vma.base, vma.size);
+ break;
+ }
+}
+
+}
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
new file mode 100644
index 00000000..22b72460
--- /dev/null
+++ b/src/core/hle/kernel/vm_manager.h
@@ -0,0 +1,200 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "common/common_types.h"
+
+#include "core/hle/result.h"
+
+namespace Kernel {
+
+enum class VMAType : u8 {
+ /// VMA represents an unmapped region of the address space.
+ Free,
+ /// VMA is backed by a ref-counted allocate memory block.
+ AllocatedMemoryBlock,
+ /// VMA is backed by a raw, unmanaged pointer.
+ BackingMemory,
+ /// VMA is mapped to MMIO registers at a fixed PAddr.
+ MMIO,
+ // TODO(yuriks): Implement MemoryAlias to support MAP/UNMAP
+};
+
+/// Permissions for mapped memory blocks
+enum class VMAPermission : u8 {
+ None = 0,
+ Read = 1,
+ Write = 2,
+ Execute = 4,
+
+ ReadWrite = Read | Write,
+ ReadExecute = Read | Execute,
+ WriteExecute = Write | Execute,
+ ReadWriteExecute = Read | Write | Execute,
+};
+
+/// Set of values returned in MemoryInfo.state by svcQueryMemory.
+enum class MemoryState : u8 {
+ Free = 0,
+ Reserved = 1,
+ IO = 2,
+ Static = 3,
+ Code = 4,
+ Private = 5,
+ Shared = 6,
+ Continuous = 7,
+ Aliased = 8,
+ Alias = 9,
+ AliasCode = 10,
+ Locked = 11,
+};
+
+/**
+ * Represents a VMA in an address space. A VMA is a contiguous region of virtual addressing space
+ * with homogeneous attributes across its extents. In this particular implementation each VMA is
+ * also backed by a single host memory allocation.
+ */
+struct VirtualMemoryArea {
+ /// Virtual base address of the region.
+ VAddr base = 0;
+ /// Size of the region.
+ u32 size = 0;
+
+ VMAType type = VMAType::Free;
+ VMAPermission permissions = VMAPermission::None;
+ /// Tag returned by svcQueryMemory. Not otherwise used.
+ MemoryState meminfo_state = MemoryState::Free;
+
+ // Settings for type = AllocatedMemoryBlock
+ /// Memory block backing this VMA.
+ std::shared_ptr<std::vector<u8>> backing_block = nullptr;
+ /// Offset into the backing_memory the mapping starts from.
+ u32 offset = 0;
+
+ // Settings for type = BackingMemory
+ /// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed.
+ u8* backing_memory = nullptr;
+
+ // Settings for type = MMIO
+ /// Physical address of the register area this VMA maps to.
+ PAddr paddr = 0;
+
+ /// Tests if this area can be merged to the right with `next`.
+ bool CanBeMergedWith(const VirtualMemoryArea& next) const;
+};
+
+/**
+ * Manages a process' virtual addressing space. This class maintains a list of allocated and free
+ * regions in the address space, along with their attributes, and allows kernel clients to
+ * manipulate it, adjusting the page table to match.
+ *
+ * This is similar in idea and purpose to the VM manager present in operating system kernels, with
+ * the main difference being that it doesn't have to support swapping or memory mapping of files.
+ * The implementation is also simplified by not having to allocate page frames. See these articles
+ * about the Linux kernel for an explantion of the concept and implementation:
+ * - http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/
+ * - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/
+ */
+class VMManager {
+ // TODO(yuriks): Make page tables switchable to support multiple VMManagers
+public:
+ /**
+ * The maximum amount of address space managed by the kernel. Addresses above this are never used.
+ * @note This is the limit used by the New 3DS kernel. Old 3DS used 0x20000000.
+ */
+ static const u32 MAX_ADDRESS = 0x40000000;
+
+ /**
+ * A map covering the entirety of the managed address space, keyed by the `base` field of each
+ * VMA. It must always be modified by splitting or merging VMAs, so that the invariant
+ * `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be
+ * merged when possible so that no two similar and adjacent regions exist that have not been
+ * merged.
+ */
+ std::map<VAddr, VirtualMemoryArea> vma_map;
+ using VMAHandle = decltype(vma_map)::const_iterator;
+
+ VMManager();
+
+ /// Clears the address space map, re-initializing with a single free area.
+ void Reset();
+
+ /// Finds the VMA in which the given address is included in, or `vma_map.end()`.
+ VMAHandle FindVMA(VAddr target) const;
+
+ // TODO(yuriks): Should these functions actually return the handle?
+
+ /**
+ * Maps part of a ref-counted block of memory at a given address.
+ *
+ * @param target The guest address to start the mapping at.
+ * @param block The block to be mapped.
+ * @param offset Offset into `block` to map from.
+ * @param size Size of the mapping.
+ * @param state MemoryState tag to attach to the VMA.
+ */
+ ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block,
+ u32 offset, u32 size, MemoryState state);
+
+ /**
+ * Maps an unmanaged host memory pointer at a given address.
+ *
+ * @param target The guest address to start the mapping at.
+ * @param memory The memory to be mapped.
+ * @param size Size of the mapping.
+ * @param state MemoryState tag to attach to the VMA.
+ */
+ ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u32 size, MemoryState state);
+
+ /**
+ * Maps a memory-mapped IO region at a given address.
+ *
+ * @param target The guest address to start the mapping at.
+ * @param paddr The physical address where the registers are present.
+ * @param size Size of the mapping.
+ * @param state MemoryState tag to attach to the VMA.
+ */
+ ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state);
+
+ /// Unmaps the given VMA.
+ void Unmap(VMAHandle vma);
+
+ /// Changes the permissions of the given VMA.
+ void Reprotect(VMAHandle vma, VMAPermission new_perms);
+
+private:
+ using VMAIter = decltype(vma_map)::iterator;
+
+ /// Converts a VMAHandle to a mutable VMAIter.
+ VMAIter StripIterConstness(const VMAHandle& iter);
+
+ /**
+ * Carves a VMA of a specific size at the specified address by splitting Free VMAs while doing
+ * the appropriate error checking.
+ */
+ ResultVal<VMAIter> CarveVMA(VAddr base, u32 size);
+
+ /**
+ * Splits a VMA in two, at the specified offset.
+ * @returns the right side of the split, with the original iterator becoming the left side.
+ */
+ VMAIter SplitVMA(VMAIter vma, u32 offset_in_vma);
+
+ /**
+ * Checks for and merges the specified VMA with adjacent ones if possible.
+ * @returns the merged VMA or the original if no merging was possible.
+ */
+ VMAIter MergeAdjacent(VMAIter vma);
+
+ /// Updates the pages corresponding to this VMA so they match the VMA's attributes.
+ void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
+};
+
+}
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 3fd4cfb0..5d14f393 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -151,7 +151,7 @@ void SendParameter(Service::Interface* self) {
u32 handle = cmd_buff[6];
u32 size = cmd_buff[7];
u32 in_param_buffer_ptr = cmd_buff[8];
-
+
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
@@ -283,7 +283,7 @@ void Init() {
AddService(new APT_A_Interface);
AddService(new APT_S_Interface);
AddService(new APT_U_Interface);
-
+
// Load the shared system font (if available).
// The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header
// generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index e7fa3932..a03e1712 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -63,7 +63,7 @@ void Initialize(Service::Interface* self);
* 4 : Handle to shared font memory
*/
void GetSharedFont(Service::Interface* self);
-
+
/**
* APT::NotifyToWait service function
* Inputs:
@@ -88,7 +88,7 @@ void Enable(Service::Interface* self);
* 4 : Home Menu AppId
* 5 : AppID of currently active app
*/
-void GetAppletManInfo(Service::Interface* self);
+void GetAppletManInfo(Service::Interface* self);
/**
* APT::IsRegistered service function. This returns whether the specified AppID is registered with NS yet.
@@ -100,14 +100,14 @@ void GetAppletManInfo(Service::Interface* self);
* Outputs:
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
- * 2 : Output, 0 = not registered, 1 = registered.
+ * 2 : Output, 0 = not registered, 1 = registered.
*/
void IsRegistered(Service::Interface* self);
void InquireNotification(Service::Interface* self);
/**
- * APT::SendParameter service function. This sets the parameter data state.
+ * APT::SendParameter service function. This sets the parameter data state.
* Inputs:
* 1 : Source AppID
* 2 : Destination AppID
diff --git a/src/core/hle/service/boss_p.h b/src/core/hle/service/boss_p.h
index 71f1e746..6fb51d57 100644
--- a/src/core/hle/service/boss_p.h
+++ b/src/core/hle/service/boss_p.h
@@ -14,7 +14,7 @@ namespace BOSS_P {
class Interface : public Service::Interface {
public:
Interface();
-
+
std::string GetPortName() const override {
return "boss:P";
}
diff --git a/src/core/hle/service/boss_u.h b/src/core/hle/service/boss_u.h
index 2668f2df..89e77fe4 100644
--- a/src/core/hle/service/boss_u.h
+++ b/src/core/hle/service/boss_u.h
@@ -14,7 +14,7 @@ namespace BOSS_U {
class Interface : public Service::Interface {
public:
Interface();
-
+
std::string GetPortName() const override {
return "boss:U";
}
diff --git a/src/core/hle/service/cam_u.cpp b/src/core/hle/service/cam_u.cpp
index fcfd8771..ecda0dbd 100644
--- a/src/core/hle/service/cam_u.cpp
+++ b/src/core/hle/service/cam_u.cpp
@@ -19,5 +19,5 @@ namespace CAM_U {
Interface::Interface() {
//Register(FunctionTable);
}
-
+
} // namespace
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index d4268288..62ad90fd 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -315,11 +315,11 @@ void Init() {
AddService(new CFG_I_Interface);
AddService(new CFG_S_Interface);
AddService(new CFG_U_Interface);
-
+
// Open the SystemSaveData archive 0x00010017
FileSys::Path archive_path(cfg_system_savedata_id);
auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path);
-
+
// If the archive didn't exist, create the files inside
if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {
// Format the archive to create the directories
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index 6d4a9c7c..7cab6802 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -254,7 +254,7 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi
CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path));
- // This should never even happen in the first place with 64-bit handles,
+ // This should never even happen in the first place with 64-bit handles,
while (handle_map.count(next_handle) != 0) {
++next_handle;
}
@@ -488,7 +488,7 @@ void ArchiveInit() {
RegisterArchiveType(std::move(sdmc_factory), ArchiveIdCode::SDMC);
else
LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());
-
+
// Create the SaveData archive
auto savedata_factory = Common::make_unique<FileSys::ArchiveFactory_SaveData>(sdmc_directory);
RegisterArchiveType(std::move(savedata_factory), ArchiveIdCode::SaveData);
@@ -503,7 +503,7 @@ void ArchiveInit() {
if (sharedextsavedata_factory->Initialize())
RegisterArchiveType(std::move(sharedextsavedata_factory), ArchiveIdCode::SharedExtSaveData);
else
- LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s",
+ LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s",
sharedextsavedata_factory->GetMountPoint().c_str());
// Create the SaveDataCheck archive, basically a small variation of the RomFS archive
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index b25c8941..32db773b 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -434,7 +434,7 @@ static void IsSdmcWriteable(Service::Interface* self) {
}
/**
- * FS_User::FormatSaveData service function,
+ * FS_User::FormatSaveData service function,
* formats the SaveData specified by the input path.
* Inputs:
* 0 : 0x084C0242
@@ -520,7 +520,7 @@ static void CreateExtSaveData(Service::Interface* self) {
LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X "
"cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X "
"cmd_buff[9]=%08X cmd_buff[10]=%08X cmd_buff[11]=%08X", save_high, save_low,
- cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9],
+ cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9],
cmd_buff[10], cmd_buff[11]);
cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low).raw;
@@ -544,7 +544,7 @@ static void DeleteExtSaveData(Service::Interface* self) {
u32 save_high = cmd_buff[3];
u32 unknown = cmd_buff[4]; // TODO(Subv): Figure out what this is
- LOG_WARNING(Service_FS, "(STUBBED) save_low=%08X save_high=%08X media_type=%08X unknown=%08X",
+ LOG_WARNING(Service_FS, "(STUBBED) save_low=%08X save_high=%08X media_type=%08X unknown=%08X",
save_low, save_high, cmd_buff[1] & 0xFF, unknown);
cmd_buff[1] = DeleteExtSaveData(media_type, save_high, save_low).raw;
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 4af168bf..4b0b4229 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -167,7 +167,7 @@ static void WriteHWRegsWithMask(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 reg_addr = cmd_buff[1];
u32 size = cmd_buff[2];
-
+
u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]);
u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]);
@@ -208,21 +208,21 @@ static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left);
PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right);
if (info.active_fb == 0) {
- WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4,
+ WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4,
&phys_address_left);
- WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4,
+ WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4,
&phys_address_right);
} else {
- WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4,
+ WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4,
&phys_address_left);
- WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4,
+ WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4,
&phys_address_right);
}
- WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4,
+ WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4,
&info.stride);
- WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), 4,
+ WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), 4,
&info.format);
- WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4,
+ WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4,
&info.shown_fb);
}
@@ -374,7 +374,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
{
auto& params = command.set_command_list_last;
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.address)),
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.address)),
Memory::VirtualToPhysicalAddress(params.address) >> 3);
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.size)), params.size);
@@ -470,7 +470,7 @@ static void SetLcdForceBlack(Service::Interface* self) {
LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_top), data.raw); // Top LCD
LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_bottom), data.raw); // Bottom LCD
-
+
cmd_buff[1] = RESULT_SUCCESS.raw;
}
@@ -516,8 +516,8 @@ static void TriggerCmdReqQueue(Service::Interface* self) {
*/
static void ImportDisplayCaptureInfo(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
-
- // TODO(Subv): We're always returning the framebuffer structures for thread_id = 0,
+
+ // TODO(Subv): We're always returning the framebuffer structures for thread_id = 0,
// because we only support a single running application at a time.
// This should always return the framebuffer data that is currently displayed on the screen.
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index feac5381..c7c1bb5a 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -106,7 +106,7 @@ void Update() {
mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks;
mem->touch.index_reset_ticks = (s64)CoreTiming::GetTicks();
}
-
+
// Signal both handles when there's an update to Pad or touch
event_pad_or_touch_1->Signal();
event_pad_or_touch_2->Signal();
diff --git a/src/core/hle/service/hid/hid_spvr.cpp b/src/core/hle/service/hid/hid_spvr.cpp
index 02db12ef..532931ae 100644
--- a/src/core/hle/service/hid/hid_spvr.cpp
+++ b/src/core/hle/service/hid/hid_spvr.cpp
@@ -25,6 +25,6 @@ const Interface::FunctionInfo FunctionTable[] = {
HID_SPVR_Interface::HID_SPVR_Interface() {
Register(FunctionTable);
}
-
+
} // namespace HID
} // namespace Service
diff --git a/src/core/hle/service/hid/hid_user.h b/src/core/hle/service/hid/hid_user.h
index 0eeec2c2..baf7fed7 100644
--- a/src/core/hle/service/hid/hid_user.h
+++ b/src/core/hle/service/hid/hid_user.h
@@ -11,7 +11,7 @@
namespace Service {
namespace HID {
-
+
/**
* HID service interface.
*/
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h
index 493e6a11..b690003c 100644
--- a/src/core/hle/service/ptm/ptm.h
+++ b/src/core/hle/service/ptm/ptm.h
@@ -20,15 +20,15 @@ enum class ChargeLevels : u32 {
CompletelyFull = 5,
};
-/**
+/**
* Represents the gamecoin file structure in the SharedExtData archive
* More information in 3dbrew (http://www.3dbrew.org/wiki/Extdata#Shared_Extdata_0xf000000b_gamecoin.dat)
*/
struct GameCoin {
u32 magic; ///< Magic number: 0x4F00
- u16 total_coins; ///< Total Play Coins
+ u16 total_coins; ///< Total Play Coins
u16 total_coins_on_date; ///< Total Play Coins obtained on the date stored below.
- u32 step_count; ///< Total step count at the time a new Play Coin was obtained.
+ u32 step_count; ///< Total step count at the time a new Play Coin was obtained.
u32 last_step_count; ///< Step count for the day the last Play Coin was obtained
u16 year;
u8 month;
diff --git a/src/core/hle/service/ptm/ptm_play.cpp b/src/core/hle/service/ptm/ptm_play.cpp
index 48e68a3d..7bb99019 100644
--- a/src/core/hle/service/ptm/ptm_play.cpp
+++ b/src/core/hle/service/ptm/ptm_play.cpp
@@ -18,6 +18,6 @@ const Interface::FunctionInfo FunctionTable[] = {
PTM_Play_Interface::PTM_Play_Interface() {
Register(FunctionTable);
}
-
+
} // namespace PTM
} // namespace Service \ No newline at end of file
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 64185c62..dc667500 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -52,7 +52,7 @@ std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_por
std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services;
/**
- * Creates a function string for logging, complete with the name (or header code, depending
+ * Creates a function string for logging, complete with the name (or header code, depending
* on what's passed in) the port name, and all the cmd_buff arguments.
*/
static std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) {
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index 39b8d65f..1e0f5df9 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -139,7 +139,7 @@ static int TranslateError(int error) {
auto found = error_map.find(error);
if (found != error_map.end())
return -found->second;
-
+
return error;
}
@@ -346,7 +346,7 @@ static void Bind(Service::Interface* self) {
sockaddr sock_addr = CTRSockAddr::ToPlatform(*ctr_sock_addr);
int res = ::bind(socket_handle, &sock_addr, std::max<u32>(sizeof(sock_addr), len));
-
+
int result = 0;
if (res != 0)
result = TranslateError(GET_ERRNO);
@@ -360,14 +360,14 @@ static void Fcntl(Service::Interface* self) {
u32 socket_handle = cmd_buffer[1];
u32 ctr_cmd = cmd_buffer[2];
u32 ctr_arg = cmd_buffer[3];
-
+
int result = 0;
u32 posix_ret = 0; // TODO: Check what hardware returns for F_SETFL (unspecified by POSIX)
SCOPE_EXIT({
cmd_buffer[1] = result;
cmd_buffer[2] = posix_ret;
});
-
+
if (ctr_cmd == 3) { // F_GETFL
#if EMU_PLATFORM == PLATFORM_WINDOWS
posix_ret = 0;
@@ -404,11 +404,11 @@ static void Fcntl(Service::Interface* self) {
posix_ret = -1;
return;
}
-
+
flags &= ~O_NONBLOCK;
if (ctr_arg & 4) // O_NONBLOCK
flags |= O_NONBLOCK;
-
+
int ret = ::fcntl(socket_handle, F_SETFL, flags);
if (ret == SOCKET_ERROR_VALUE) {
result = TranslateError(GET_ERRNO);
@@ -439,8 +439,8 @@ static void Listen(Service::Interface* self) {
}
static void Accept(Service::Interface* self) {
- // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
- // preventing graceful shutdown when closing the emulator, this can be fixed by always
+ // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
+ // preventing graceful shutdown when closing the emulator, this can be fixed by always
// performing nonblocking operations and spinlock until the data is available
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
@@ -448,7 +448,7 @@ static void Accept(Service::Interface* self) {
sockaddr addr;
socklen_t addr_len = sizeof(addr);
u32 ret = static_cast<u32>(::accept(socket_handle, &addr, &addr_len));
-
+
if ((s32)ret != SOCKET_ERROR_VALUE)
open_sockets[ret] = { ret, true };
@@ -525,8 +525,8 @@ static void SendTo(Service::Interface* self) {
}
static void RecvFrom(Service::Interface* self) {
- // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
- // preventing graceful shutdown when closing the emulator, this can be fixed by always
+ // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
+ // preventing graceful shutdown when closing the emulator, this can be fixed by always
// performing nonblocking operations and spinlock until the data is available
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
@@ -568,7 +568,7 @@ static void Poll(Service::Interface* self) {
pollfd* platform_pollfd = new pollfd[nfds];
for (unsigned current_fds = 0; current_fds < nfds; ++current_fds)
platform_pollfd[current_fds] = CTRPollFD::ToPlatform(input_fds[current_fds]);
-
+
int ret = ::poll(platform_pollfd, nfds, timeout);
// Now update the output pollfd structure
@@ -630,7 +630,7 @@ static void GetPeerName(Service::Interface* self) {
socklen_t len = cmd_buffer[2];
CTRSockAddr* ctr_dest_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[0x104 >> 2]));
-
+
sockaddr dest_addr;
socklen_t dest_addr_len = sizeof(dest_addr);
int ret = ::getpeername(socket_handle, &dest_addr, &dest_addr_len);
@@ -651,8 +651,8 @@ static void GetPeerName(Service::Interface* self) {
}
static void Connect(Service::Interface* self) {
- // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
- // preventing graceful shutdown when closing the emulator, this can be fixed by always
+ // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
+ // preventing graceful shutdown when closing the emulator, this can be fixed by always
// performing nonblocking operations and spinlock until the data is available
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index ca3ff332..d1555c75 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -228,7 +228,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou
// Actually wait the current thread on each object if we decided to wait...
std::vector<SharedPtr<Kernel::WaitObject>> wait_objects;
wait_objects.reserve(handle_count);
-
+
for (int i = 0; i < handle_count; ++i) {
auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
object->AddWaitingThread(Kernel::GetCurrentThread());
@@ -475,7 +475,7 @@ static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
return ERR_INVALID_HANDLE;
const SharedPtr<Kernel::Process> process = thread->owner_process;
-
+
ASSERT_MSG(process != nullptr, "Invalid parent process for thread=0x%08X", thread_handle);
*process_id = process->process_id;
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 99cfdaaf..789d3dda 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -140,7 +140,7 @@ inline void Write(u32 addr, const T data) {
// Raw copies do not perform color conversion nor tiled->linear / linear->tiled conversions
// TODO(Subv): Verify if raw copies perform scaling
memcpy(dst_pointer, src_pointer, output_size);
-
+
LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), output format: %x, flags 0x%08X, Raw copy",
output_size,
config.GetPhysicalInputAddress(), config.input_width.Value(), config.input_height.Value(),
@@ -159,14 +159,14 @@ inline void Write(u32 addr, const T data) {
for (u32 x = 0; x < output_width; ++x) {
Math::Vec4<u8> src_color = { 0, 0, 0, 0 };
- // Calculate the [x,y] position of the input image
+ // Calculate the [x,y] position of the input image
// based on the current output position and the scale
u32 input_x = x * horizontal_scale;
u32 input_y = y * vertical_scale;
if (config.flip_vertically) {
- // Flip the y value of the output data,
- // we do this after calculating the [x,y] position of the input image
+ // Flip the y value of the output data,
+ // we do this after calculating the [x,y] position of the input image
// to account for the scaling options.
y = output_height - y - 1;
}
@@ -302,7 +302,7 @@ static void VBlankCallback(u64 userdata, int cycles_late) {
// - If frameskip == 0 (disabled), always swap buffers
// - If frameskip == 1, swap buffers every other frame (starting from the first frame)
// - If frameskip > 1, swap buffers every frameskip^n frames (starting from the second frame)
- if ((((Settings::values.frame_skip != 1) ^ last_skip_frame) && last_skip_frame != g_skip_frame) ||
+ if ((((Settings::values.frame_skip != 1) ^ last_skip_frame) && last_skip_frame != g_skip_frame) ||
Settings::values.frame_skip == 0) {
VideoCore::g_renderer->SwapBuffers();
}
diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp
index 09134c95..963c8d98 100644
--- a/src/core/hw/lcd.cpp
+++ b/src/core/hw/lcd.cpp
@@ -66,5 +66,5 @@ void Init() {
void Shutdown() {
LOG_DEBUG(HW_LCD, "shutdown OK");
}
-
+
} // namespace
diff --git a/src/core/hw/lcd.h b/src/core/hw/lcd.h
index fb14c3b2..8631eb20 100644
--- a/src/core/hw/lcd.h
+++ b/src/core/hw/lcd.h
@@ -85,5 +85,5 @@ void Init();
/// Shutdown hardware
void Shutdown();
-
+
} // namespace
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index ad5e929c..14aeebeb 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -234,7 +234,7 @@ ResultStatus AppLoader_THREEDSX::Load() {
Kernel::g_current_process = Kernel::Process::Create(filename, 0);
Kernel::g_current_process->svc_access_mask.set();
Kernel::g_current_process->address_mappings = default_address_mappings;
-
+
// Attach the default resource limit (APPLICATION) to the process
Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp
index 5ecec956..bf814b94 100644
--- a/src/core/mem_map.cpp
+++ b/src/core/mem_map.cpp
@@ -8,6 +8,10 @@
#include "common/logging/log.h"
#include "core/hle/config_mem.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/kernel/vm_manager.h"
+#include "core/hle/result.h"
#include "core/hle/shared_page.h"
#include "core/mem_map.h"
#include "core/memory.h"
@@ -17,31 +21,23 @@
namespace Memory {
-u8* g_exefs_code; ///< ExeFS:/.code is loaded here
-u8* g_heap; ///< Application heap (main memory)
-u8* g_shared_mem; ///< Shared memory
-u8* g_heap_linear; ///< Linear heap
-u8* g_vram; ///< Video memory (VRAM) pointer
-u8* g_dsp_mem; ///< DSP memory
-u8* g_tls_mem; ///< TLS memory
-
namespace {
struct MemoryArea {
- u8** ptr;
u32 base;
u32 size;
+ const char* name;
};
// We don't declare the IO regions in here since its handled by other means.
static MemoryArea memory_areas[] = {
- {&g_exefs_code, PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE},
- {&g_heap, HEAP_VADDR, HEAP_SIZE },
- {&g_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE },
- {&g_heap_linear, LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE },
- {&g_vram, VRAM_VADDR, VRAM_SIZE },
- {&g_dsp_mem, DSP_RAM_VADDR, DSP_RAM_SIZE },
- {&g_tls_mem, TLS_AREA_VADDR, TLS_AREA_SIZE },
+ {PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE, "Process Image"}, // ExeFS:/.code is loaded here
+ {HEAP_VADDR, HEAP_SIZE, "Heap"}, // Application heap (main memory)
+ {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory
+ {LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE, "Linear Heap"}, // Linear heap (main memory)
+ {VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM)
+ {DSP_RAM_VADDR, DSP_RAM_SIZE, "DSP RAM"}, // DSP memory
+ {TLS_AREA_VADDR, TLS_AREA_SIZE, "TLS Area"}, // TLS memory
};
/// Represents a block of memory mapped by ControlMemory/MapMemoryBlock
@@ -135,27 +131,34 @@ VAddr PhysicalToVirtualAddress(const PAddr addr) {
return addr | 0x80000000;
}
+// TODO(yuriks): Move this into Process
+static Kernel::VMManager address_space;
+
void Init() {
+ using namespace Kernel;
+
InitMemoryMap();
for (MemoryArea& area : memory_areas) {
- *area.ptr = new u8[area.size];
- MapMemoryRegion(area.base, area.size, *area.ptr);
+ auto block = std::make_shared<std::vector<u8>>(area.size);
+ address_space.MapMemoryBlock(area.base, std::move(block), 0, area.size, MemoryState::Private).Unwrap();
}
- MapMemoryRegion(CONFIG_MEMORY_VADDR, CONFIG_MEMORY_SIZE, (u8*)&ConfigMem::config_mem);
- MapMemoryRegion(SHARED_PAGE_VADDR, SHARED_PAGE_SIZE, (u8*)&SharedPage::shared_page);
- LOG_DEBUG(HW_Memory, "initialized OK, RAM at %p", g_heap);
+ auto cfg_mem_vma = address_space.MapBackingMemory(CONFIG_MEMORY_VADDR,
+ (u8*)&ConfigMem::config_mem, CONFIG_MEMORY_SIZE, MemoryState::Shared).MoveFrom();
+ address_space.Reprotect(cfg_mem_vma, VMAPermission::Read);
+
+ auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR,
+ (u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom();
+ address_space.Reprotect(shared_page_vma, VMAPermission::Read);
+
+ LOG_DEBUG(HW_Memory, "initialized OK");
}
void Shutdown() {
heap_map.clear();
heap_linear_map.clear();
-
- for (MemoryArea& area : memory_areas) {
- delete[] *area.ptr;
- *area.ptr = nullptr;
- }
+ address_space.Reset();
LOG_DEBUG(HW_Memory, "shutdown OK");
}
diff --git a/src/core/mem_map.h b/src/core/mem_map.h
index 945815cd..ba50914a 100644
--- a/src/core/mem_map.h
+++ b/src/core/mem_map.h
@@ -8,14 +8,6 @@
namespace Memory {
-extern u8* g_exefs_code; ///< ExeFS:/.code is loaded here
-extern u8* g_heap; ///< Application heap (main memory)
-extern u8* g_shared_mem; ///< Shared memory
-extern u8* g_heap_linear; ///< Linear heap (main memory)
-extern u8* g_vram; ///< Video memory (VRAM)
-extern u8* g_dsp_mem; ///< DSP memory
-extern u8* g_tls_mem; ///< TLS memory
-
void Init();
void Shutdown();
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 5d8069ac..28844a91 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -14,12 +14,10 @@
#include "core/hw/hw.h"
#include "core/mem_map.h"
#include "core/memory.h"
+#include "core/memory_setup.h"
namespace Memory {
-const u32 PAGE_MASK = PAGE_SIZE - 1;
-const int PAGE_BITS = 12;
-
enum class PageType {
/// Page is unmapped and should cause an access error.
Unmapped,
@@ -64,7 +62,7 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) {
while (base != end) {
ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base);
- if (current_page_table->attributes[base] != PageType::Unmapped) {
+ if (current_page_table->attributes[base] != PageType::Unmapped && type != PageType::Unmapped) {
LOG_ERROR(HW_Memory, "overlapping memory ranges at %08X", base * PAGE_SIZE);
}
current_page_table->attributes[base] = type;
@@ -92,6 +90,12 @@ void MapIoRegion(VAddr base, u32 size) {
MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special);
}
+void UnmapRegion(VAddr base, u32 size) {
+ ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %08X", size);
+ ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %08X", base);
+ MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped);
+}
+
template <typename T>
T Read(const VAddr vaddr) {
const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
diff --git a/src/core/memory.h b/src/core/memory.h
index 2d225801..0b8ff9ec 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -97,7 +97,7 @@ enum : VAddr {
SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE,
// TODO(yuriks): The size of this area is dynamic, the kernel grows
- // it as more and more threads are created. For now we'll just use a
+ // it as more and more threads are created. For now we'll just use a
// hardcoded value.
/// Area where TLS (Thread-Local Storage) buffers are allocated.
TLS_AREA_VADDR = 0x1FF82000,
diff --git a/src/core/memory_setup.h b/src/core/memory_setup.h
index 46263495..361bfc81 100644
--- a/src/core/memory_setup.h
+++ b/src/core/memory_setup.h
@@ -6,8 +6,13 @@
#include "common/common_types.h"
+#include "core/memory.h"
+
namespace Memory {
+const u32 PAGE_MASK = PAGE_SIZE - 1;
+const int PAGE_BITS = 12;
+
void InitMemoryMap();
/**
@@ -26,4 +31,6 @@ void MapMemoryRegion(VAddr base, u32 size, u8* target);
*/
void MapIoRegion(VAddr base, u32 size);
+void UnmapRegion(VAddr base, u32 size);
+
}
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index 100d8c7c..b46fadd9 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -56,7 +56,17 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
// Trigger IRQ
case PICA_REG_INDEX(trigger_irq):
GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D);
- return;
+ break;
+
+ case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c):
+ case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d):
+ {
+ unsigned index = id - PICA_REG_INDEX(command_buffer.trigger[0]);
+ u32* head_ptr = (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index));
+ g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr;
+ g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32);
+ break;
+ }
// It seems like these trigger vertex rendering
case PICA_REG_INDEX(trigger_draw):
@@ -136,7 +146,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
input.attr[i][0].ToFloat32(), input.attr[i][1].ToFloat32(),
input.attr[i][2].ToFloat32(), input.attr[i][3].ToFloat32());
}
-
+
// Load per-vertex data from the loader arrays
for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
const u8* srcdata = Memory::GetPhysicalPointer(vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]);
@@ -193,7 +203,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
const Pica::VertexShader::OutputVertex& v2) {
VideoCore::g_renderer->hw_rasterizer->AddTriangle(v0, v1, v2);
};
-
+
primitive_assembler.SubmitVertex(output, AddHWTriangle);
} else {
// Send to triangle clipper
@@ -282,7 +292,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
}
break;
}
-
+
// Load default vertex input attributes
case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233):
case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234):
@@ -306,7 +316,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
}
Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index];
-
+
// NOTE: The destination component order indeed is "backwards"
attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8);
attribute.z = float24::FromRawFloat24(((default_attr_write_buffer[0] & 0xFF) << 16) | ((default_attr_write_buffer[1] >> 16) & 0xFFFF));
@@ -363,38 +373,34 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id));
}
-static std::ptrdiff_t ExecuteCommandBlock(const u32* first_command_word) {
- const CommandHeader& header = *(const CommandHeader*)(&first_command_word[1]);
-
- u32* read_pointer = (u32*)first_command_word;
-
- const u32 write_mask = ((header.parameter_mask & 0x1) ? (0xFFu << 0) : 0u) |
- ((header.parameter_mask & 0x2) ? (0xFFu << 8) : 0u) |
- ((header.parameter_mask & 0x4) ? (0xFFu << 16) : 0u) |
- ((header.parameter_mask & 0x8) ? (0xFFu << 24) : 0u);
-
- WritePicaReg(header.cmd_id, *read_pointer, write_mask);
- read_pointer += 2;
-
- for (unsigned int i = 1; i < 1+header.extra_data_length; ++i) {
- u32 cmd = header.cmd_id + ((header.group_commands) ? i : 0);
- WritePicaReg(cmd, *read_pointer, write_mask);
- ++read_pointer;
- }
-
- // align read pointer to 8 bytes
- if ((first_command_word - read_pointer) % 2)
- ++read_pointer;
-
- return read_pointer - first_command_word;
-}
-
void ProcessCommandList(const u32* list, u32 size) {
- u32* read_pointer = (u32*)list;
- u32 list_length = size / sizeof(u32);
-
- while (read_pointer < list + list_length) {
- read_pointer += ExecuteCommandBlock(read_pointer);
+ g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = list;
+ g_state.cmd_list.length = size / sizeof(u32);
+
+ while (g_state.cmd_list.current_ptr < g_state.cmd_list.head_ptr + g_state.cmd_list.length) {
+ // Expand a 4-bit mask to 4-byte mask, e.g. 0b0101 -> 0x00FF00FF
+ static const u32 expand_bits_to_bytes[] = {
+ 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
+ 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
+ 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
+ 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff
+ };
+
+ // Align read pointer to 8 bytes
+ if ((g_state.cmd_list.head_ptr - g_state.cmd_list.current_ptr) % 2 != 0)
+ ++g_state.cmd_list.current_ptr;
+
+ u32 value = *g_state.cmd_list.current_ptr++;
+ const CommandHeader header = { *g_state.cmd_list.current_ptr++ };
+ const u32 write_mask = expand_bits_to_bytes[header.parameter_mask];
+ u32 cmd = header.cmd_id;
+
+ WritePicaReg(cmd, value, write_mask);
+
+ for (unsigned i = 0; i < header.extra_data_length; ++i) {
+ u32 cmd = header.cmd_id + (header.group_commands ? i + 1 : 0);
+ WritePicaReg(cmd, *g_state.cmd_list.current_ptr++, write_mask);
+ }
}
}
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 7987b922..b92cd1a7 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -319,7 +319,7 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture
// TODO(neobrain): Fix code design to unify vertical block offsets!
source += coarse_y * info.stride;
}
-
+
// TODO: Assert that width/height are multiples of block dimensions
switch (info.format) {
diff --git a/src/video_core/math.h b/src/video_core/math.h
index f9a82265..4928c9bf 100644
--- a/src/video_core/math.h
+++ b/src/video_core/math.h
@@ -461,7 +461,7 @@ public:
// e.g. Vec2 uv() { return Vec2(x,y); }
// _DEFINE_SWIZZLER2 defines a single such function
- // DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r)
+ // DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r)
// DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and permutations (xy<->yx)
#define _DEFINE_SWIZZLER2(a, b, name) const Vec2<T> name() const { return Vec2<T>(a, b); }
#define DEFINE_SWIZZLER2_COMP1(a, a2) \
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index b67dce1a..8ad47a92 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -16,7 +16,7 @@
#include "common/common_types.h"
#include "common/logging/log.h"
-#include "math.h"
+#include "math.h"
namespace Pica {
@@ -162,6 +162,25 @@ struct Regs {
ETC1A4 = 13, // compressed
};
+ enum class LogicOp : u32 {
+ Clear = 0,
+ And = 1,
+ AndReverse = 2,
+ Copy = 3,
+ Set = 4,
+ CopyInverted = 5,
+ NoOp = 6,
+ Invert = 7,
+ Nand = 8,
+ Or = 9,
+ Nor = 10,
+ Xor = 11,
+ Equiv = 12,
+ AndInverted = 13,
+ OrReverse = 14,
+ OrInverted = 15,
+ };
+
static unsigned NibblesPerPixel(TextureFormat format) {
switch (format) {
case TextureFormat::RGBA8:
@@ -221,6 +240,7 @@ struct Regs {
enum class Source : u32 {
PrimaryColor = 0x0,
PrimaryFragmentColor = 0x1,
+ SecondaryFragmentColor = 0x2,
Texture0 = 0x3,
Texture1 = 0x4,
@@ -337,7 +357,7 @@ struct Regs {
return (stage_index < 4) && (update_mask_a & (1 << stage_index));
}
} tev_combiner_buffer_input;
-
+
INSERT_PADDING_WORDS(0xf);
TevStageConfig tev_stage4;
INSERT_PADDING_WORDS(0x3);
@@ -413,12 +433,8 @@ struct Regs {
} alpha_blending;
union {
- enum Op {
- Set = 4,
- };
-
- BitField<0, 4, Op> op;
- } logic_op;
+ BitField<0, 4, LogicOp> logic_op;
+ };
union {
BitField< 0, 8, u32> r;
@@ -703,12 +719,38 @@ struct Regs {
struct {
// Index of the current default attribute
u32 index;
-
+
// Writing to these registers sets the "current" default attribute.
u32 set_value[3];
} vs_default_attributes_setup;
-
- INSERT_PADDING_WORDS(0x28);
+
+ INSERT_PADDING_WORDS(0x2);
+
+ struct {
+ // There are two channels that can be used to configure the next command buffer, which
+ // can be then executed by writing to the "trigger" registers. There are two reasons why a
+ // game might use this feature:
+ // 1) With this, an arbitrary number of additional command buffers may be executed in
+ // sequence without requiring any intervention of the CPU after the initial one is
+ // kicked off.
+ // 2) Games can configure these registers to provide a command list subroutine mechanism.
+
+ BitField< 0, 20, u32> size[2]; ///< Size (in bytes / 8) of each channel's command buffer
+ BitField< 0, 28, u32> addr[2]; ///< Physical address / 8 of each channel's command buffer
+ u32 trigger[2]; ///< Triggers execution of the channel's command buffer when written to
+
+ unsigned GetSize(unsigned index) const {
+ ASSERT(index < 2);
+ return 8 * size[index];
+ }
+
+ PAddr GetPhysicalAddress(unsigned index) const {
+ ASSERT(index < 2);
+ return (PAddr)(8 * addr[index]);
+ }
+ } command_buffer;
+
+ INSERT_PADDING_WORDS(0x20);
enum class TriangleTopology : u32 {
List = 0,
@@ -861,6 +903,7 @@ struct Regs {
ADD_FIELD(trigger_draw);
ADD_FIELD(trigger_draw_indexed);
ADD_FIELD(vs_default_attributes_setup);
+ ADD_FIELD(command_buffer);
ADD_FIELD(triangle_topology);
ADD_FIELD(vs_bool_uniforms);
ADD_FIELD(vs_int_uniforms);
@@ -938,6 +981,7 @@ ASSERT_REG_POSITION(num_vertices, 0x228);
ASSERT_REG_POSITION(trigger_draw, 0x22e);
ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f);
ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232);
+ASSERT_REG_POSITION(command_buffer, 0x238);
ASSERT_REG_POSITION(triangle_topology, 0x25e);
ASSERT_REG_POSITION(vs_bool_uniforms, 0x2b0);
ASSERT_REG_POSITION(vs_int_uniforms, 0x2b1);
@@ -1053,21 +1097,12 @@ private:
float value;
};
-union CommandHeader {
- CommandHeader(u32 h) : hex(h) {}
-
- u32 hex;
-
- BitField< 0, 16, u32> cmd_id;
- BitField<16, 4, u32> parameter_mask;
- BitField<20, 11, u32> extra_data_length;
- BitField<31, 1, u32> group_commands;
-};
-
/// Struct used to describe current Pica state
struct State {
+ /// Pica registers
Regs regs;
+ /// Vertex shader memory
struct {
struct {
Math::Vec4<float24> f[96];
@@ -1080,6 +1115,13 @@ struct State {
std::array<u32, 1024> program_code;
std::array<u32, 1024> swizzle_data;
} vs;
+
+ /// Current Pica command list
+ struct {
+ const u32* head_ptr;
+ const u32* current_ptr;
+ u32 length;
+ } cmd_list;
};
/// Initialize Pica state
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 767ff420..113b573f 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -104,7 +104,7 @@ static u32 GetDepth(int x, int y) {
u8* depth_buffer = Memory::GetPhysicalPointer(addr);
y = framebuffer.height - y;
-
+
const u32 coarse_y = y & ~7;
u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format);
u32 stride = framebuffer.width * bytes_per_pixel;
@@ -402,11 +402,16 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
auto GetSource = [&](Source source) -> Math::Vec4<u8> {
switch (source) {
- // TODO: What's the difference between these two?
case Source::PrimaryColor:
+
+ // HACK: Until we implement fragment lighting, use primary_color
case Source::PrimaryFragmentColor:
return primary_color;
+ // HACK: Until we implement fragment lighting, use zero
+ case Source::SecondaryFragmentColor:
+ return {0, 0, 0, 0};
+
case Source::Texture0:
return texture_color[0];
@@ -570,6 +575,13 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
case Operation::Add:
return std::min(255, input[0] + input[1]);
+ case Operation::AddSigned:
+ {
+ // TODO(bunnei): Verify that the color conversion from (float) 0.5f to (byte) 128 is correct
+ auto result = static_cast<int>(input[0]) + static_cast<int>(input[1]) - 128;
+ return static_cast<u8>(MathUtil::Clamp<int>(result, 0, 255));
+ }
+
case Operation::Lerp:
return (input[0] * input[2] + input[1] * (255 - input[2])) / 255;
@@ -808,10 +820,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
}
};
- using BlendEquation = Regs::BlendEquation;
static auto EvaluateBlendEquation = [](const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor,
const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor,
- BlendEquation equation) {
+ Regs::BlendEquation equation) {
Math::Vec4<int> result;
auto src_result = (src * srcfactor).Cast<int>();
@@ -866,8 +877,63 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb);
blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a();
} else {
- LOG_CRITICAL(HW_GPU, "logic op: %x", output_merger.logic_op);
- UNIMPLEMENTED();
+ static auto LogicOp = [](u8 src, u8 dest, Regs::LogicOp op) -> u8 {
+ switch (op) {
+ case Regs::LogicOp::Clear:
+ return 0;
+
+ case Regs::LogicOp::And:
+ return src & dest;
+
+ case Regs::LogicOp::AndReverse:
+ return src & ~dest;
+
+ case Regs::LogicOp::Copy:
+ return src;
+
+ case Regs::LogicOp::Set:
+ return 255;
+
+ case Regs::LogicOp::CopyInverted:
+ return ~src;
+
+ case Regs::LogicOp::NoOp:
+ return dest;
+
+ case Regs::LogicOp::Invert:
+ return ~dest;
+
+ case Regs::LogicOp::Nand:
+ return ~(src & dest);
+
+ case Regs::LogicOp::Or:
+ return src | dest;
+
+ case Regs::LogicOp::Nor:
+ return ~(src | dest);
+
+ case Regs::LogicOp::Xor:
+ return src ^ dest;
+
+ case Regs::LogicOp::Equiv:
+ return ~(src ^ dest);
+
+ case Regs::LogicOp::AndInverted:
+ return ~src & dest;
+
+ case Regs::LogicOp::OrReverse:
+ return src | ~dest;
+
+ case Regs::LogicOp::OrInverted:
+ return ~src | dest;
+ }
+ };
+
+ blend_output = Math::MakeVec(
+ LogicOp(combiner_output.r(), dest.r(), output_merger.logic_op),
+ LogicOp(combiner_output.g(), dest.g(), output_merger.logic_op),
+ LogicOp(combiner_output.b(), dest.b(), output_merger.logic_op),
+ LogicOp(combiner_output.a(), dest.a(), output_merger.logic_op));
}
const Math::Vec4<u8> result = {
diff --git a/src/video_core/renderer_opengl/generated/gl_3_2_core.c b/src/video_core/renderer_opengl/generated/gl_3_2_core.c
index ef29972d..95fd29c0 100644
--- a/src/video_core/renderer_opengl/generated/gl_3_2_core.c
+++ b/src/video_core/renderer_opengl/generated/gl_3_2_core.c
@@ -62,9 +62,9 @@ static int TestPointer(const PROC pTest)
ptrdiff_t iTest;
if(!pTest) return 0;
iTest = (ptrdiff_t)pTest;
-
+
if(iTest == 1 || iTest == 2 || iTest == 3 || iTest == -1) return 0;
-
+
return 1;
}
@@ -79,7 +79,7 @@ static PROC WinGetProcAddress(const char *name)
glMod = GetModuleHandleA("OpenGL32.dll");
return (PROC)GetProcAddress(glMod, (LPCSTR)name);
}
-
+
#define IntGetProcAddress(name) WinGetProcAddress(name)
#else
#if defined(__APPLE__)
@@ -1083,7 +1083,7 @@ static ogl_StrToExtMap *FindExtEntry(const char *extensionName)
if(strcmp(extensionName, currLoc->extensionName) == 0)
return currLoc;
}
-
+
return NULL;
}
@@ -1135,15 +1135,15 @@ int ogl_LoadFunctions()
{
int numFailed = 0;
ClearExtensionVars();
-
+
_ptrc_glGetIntegerv = (void (CODEGEN_FUNCPTR *)(GLenum, GLint *))IntGetProcAddress("glGetIntegerv");
if(!_ptrc_glGetIntegerv) return ogl_LOAD_FAILED;
_ptrc_glGetStringi = (const GLubyte * (CODEGEN_FUNCPTR *)(GLenum, GLuint))IntGetProcAddress("glGetStringi");
if(!_ptrc_glGetStringi) return ogl_LOAD_FAILED;
-
+
ProcExtsFromExtList();
numFailed = Load_Version_3_2();
-
+
if(numFailed == 0)
return ogl_LOAD_SUCCEEDED;
else
@@ -1177,7 +1177,7 @@ int ogl_IsVersionGEQ(int majorVersion, int minorVersion)
{
if(g_major_version == 0)
GetGLVersion();
-
+
if(majorVersion > g_major_version) return 1;
if(majorVersion < g_major_version) return 0;
if(minorVersion >= g_minor_version) return 1;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 4b7d099a..b51f8efd 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -135,6 +135,7 @@ void RasterizerOpenGL::Reset() {
SyncBlendFuncs();
SyncBlendColor();
SyncAlphaTest();
+ SyncLogicOp();
SyncStencilTest();
SyncDepthTest();
@@ -249,6 +250,11 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
SyncDepthTest();
break;
+ // Logic op
+ case PICA_REG_INDEX(output_merger.logic_op):
+ SyncLogicOp();
+ break;
+
// TEV stage 0
case PICA_REG_INDEX(tev_stage0.color_source1):
SyncTevSources(0, regs.tev_stage0);
@@ -350,7 +356,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
case PICA_REG_INDEX(tev_stage5.color_scale):
SyncTevMultipliers(5, regs.tev_stage5);
break;
-
+
// TEV combiner buffer color
case PICA_REG_INDEX(tev_combiner_buffer_color):
SyncCombinerColor();
@@ -633,6 +639,10 @@ void RasterizerOpenGL::SyncAlphaTest() {
glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f);
}
+void RasterizerOpenGL::SyncLogicOp() {
+ state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op);
+}
+
void RasterizerOpenGL::SyncStencilTest() {
// TODO: Implement stencil test, mask, and op
}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 9896f8d0..d7d422b1 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -125,6 +125,9 @@ private:
/// Syncs the alpha test states to match the PICA register
void SyncAlphaTest();
+ /// Syncs the logic op states to match the PICA register
+ void SyncLogicOp();
+
/// Syncs the stencil test states to match the PICA register
void SyncStencilTest();
diff --git a/src/video_core/renderer_opengl/gl_shaders.h b/src/video_core/renderer_opengl/gl_shaders.h
index 8f094123..a8cb2f59 100644
--- a/src/video_core/renderer_opengl/gl_shaders.h
+++ b/src/video_core/renderer_opengl/gl_shaders.h
@@ -69,15 +69,16 @@ const char g_fragment_shader_hw[] = R"(
#define NUM_VTX_ATTR 7
#define NUM_TEV_STAGES 6
-#define SOURCE_PRIMARYCOLOR 0x0
-#define SOURCE_PRIMARYFRAGMENTCOLOR 0x1
-#define SOURCE_TEXTURE0 0x3
-#define SOURCE_TEXTURE1 0x4
-#define SOURCE_TEXTURE2 0x5
-#define SOURCE_TEXTURE3 0x6
-#define SOURCE_PREVIOUSBUFFER 0xd
-#define SOURCE_CONSTANT 0xe
-#define SOURCE_PREVIOUS 0xf
+#define SOURCE_PRIMARYCOLOR 0x0
+#define SOURCE_PRIMARYFRAGMENTCOLOR 0x1
+#define SOURCE_SECONDARYFRAGMENTCOLOR 0x2
+#define SOURCE_TEXTURE0 0x3
+#define SOURCE_TEXTURE1 0x4
+#define SOURCE_TEXTURE2 0x5
+#define SOURCE_TEXTURE3 0x6
+#define SOURCE_PREVIOUSBUFFER 0xd
+#define SOURCE_CONSTANT 0xe
+#define SOURCE_PREVIOUS 0xf
#define COLORMODIFIER_SOURCECOLOR 0x0
#define COLORMODIFIER_ONEMINUSSOURCECOLOR 0x1
@@ -151,8 +152,11 @@ vec4 GetSource(int source) {
if (source == SOURCE_PRIMARYCOLOR) {
return o[2];
} else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) {
- // HACK: Uses color value, but should really use fragment lighting output
+ // HACK: Until we implement fragment lighting, use primary_color
return o[2];
+ } else if (source == SOURCE_SECONDARYFRAGMENTCOLOR) {
+ // HACK: Until we implement fragment lighting, use zero
+ return vec4(0.0, 0.0, 0.0, 0.0);
} else if (source == SOURCE_TEXTURE0) {
return texture(tex[0], o[3].xy);
} else if (source == SOURCE_TEXTURE1) {
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 1afa58c9..9c5f38f9 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -32,6 +32,8 @@ OpenGLState::OpenGLState() {
blend.color.blue = 0.0f;
blend.color.alpha = 0.0f;
+ logic_op = GL_COPY;
+
for (auto& texture_unit : texture_units) {
texture_unit.enabled_2d = false;
texture_unit.texture_2d = 0;
@@ -82,7 +84,7 @@ void OpenGLState::Apply() {
} else {
glDisable(GL_STENCIL_TEST);
}
- }
+ }
if (stencil.test_func != cur_state.stencil.test_func ||
stencil.test_ref != cur_state.stencil.test_ref ||
@@ -99,8 +101,13 @@ void OpenGLState::Apply() {
if (blend.enabled != cur_state.blend.enabled) {
if (blend.enabled) {
glEnable(GL_BLEND);
+
+ cur_state.logic_op = GL_COPY;
+ glLogicOp(cur_state.logic_op);
+ glDisable(GL_COLOR_LOGIC_OP);
} else {
glDisable(GL_BLEND);
+ glEnable(GL_COLOR_LOGIC_OP);
}
}
@@ -118,6 +125,10 @@ void OpenGLState::Apply() {
glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, blend.dst_a_func);
}
+ if (logic_op != cur_state.logic_op) {
+ glLogicOp(logic_op);
+ }
+
// Textures
for (unsigned texture_index = 0; texture_index < ARRAY_SIZE(texture_units); ++texture_index) {
if (texture_units[texture_index].enabled_2d != cur_state.texture_units[texture_index].enabled_2d) {
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 281b7cad..6b97721d 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -42,6 +42,8 @@ public:
} color; // GL_BLEND_COLOR
} blend;
+ GLenum logic_op; // GL_LOGIC_OP_MODE
+
// 3 texture units - one for each that is used in PICA fragment shader emulation
struct {
bool enabled_2d; // GL_TEXTURE_2D
@@ -61,7 +63,7 @@ public:
static const OpenGLState& GetCurState() {
return cur_state;
}
-
+
/// Apply this state as the current OpenGL state
void Apply();
diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h
index f8763e71..e566f9f7 100644
--- a/src/video_core/renderer_opengl/pica_to_gl.h
+++ b/src/video_core/renderer_opengl/pica_to_gl.h
@@ -71,6 +71,37 @@ inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) {
return blend_func_table[(unsigned)factor];
}
+inline GLenum LogicOp(Pica::Regs::LogicOp op) {
+ static const GLenum logic_op_table[] = {
+ GL_CLEAR, // Clear
+ GL_AND, // And
+ GL_AND_REVERSE, // AndReverse
+ GL_COPY, // Copy
+ GL_SET, // Set
+ GL_COPY_INVERTED, // CopyInverted
+ GL_NOOP, // NoOp
+ GL_INVERT, // Invert
+ GL_NAND, // Nand
+ GL_OR, // Or
+ GL_NOR, // Nor
+ GL_XOR, // Xor
+ GL_EQUIV, // Equiv
+ GL_AND_INVERTED, // AndInverted
+ GL_OR_REVERSE, // OrReverse
+ GL_OR_INVERTED, // OrInverted
+ };
+
+ // Range check table for input
+ if ((unsigned)op >= ARRAY_SIZE(logic_op_table)) {
+ LOG_CRITICAL(Render_OpenGL, "Unknown logic op %d", op);
+ UNREACHABLE();
+
+ return GL_COPY;
+ }
+
+ return logic_op_table[(unsigned)op];
+}
+
inline GLenum CompareFunc(Pica::Regs::CompareFunc func) {
static const GLenum compare_func_table[] = {
GL_NEVER, // CompareFunc::Never
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 16cf92e2..382aeaa0 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -157,7 +157,7 @@ void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig&
state.texture_units[0].enabled_2d = true;
state.texture_units[0].texture_2d = texture.handle;
state.Apply();
-
+
glActiveTexture(GL_TEXTURE0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride);
diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp
index 7d68998f..87006a83 100644
--- a/src/video_core/vertex_shader.cpp
+++ b/src/video_core/vertex_shader.cpp
@@ -119,17 +119,13 @@ static void ProcessShaderCode(VertexShaderState& state) {
switch (instr.opcode.Value().GetInfo().type) {
case OpCode::Type::Arithmetic:
{
- bool is_inverted = 0 != (instr.opcode.Value().GetInfo().subtype & OpCode::Info::SrcInversed);
- // TODO: We don't really support this properly: For instance, the address register
- // offset needs to be applied to SRC2 instead, etc.
- // For now, we just abort in this situation.
- ASSERT_MSG(!is_inverted, "Bad condition...");
+ const bool is_inverted = (0 != (instr.opcode.Value().GetInfo().subtype & OpCode::Info::SrcInversed));
const int address_offset = (instr.common.address_register_index == 0)
? 0 : state.address_registers[instr.common.address_register_index - 1];
- const float24* src1_ = LookupSourceRegister(instr.common.GetSrc1(is_inverted) + address_offset);
- const float24* src2_ = LookupSourceRegister(instr.common.GetSrc2(is_inverted));
+ const float24* src1_ = LookupSourceRegister(instr.common.GetSrc1(is_inverted) + (!is_inverted * address_offset));
+ const float24* src2_ = LookupSourceRegister(instr.common.GetSrc2(is_inverted) + ( is_inverted * address_offset));
const bool negate_src1 = ((bool)swizzle.negate_src1 != false);
const bool negate_src2 = ((bool)swizzle.negate_src2 != false);
@@ -208,6 +204,15 @@ static void ProcessShaderCode(VertexShaderState& state) {
}
break;
+ case OpCode::Id::MIN:
+ for (int i = 0; i < 4; ++i) {
+ if (!swizzle.DestComponentEnabled(i))
+ continue;
+
+ dest[i] = std::min(src1[i], src2[i]);
+ }
+ break;
+
case OpCode::Id::DP3:
case OpCode::Id::DP4:
{
@@ -279,6 +284,16 @@ static void ProcessShaderCode(VertexShaderState& state) {
break;
}
+ case OpCode::Id::SLT:
+ case OpCode::Id::SLTI:
+ for (int i = 0; i < 4; ++i) {
+ if (!swizzle.DestComponentEnabled(i))
+ continue;
+
+ dest[i] = (src1[i] < src2[i]) ? float24::FromFloat32(1.0f) : float24::FromFloat32(0.0f);
+ }
+ break;
+
case OpCode::Id::CMP:
for (int i = 0; i < 2; ++i) {
// TODO: Can you restrict to one compare via dest masking?
@@ -330,7 +345,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
case OpCode::Type::MultiplyAdd:
{
- if ((instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD) ||
+ if ((instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD) ||
(instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MADI)) {
const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.mad.operand_desc_id];
@@ -547,7 +562,7 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes) {
const auto& attribute_register_map = regs.vs_input_register_map;
float24 dummy_register;
boost::fill(state.input_register_table, &dummy_register);
-
+
if (num_attributes > 0) state.input_register_table[attribute_register_map.attribute0_register] = &input.attr[0].x;
if (num_attributes > 1) state.input_register_table[attribute_register_map.attribute1_register] = &input.attr[1].x;
if (num_attributes > 2) state.input_register_table[attribute_register_map.attribute2_register] = &input.attr[2].x;