summaryrefslogtreecommitdiff
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 0d42c8a8a..127896424 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 efccdbec6..c05779380 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -89,15 +89,15 @@ if (Qt5_FOUND AND MSVC)
89 ) 89 )
90 set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/") 90 set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
91 set(PLATFORMS ${DLL_DEST}platforms/) 91 set(PLATFORMS ${DLL_DEST}platforms/)
92 92
93 # windows commandline expects the / to be \ so switch them 93 # windows commandline expects the / to be \ so switch them
94 string(REPLACE "/" "\\" Qt5_DLL_DIR ${Qt5_DLL_DIR}) 94 string(REPLACE "/" "\\" Qt5_DLL_DIR ${Qt5_DLL_DIR})
95 string(REPLACE "/" "\\" Qt5_PLATFORMS_DIR ${Qt5_PLATFORMS_DIR}) 95 string(REPLACE "/" "\\" Qt5_PLATFORMS_DIR ${Qt5_PLATFORMS_DIR})
96 string(REPLACE "/" "\\" DLL_DEST ${DLL_DEST}) 96 string(REPLACE "/" "\\" DLL_DEST ${DLL_DEST})
97 string(REPLACE "/" "\\" PLATFORMS ${PLATFORMS}) 97 string(REPLACE "/" "\\" PLATFORMS ${PLATFORMS})
98 98
99 # /NJH /NJS /NDL /NFL /NC /NS /NP - Silence any output 99 # /NJH /NJS /NDL /NFL /NC /NS /NP - Silence any output
100 # cmake adds an extra check for command success which doesn't work too well with robocopy 100 # cmake adds an extra check for command success which doesn't work too well with robocopy
101 # so trick it into thinking the command was successful with the || cmd /c "exit /b 0" 101 # so trick it into thinking the command was successful with the || cmd /c "exit /b 0"
102 add_custom_command(TARGET citra-qt POST_BUILD 102 add_custom_command(TARGET citra-qt POST_BUILD
103 COMMAND robocopy ${Qt5_DLL_DIR} ${DLL_DEST} ${Qt5_DLLS} /NJH /NJS /NDL /NFL /NC /NS /NP || cmd /c "exit /b 0" 103 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 72b55e94d..3db09c65b 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -57,7 +57,7 @@ void EmuThread::run() {
57 Core::SingleStep(); 57 Core::SingleStep();
58 emit DebugModeEntered(); 58 emit DebugModeEntered();
59 yieldCurrentThread(); 59 yieldCurrentThread();
60 60
61 was_active = false; 61 was_active = false;
62 } else { 62 } else {
63 std::unique_lock<std::mutex> lock(running_mutex); 63 std::unique_lock<std::mutex> lock(running_mutex);
diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h
index 16809eaae..475124319 100644
--- a/src/citra_qt/bootmanager.h
+++ b/src/citra_qt/bootmanager.h
@@ -80,7 +80,7 @@ signals:
80 * @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) 80 * @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)
81 */ 81 */
82 void DebugModeEntered(); 82 void DebugModeEntered();
83 83
84 /** 84 /**
85 * Emitted right before the CPU continues execution 85 * Emitted right before the CPU continues execution
86 * 86 *
diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp
index 94e204717..6799ce844 100644
--- a/src/citra_qt/debugger/callstack.cpp
+++ b/src/citra_qt/debugger/callstack.cpp
@@ -39,7 +39,7 @@ void CallstackWidget::OnDebugModeEntered()
39 { 39 {
40 ret_addr = Memory::Read32(addr); 40 ret_addr = Memory::Read32(addr);
41 call_addr = ret_addr - 4; //get call address??? 41 call_addr = ret_addr - 4; //get call address???
42 42
43 if (Memory::GetPointer(call_addr) == nullptr) 43 if (Memory::GetPointer(call_addr) == nullptr)
44 break; 44 break;
45 45
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index f6010459a..8041816a0 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -127,7 +127,7 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
127 127
128 ui.action_Use_Hardware_Renderer->setChecked(Settings::values.use_hw_renderer); 128 ui.action_Use_Hardware_Renderer->setChecked(Settings::values.use_hw_renderer);
129 SetHardwareRendererEnabled(ui.action_Use_Hardware_Renderer->isChecked()); 129 SetHardwareRendererEnabled(ui.action_Use_Hardware_Renderer->isChecked());
130 130
131 ui.action_Single_Window_Mode->setChecked(settings.value("singleWindowMode", true).toBool()); 131 ui.action_Single_Window_Mode->setChecked(settings.value("singleWindowMode", true).toBool());
132 ToggleWindowMode(); 132 ToggleWindowMode();
133 133
diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui
index 0942c28c8..9a809ee6c 100644
--- a/src/citra_qt/main.ui
+++ b/src/citra_qt/main.ui
@@ -24,7 +24,20 @@
24 <bool>true</bool> 24 <bool>true</bool>
25 </property> 25 </property>
26 <widget class="QWidget" name="centralwidget"> 26 <widget class="QWidget" name="centralwidget">
27 <layout class="QHBoxLayout" name="horizontalLayout"/> 27 <layout class="QHBoxLayout" name="horizontalLayout">
28 <property name="leftMargin">
29 <number>0</number>
30 </property>
31 <property name="topMargin">
32 <number>0</number>
33 </property>
34 <property name="rightMargin">
35 <number>0</number>
36 </property>
37 <property name="bottomMargin">
38 <number>0</number>
39 </property>
40 </layout>
28 </widget> 41 </widget>
29 <widget class="QMenuBar" name="menubar"> 42 <widget class="QMenuBar" name="menubar">
30 <property name="geometry"> 43 <property name="geometry">
@@ -92,7 +105,7 @@
92 </action> 105 </action>
93 <action name="action_Start"> 106 <action name="action_Start">
94 <property name="enabled"> 107 <property name="enabled">
95 <bool>false</bool> 108 <bool>false</bool>
96 </property> 109 </property>
97 <property name="text"> 110 <property name="text">
98 <string>&amp;Start</string> 111 <string>&amp;Start</string>
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp
index f5b6c7301..43facb85c 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
32 32
33 new_x = std::max(new_x, framebuffer_layout.bottom_screen.left); 33 new_x = std::max(new_x, framebuffer_layout.bottom_screen.left);
34 new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1); 34 new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1);
35 35
36 new_y = std::max(new_y, framebuffer_layout.bottom_screen.top); 36 new_y = std::max(new_y, framebuffer_layout.bottom_screen.top);
37 new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom-1); 37 new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom-1);
38 38
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 7cdd1484f..24648ea33 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -16,7 +16,7 @@
16 #include <io.h> 16 #include <io.h>
17 #include <direct.h> // getcwd 17 #include <direct.h> // getcwd
18 #include <tchar.h> 18 #include <tchar.h>
19 19
20 // 64 bit offsets for windows 20 // 64 bit offsets for windows
21 #define fseeko _fseeki64 21 #define fseeko _fseeki64
22 #define ftello _ftelli64 22 #define ftello _ftelli64
diff --git a/src/common/swap.h b/src/common/swap.h
index 7e37655bf..588cebc70 100644
--- a/src/common/swap.h
+++ b/src/common/swap.h
@@ -135,7 +135,7 @@ template <>
135inline void swap<8>(u8* data) { 135inline void swap<8>(u8* data) {
136 *reinterpret_cast<u64*>(data) = swap64(data); 136 *reinterpret_cast<u64*>(data) = swap64(data);
137} 137}
138 138
139} // Namespace Common 139} // Namespace Common
140 140
141 141
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 42b4be938..bbc285168 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -36,6 +36,7 @@ set(SRCS
36 hle/kernel/shared_memory.cpp 36 hle/kernel/shared_memory.cpp
37 hle/kernel/thread.cpp 37 hle/kernel/thread.cpp
38 hle/kernel/timer.cpp 38 hle/kernel/timer.cpp
39 hle/kernel/vm_manager.cpp
39 hle/service/ac_u.cpp 40 hle/service/ac_u.cpp
40 hle/service/act_u.cpp 41 hle/service/act_u.cpp
41 hle/service/am_app.cpp 42 hle/service/am_app.cpp
@@ -147,6 +148,7 @@ set(HEADERS
147 hle/kernel/shared_memory.h 148 hle/kernel/shared_memory.h
148 hle/kernel/thread.h 149 hle/kernel/thread.h
149 hle/kernel/timer.h 150 hle/kernel/timer.h
151 hle/kernel/vm_manager.h
150 hle/result.h 152 hle/result.h
151 hle/service/ac_u.h 153 hle/service/ac_u.h
152 hle/service/act_u.h 154 hle/service/act_u.h
diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp
index 913dc1454..f6d44d85a 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) {
813 // SWI 813 // SWI
814 return OP_SWI; 814 return OP_SWI;
815 } 815 }
816 816
817 uint8_t bit4 = (insn >> 4) & 0x1; 817 uint8_t bit4 = (insn >> 4) & 0x1;
818 uint8_t cpnum = (insn >> 8) & 0xf; 818 uint8_t cpnum = (insn >> 8) & 0xf;
819 819
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index b5d1b43cd..b00eb49a9 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) {
134 unsigned int immed_8 = BITS(sht_oper, 0, 7); 134 unsigned int immed_8 = BITS(sht_oper, 0, 7);
135 unsigned int rotate_imm = BITS(sht_oper, 8, 11); 135 unsigned int rotate_imm = BITS(sht_oper, 8, 11);
136 unsigned int shifter_operand = ROTATE_RIGHT_32(immed_8, rotate_imm * 2); 136 unsigned int shifter_operand = ROTATE_RIGHT_32(immed_8, rotate_imm * 2);
137 if (rotate_imm == 0) 137 if (rotate_imm == 0)
138 cpu->shifter_carry_out = cpu->CFlag; 138 cpu->shifter_carry_out = cpu->CFlag;
139 else 139 else
140 cpu->shifter_carry_out = BIT(shifter_operand, 31); 140 cpu->shifter_carry_out = BIT(shifter_operand, 31);
@@ -521,7 +521,7 @@ static void MLnS(ImmediateOffset)(ARMul_State* cpu, unsigned int inst, unsigned
521 addr = CHECK_READ_REG15_WA(cpu, Rn) + offset_8; 521 addr = CHECK_READ_REG15_WA(cpu, Rn) + offset_8;
522 else 522 else
523 addr = CHECK_READ_REG15_WA(cpu, Rn) - offset_8; 523 addr = CHECK_READ_REG15_WA(cpu, Rn) - offset_8;
524 524
525 virt_addr = addr; 525 virt_addr = addr;
526} 526}
527 527
@@ -550,7 +550,7 @@ static void MLnS(ImmediatePreIndexed)(ARMul_State* cpu, unsigned int inst, unsig
550 550
551 if (U_BIT) 551 if (U_BIT)
552 addr = rn + offset_8; 552 addr = rn + offset_8;
553 else 553 else
554 addr = rn - offset_8; 554 addr = rn - offset_8;
555 555
556 virt_addr = addr; 556 virt_addr = addr;
@@ -1306,8 +1306,8 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index)
1306 inst_cream->Rd = BITS(inst, 12, 15); 1306 inst_cream->Rd = BITS(inst, 12, 15);
1307 inst_cream->shifter_operand = BITS(inst, 0, 11); 1307 inst_cream->shifter_operand = BITS(inst, 0, 11);
1308 inst_cream->shtop_func = get_shtop(inst); 1308 inst_cream->shtop_func = get_shtop(inst);
1309 1309
1310 if (inst_cream->Rd == 15) 1310 if (inst_cream->Rd == 15)
1311 inst_base->br = INDIRECT_BRANCH; 1311 inst_base->br = INDIRECT_BRANCH;
1312 1312
1313 return inst_base; 1313 return inst_base;
@@ -1350,7 +1350,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index)
1350 inst_cream->shifter_operand = BITS(inst, 0, 11); 1350 inst_cream->shifter_operand = BITS(inst, 0, 11);
1351 inst_cream->shtop_func = get_shtop(inst); 1351 inst_cream->shtop_func = get_shtop(inst);
1352 1352
1353 if (inst_cream->Rd == 15) 1353 if (inst_cream->Rd == 15)
1354 inst_base->br = INDIRECT_BRANCH; 1354 inst_base->br = INDIRECT_BRANCH;
1355 return inst_base; 1355 return inst_base;
1356} 1356}
@@ -3269,7 +3269,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(yield)(unsigned int inst, int index)
3269#define VFP_INTERPRETER_STRUCT 3269#define VFP_INTERPRETER_STRUCT
3270#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 3270#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
3271#undef VFP_INTERPRETER_STRUCT 3271#undef VFP_INTERPRETER_STRUCT
3272 3272
3273#define VFP_INTERPRETER_TRANS 3273#define VFP_INTERPRETER_TRANS
3274#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 3274#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
3275#undef VFP_INTERPRETER_TRANS 3275#undef VFP_INTERPRETER_TRANS
@@ -3478,9 +3478,9 @@ const transop_fp_t arm_instruction_trans[] = {
3478 INTERPRETER_TRANSLATE(bbl), 3478 INTERPRETER_TRANSLATE(bbl),
3479 3479
3480 // All the thumb instructions should be placed the end of table 3480 // All the thumb instructions should be placed the end of table
3481 INTERPRETER_TRANSLATE(b_2_thumb), 3481 INTERPRETER_TRANSLATE(b_2_thumb),
3482 INTERPRETER_TRANSLATE(b_cond_thumb), 3482 INTERPRETER_TRANSLATE(b_cond_thumb),
3483 INTERPRETER_TRANSLATE(bl_1_thumb), 3483 INTERPRETER_TRANSLATE(bl_1_thumb),
3484 INTERPRETER_TRANSLATE(bl_2_thumb), 3484 INTERPRETER_TRANSLATE(bl_2_thumb),
3485 INTERPRETER_TRANSLATE(blx_1_thumb) 3485 INTERPRETER_TRANSLATE(blx_1_thumb)
3486}; 3486};
@@ -4338,7 +4338,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4338 } 4338 }
4339 } 4339 }
4340 if (BIT(inst, 13)) { 4340 if (BIT(inst, 13)) {
4341 if (cpu->Mode == USER32MODE) 4341 if (cpu->Mode == USER32MODE)
4342 cpu->Reg[13] = ReadMemory32(cpu, addr); 4342 cpu->Reg[13] = ReadMemory32(cpu, addr);
4343 else 4343 else
4344 cpu->Reg_usr[0] = ReadMemory32(cpu, addr); 4344 cpu->Reg_usr[0] = ReadMemory32(cpu, addr);
@@ -4346,7 +4346,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4346 addr += 4; 4346 addr += 4;
4347 } 4347 }
4348 if (BIT(inst, 14)) { 4348 if (BIT(inst, 14)) {
4349 if (cpu->Mode == USER32MODE) 4349 if (cpu->Mode == USER32MODE)
4350 cpu->Reg[14] = ReadMemory32(cpu, addr); 4350 cpu->Reg[14] = ReadMemory32(cpu, addr);
4351 else 4351 else
4352 cpu->Reg_usr[1] = ReadMemory32(cpu, addr); 4352 cpu->Reg_usr[1] = ReadMemory32(cpu, addr);
@@ -5148,7 +5148,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5148 REV16_INST: 5148 REV16_INST:
5149 REVSH_INST: 5149 REVSH_INST:
5150 { 5150 {
5151 5151
5152 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { 5152 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
5153 rev_inst* const inst_cream = (rev_inst*)inst_base->component; 5153 rev_inst* const inst_cream = (rev_inst*)inst_base->component;
5154 5154
@@ -5721,7 +5721,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5721 5721
5722 if (do_swap) 5722 if (do_swap)
5723 rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16)); 5723 rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16));
5724 5724
5725 const s32 product1 = (s16)(rn_val & 0xFFFF) * (s16)(rm_val & 0xFFFF); 5725 const s32 product1 = (s16)(rn_val & 0xFFFF) * (s16)(rm_val & 0xFFFF);
5726 const s32 product2 = (s16)((rn_val >> 16) & 0xFFFF) * (s16)((rm_val >> 16) & 0xFFFF); 5726 const s32 product2 = (s16)((rn_val >> 16) & 0xFFFF) * (s16)((rm_val >> 16) & 0xFFFF);
5727 s64 result; 5727 s64 result;
@@ -6583,7 +6583,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6583 { 6583 {
6584 u32 lo_val = 0; 6584 u32 lo_val = 0;
6585 u32 hi_val = 0; 6585 u32 hi_val = 0;
6586 6586
6587 // UHADD16 6587 // UHADD16
6588 if (op2 == 0x00) { 6588 if (op2 == 0x00) {
6589 lo_val = (rn_val & 0xFFFF) + (rm_val & 0xFFFF); 6589 lo_val = (rn_val & 0xFFFF) + (rm_val & 0xFFFF);
@@ -6772,7 +6772,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6772 6772
6773 u16 lo_val = 0; 6773 u16 lo_val = 0;
6774 u16 hi_val = 0; 6774 u16 hi_val = 0;
6775 6775
6776 // UQADD16 6776 // UQADD16
6777 if (op2 == 0x00) { 6777 if (op2 == 0x00) {
6778 lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, rm_val & 0xFFFF); 6778 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 cdaf21450..2fc8170be 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) {
184 case 9: // LDR Rd,[PC,#imm8] 184 case 9: // LDR Rd,[PC,#imm8]
185 *ainstr = 0xE59F0000 // base 185 *ainstr = 0xE59F0000 // base
186 | ((tinstr & 0x0700) << (12 - 8)) // Rd 186 | ((tinstr & 0x0700) << (12 - 8)) // Rd
187 |((tinstr & 0x00FF) << (2 - 0)); // off8 187 |((tinstr & 0x00FF) << (2 - 0)); // off8
188 break; 188 break;
189 189
190 case 10: 190 case 10:
diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp
index 1b078dc71..83f7f3e2c 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
628 cpu->CP15[CP15_DATA_SYNC_BARRIER] = value; 628 cpu->CP15[CP15_DATA_SYNC_BARRIER] = value;
629 else if (opcode_2 == 5) 629 else if (opcode_2 == 5)
630 cpu->CP15[CP15_DATA_MEMORY_BARRIER] = value; 630 cpu->CP15[CP15_DATA_MEMORY_BARRIER] = value;
631 631
632 } 632 }
633 else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2) 633 else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2)
634 { 634 {
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h
index 08ece69b6..d2c901100 100644
--- a/src/core/arm/skyeye_common/armdefs.h
+++ b/src/core/arm/skyeye_common/armdefs.h
@@ -1,16 +1,16 @@
1/* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator. 1/* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator.
2 Copyright (C) 1994 Advanced RISC Machines Ltd. 2 Copyright (C) 1994 Advanced RISC Machines Ltd.
3 3
4 This program is free software; you can redistribute it and/or modify 4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or 6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version. 7 (at your option) any later version.
8 8
9 This program is distributed in the hope that it will be useful, 9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details. 12 GNU General Public License for more details.
13 13
14 You should have received a copy of the GNU General Public License 14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software 15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 16 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 ccc0212ab..2007d6dc4 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 @@
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/ 19*/
20 20
21/* 21/*
22 * The following code is derivative from Linux Android kernel vfp 22 * The following code is derivative from Linux Android kernel vfp
23 * floating point support. 23 * floating point support.
24 * 24 *
25 * Copyright (C) 2004 ARM Limited. 25 * Copyright (C) 2004 ARM Limited.
26 * Written by Deep Blue Solutions Limited. 26 * Written by Deep Blue Solutions Limited.
27 * 27 *
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index f70c84c3d..e53c2e606 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -549,7 +549,7 @@ std::string GetScheduledEventsSummary() {
549 const char* name = event_types[event->type].name; 549 const char* name = event_types[event->type].name;
550 if (!name) 550 if (!name)
551 name = "[unknown]"; 551 name = "[unknown]";
552 text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)event->time, 552 text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)event->time,
553 (u32)(event->userdata >> 32), (u32)(event->userdata)); 553 (u32)(event->userdata >> 32), (u32)(event->userdata));
554 event = event->next; 554 event = event->next;
555 } 555 }
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 01519608d..64f5b06d9 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -87,7 +87,7 @@ void UnregisterAllEvents();
87/// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from disk, 87/// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from disk,
88/// when we implement state saves. 88/// when we implement state saves.
89/** 89/**
90 * Schedules an event to run after the specified number of cycles, 90 * Schedules an event to run after the specified number of cycles,
91 * with an optional parameter to be passed to the callback handler. 91 * with an optional parameter to be passed to the callback handler.
92 * This must be run ONLY from within the cpu thread. 92 * This must be run ONLY from within the cpu thread.
93 * @param cycles_into_future The number of cycles after which this event will be fired 93 * @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 38d498d0e..975aafb35 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)
30std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) { 30std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) {
31 if (shared) 31 if (shared)
32 return Common::StringFromFormat("%sdata/%s/extdata/", mount_point.c_str(), SYSTEM_ID.c_str()); 32 return Common::StringFromFormat("%sdata/%s/extdata/", mount_point.c_str(), SYSTEM_ID.c_str());
33 33
34 return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(), 34 return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(),
35 SYSTEM_ID.c_str(), SDCARD_ID.c_str()); 35 SYSTEM_ID.c_str(), SDCARD_ID.c_str());
36} 36}
37 37
diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h
index c77c04e44..ef0b27bde 100644
--- a/src/core/file_sys/archive_extsavedata.h
+++ b/src/core/file_sys/archive_extsavedata.h
@@ -35,14 +35,14 @@ public:
35private: 35private:
36 /** 36 /**
37 * This holds the full directory path for this archive, it is only set after a successful call 37 * This holds the full directory path for this archive, it is only set after a successful call
38 * to Open, this is formed as <base extsavedatapath>/<type>/<high>/<low>. 38 * to Open, this is formed as <base extsavedatapath>/<type>/<high>/<low>.
39 * See GetExtSaveDataPath for the code that extracts this data from an archive path. 39 * See GetExtSaveDataPath for the code that extracts this data from an archive path.
40 */ 40 */
41 std::string mount_point; 41 std::string mount_point;
42}; 42};
43 43
44/** 44/**
45 * Constructs a path to the concrete ExtData archive in the host filesystem based on the 45 * Constructs a path to the concrete ExtData archive in the host filesystem based on the
46 * input Path and base mount point. 46 * input Path and base mount point.
47 * @param mount_point The base mount point of the ExtSaveData archives. 47 * @param mount_point The base mount point of the ExtSaveData archives.
48 * @param path The path that identifies the requested concrete ExtSaveData archive. 48 * @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 8dff51966..a92309377 100644
--- a/src/core/file_sys/archive_savedata.cpp
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -21,7 +21,7 @@
21namespace FileSys { 21namespace FileSys {
22 22
23static std::string GetSaveDataContainerPath(const std::string& sdmc_directory) { 23static std::string GetSaveDataContainerPath(const std::string& sdmc_directory) {
24 return Common::StringFromFormat("%sNintendo 3DS/%s/%s/title/", sdmc_directory.c_str(), 24 return Common::StringFromFormat("%sNintendo 3DS/%s/%s/title/", sdmc_directory.c_str(),
25 SYSTEM_ID.c_str(), SDCARD_ID.c_str()); 25 SYSTEM_ID.c_str(), SDCARD_ID.c_str());
26} 26}
27 27
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
index 201ec0db9..1b8249c74 100644
--- a/src/core/hle/kernel/resource_limit.h
+++ b/src/core/hle/kernel/resource_limit.h
@@ -81,13 +81,13 @@ public:
81 s32 max_timers = 0; 81 s32 max_timers = 0;
82 s32 max_shared_mems = 0; 82 s32 max_shared_mems = 0;
83 s32 max_address_arbiters = 0; 83 s32 max_address_arbiters = 0;
84 84
85 /// Max CPU time that the processes in this category can utilize 85 /// Max CPU time that the processes in this category can utilize
86 s32 max_cpu_time = 0; 86 s32 max_cpu_time = 0;
87 87
88 // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind that 88 // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind that
89 // APPLICATION resource limits should not be affected by the objects created by service modules. 89 // APPLICATION resource limits should not be affected by the objects created by service modules.
90 // Currently we have no way of distinguishing if a Create was called by the running application, 90 // Currently we have no way of distinguishing if a Create was called by the running application,
91 // or by a service module. Approach this once we have separated the service modules into their own processes 91 // or by a service module. Approach this once we have separated the service modules into their own processes
92 92
93 /// Current memory that the processes in this category are using 93 /// 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 dbb4c9b7f..96d61ed3a 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -42,7 +42,7 @@ void Semaphore::Acquire() {
42 42
43ResultVal<s32> Semaphore::Release(s32 release_count) { 43ResultVal<s32> Semaphore::Release(s32 release_count) {
44 if (max_count - available_count < release_count) 44 if (max_count - available_count < release_count)
45 return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, 45 return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel,
46 ErrorSummary::InvalidArgument, ErrorLevel::Permanent); 46 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
47 47
48 s32 previous_count = available_count; 48 s32 previous_count = available_count;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 690d33b55..22c795ad4 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -100,7 +100,7 @@ void Thread::Stop() {
100 } 100 }
101 101
102 status = THREADSTATUS_DEAD; 102 status = THREADSTATUS_DEAD;
103 103
104 WakeupAllWaitingThreads(); 104 WakeupAllWaitingThreads();
105 105
106 // Clean up any dangling references in objects that this thread was waiting for 106 // Clean up any dangling references in objects that this thread was waiting for
@@ -169,7 +169,7 @@ static void PriorityBoostStarvedThreads() {
169 } 169 }
170} 170}
171 171
172/** 172/**
173 * Switches the CPU's active thread context to that of the specified thread 173 * Switches the CPU's active thread context to that of the specified thread
174 * @param new_thread The thread to switch to 174 * @param new_thread The thread to switch to
175 */ 175 */
@@ -353,7 +353,7 @@ void Thread::ResumeFromWait() {
353 GetObjectId()); 353 GetObjectId());
354 return; 354 return;
355 } 355 }
356 356
357 ready_queue.push_back(current_priority, this); 357 ready_queue.push_back(current_priority, this);
358 status = THREADSTATUS_READY; 358 status = THREADSTATUS_READY;
359} 359}
@@ -504,7 +504,7 @@ void Reschedule() {
504 } else if (next) { 504 } else if (next) {
505 LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId()); 505 LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId());
506 } 506 }
507 507
508 SwitchContext(next); 508 SwitchContext(next);
509} 509}
510 510
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 389928178..2c65419c3 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -94,7 +94,7 @@ public:
94 * @return The thread's ID 94 * @return The thread's ID
95 */ 95 */
96 u32 GetThreadId() const { return thread_id; } 96 u32 GetThreadId() const { return thread_id; }
97 97
98 /** 98 /**
99 * Release an acquired wait object 99 * Release an acquired wait object
100 * @param wait_object WaitObject to release 100 * @param wait_object WaitObject to release
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index 25d066bf1..8aa4110a6 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) {
88 if (timer->interval_delay != 0) { 88 if (timer->interval_delay != 0) {
89 // Reschedule the timer with the interval delay 89 // Reschedule the timer with the interval delay
90 u64 interval_microseconds = timer->interval_delay / 1000; 90 u64 interval_microseconds = timer->interval_delay / 1000;
91 CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, 91 CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,
92 timer_callback_event_type, timer_handle); 92 timer_callback_event_type, timer_handle);
93 } 93 }
94} 94}
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
new file mode 100644
index 000000000..b2dd21542
--- /dev/null
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -0,0 +1,245 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6
7#include "core/hle/kernel/vm_manager.h"
8#include "core/memory_setup.h"
9
10namespace Kernel {
11
12bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
13 ASSERT(base + size == next.base);
14 if (permissions != next.permissions ||
15 meminfo_state != next.meminfo_state ||
16 type != next.type) {
17 return false;
18 }
19 if (type == VMAType::AllocatedMemoryBlock &&
20 (backing_block != next.backing_block || offset + size != next.offset)) {
21 return false;
22 }
23 if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) {
24 return false;
25 }
26 if (type == VMAType::MMIO && paddr + size != next.paddr) {
27 return false;
28 }
29 return true;
30}
31
32VMManager::VMManager() {
33 Reset();
34}
35
36void VMManager::Reset() {
37 vma_map.clear();
38
39 // Initialize the map with a single free region covering the entire managed space.
40 VirtualMemoryArea initial_vma;
41 initial_vma.size = MAX_ADDRESS;
42 vma_map.emplace(initial_vma.base, initial_vma);
43
44 UpdatePageTableForVMA(initial_vma);
45}
46
47VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
48 return std::prev(vma_map.upper_bound(target));
49}
50
51ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
52 std::shared_ptr<std::vector<u8>> block, u32 offset, u32 size, MemoryState state) {
53 ASSERT(block != nullptr);
54 ASSERT(offset + size <= block->size());
55
56 // This is the appropriately sized VMA that will turn into our allocation.
57 CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
58 VirtualMemoryArea& final_vma = vma_handle->second;
59 ASSERT(final_vma.size == size);
60
61 final_vma.type = VMAType::AllocatedMemoryBlock;
62 final_vma.permissions = VMAPermission::ReadWrite;
63 final_vma.meminfo_state = state;
64 final_vma.backing_block = block;
65 final_vma.offset = offset;
66 UpdatePageTableForVMA(final_vma);
67
68 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
69}
70
71ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8 * memory, u32 size, MemoryState state) {
72 ASSERT(memory != nullptr);
73
74 // This is the appropriately sized VMA that will turn into our allocation.
75 CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
76 VirtualMemoryArea& final_vma = vma_handle->second;
77 ASSERT(final_vma.size == size);
78
79 final_vma.type = VMAType::BackingMemory;
80 final_vma.permissions = VMAPermission::ReadWrite;
81 final_vma.meminfo_state = state;
82 final_vma.backing_memory = memory;
83 UpdatePageTableForVMA(final_vma);
84
85 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
86}
87
88ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state) {
89 // This is the appropriately sized VMA that will turn into our allocation.
90 CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
91 VirtualMemoryArea& final_vma = vma_handle->second;
92 ASSERT(final_vma.size == size);
93
94 final_vma.type = VMAType::MMIO;
95 final_vma.permissions = VMAPermission::ReadWrite;
96 final_vma.meminfo_state = state;
97 final_vma.paddr = paddr;
98 UpdatePageTableForVMA(final_vma);
99
100 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
101}
102
103void VMManager::Unmap(VMAHandle vma_handle) {
104 VMAIter iter = StripIterConstness(vma_handle);
105
106 VirtualMemoryArea& vma = iter->second;
107 vma.type = VMAType::Free;
108 vma.permissions = VMAPermission::None;
109 vma.meminfo_state = MemoryState::Free;
110
111 vma.backing_block = nullptr;
112 vma.offset = 0;
113 vma.backing_memory = nullptr;
114 vma.paddr = 0;
115
116 UpdatePageTableForVMA(vma);
117
118 MergeAdjacent(iter);
119}
120
121void VMManager::Reprotect(VMAHandle vma_handle, VMAPermission new_perms) {
122 VMAIter iter = StripIterConstness(vma_handle);
123
124 VirtualMemoryArea& vma = iter->second;
125 vma.permissions = new_perms;
126 UpdatePageTableForVMA(vma);
127
128 MergeAdjacent(iter);
129}
130
131VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle & iter) {
132 // This uses a neat C++ trick to convert a const_iterator to a regular iterator, given
133 // non-const access to its container.
134 return vma_map.erase(iter, iter); // Erases an empty range of elements
135}
136
137ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) {
138 ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: %8X", size);
139 ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: %08X", base);
140
141 VMAIter vma_handle = StripIterConstness(FindVMA(base));
142 if (vma_handle == vma_map.end()) {
143 // Target address is outside the range managed by the kernel
144 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
145 ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E01BF5
146 }
147
148 VirtualMemoryArea& vma = vma_handle->second;
149 if (vma.type != VMAType::Free) {
150 // Region is already allocated
151 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
152 ErrorSummary::InvalidState, ErrorLevel::Usage); // 0xE0A01BF5
153 }
154
155 u32 start_in_vma = base - vma.base;
156 u32 end_in_vma = start_in_vma + size;
157
158 if (end_in_vma > vma.size) {
159 // Requested allocation doesn't fit inside VMA
160 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
161 ErrorSummary::InvalidState, ErrorLevel::Usage); // 0xE0A01BF5
162 }
163
164 if (end_in_vma != vma.size) {
165 // Split VMA at the end of the allocated region
166 SplitVMA(vma_handle, end_in_vma);
167 }
168 if (start_in_vma != 0) {
169 // Split VMA at the start of the allocated region
170 vma_handle = SplitVMA(vma_handle, start_in_vma);
171 }
172
173 return MakeResult<VMAIter>(vma_handle);
174}
175
176VMManager::VMAIter VMManager::SplitVMA(VMAIter vma_handle, u32 offset_in_vma) {
177 VirtualMemoryArea& old_vma = vma_handle->second;
178 VirtualMemoryArea new_vma = old_vma; // Make a copy of the VMA
179
180 // For now, don't allow no-op VMA splits (trying to split at a boundary) because it's probably
181 // a bug. This restriction might be removed later.
182 ASSERT(offset_in_vma < old_vma.size);
183 ASSERT(offset_in_vma > 0);
184
185 old_vma.size = offset_in_vma;
186 new_vma.base += offset_in_vma;
187 new_vma.size -= offset_in_vma;
188
189 switch (new_vma.type) {
190 case VMAType::Free:
191 break;
192 case VMAType::AllocatedMemoryBlock:
193 new_vma.offset += offset_in_vma;
194 break;
195 case VMAType::BackingMemory:
196 new_vma.backing_memory += offset_in_vma;
197 break;
198 case VMAType::MMIO:
199 new_vma.paddr += offset_in_vma;
200 break;
201 }
202
203 ASSERT(old_vma.CanBeMergedWith(new_vma));
204
205 return vma_map.emplace_hint(std::next(vma_handle), new_vma.base, new_vma);
206}
207
208VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) {
209 VMAIter next_vma = std::next(iter);
210 if (next_vma != vma_map.end() && iter->second.CanBeMergedWith(next_vma->second)) {
211 iter->second.size += next_vma->second.size;
212 vma_map.erase(next_vma);
213 }
214
215 if (iter != vma_map.begin()) {
216 VMAIter prev_vma = std::prev(iter);
217 if (prev_vma->second.CanBeMergedWith(iter->second)) {
218 prev_vma->second.size += iter->second.size;
219 vma_map.erase(iter);
220 iter = prev_vma;
221 }
222 }
223
224 return iter;
225}
226
227void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
228 switch (vma.type) {
229 case VMAType::Free:
230 Memory::UnmapRegion(vma.base, vma.size);
231 break;
232 case VMAType::AllocatedMemoryBlock:
233 Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_block->data() + vma.offset);
234 break;
235 case VMAType::BackingMemory:
236 Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_memory);
237 break;
238 case VMAType::MMIO:
239 // TODO(yuriks): Add support for MMIO handlers.
240 Memory::MapIoRegion(vma.base, vma.size);
241 break;
242 }
243}
244
245}
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
new file mode 100644
index 000000000..22b724603
--- /dev/null
+++ b/src/core/hle/kernel/vm_manager.h
@@ -0,0 +1,200 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <map>
8#include <memory>
9#include <string>
10#include <vector>
11
12#include "common/common_types.h"
13
14#include "core/hle/result.h"
15
16namespace Kernel {
17
18enum class VMAType : u8 {
19 /// VMA represents an unmapped region of the address space.
20 Free,
21 /// VMA is backed by a ref-counted allocate memory block.
22 AllocatedMemoryBlock,
23 /// VMA is backed by a raw, unmanaged pointer.
24 BackingMemory,
25 /// VMA is mapped to MMIO registers at a fixed PAddr.
26 MMIO,
27 // TODO(yuriks): Implement MemoryAlias to support MAP/UNMAP
28};
29
30/// Permissions for mapped memory blocks
31enum class VMAPermission : u8 {
32 None = 0,
33 Read = 1,
34 Write = 2,
35 Execute = 4,
36
37 ReadWrite = Read | Write,
38 ReadExecute = Read | Execute,
39 WriteExecute = Write | Execute,
40 ReadWriteExecute = Read | Write | Execute,
41};
42
43/// Set of values returned in MemoryInfo.state by svcQueryMemory.
44enum class MemoryState : u8 {
45 Free = 0,
46 Reserved = 1,
47 IO = 2,
48 Static = 3,
49 Code = 4,
50 Private = 5,
51 Shared = 6,
52 Continuous = 7,
53 Aliased = 8,
54 Alias = 9,
55 AliasCode = 10,
56 Locked = 11,
57};
58
59/**
60 * Represents a VMA in an address space. A VMA is a contiguous region of virtual addressing space
61 * with homogeneous attributes across its extents. In this particular implementation each VMA is
62 * also backed by a single host memory allocation.
63 */
64struct VirtualMemoryArea {
65 /// Virtual base address of the region.
66 VAddr base = 0;
67 /// Size of the region.
68 u32 size = 0;
69
70 VMAType type = VMAType::Free;
71 VMAPermission permissions = VMAPermission::None;
72 /// Tag returned by svcQueryMemory. Not otherwise used.
73 MemoryState meminfo_state = MemoryState::Free;
74
75 // Settings for type = AllocatedMemoryBlock
76 /// Memory block backing this VMA.
77 std::shared_ptr<std::vector<u8>> backing_block = nullptr;
78 /// Offset into the backing_memory the mapping starts from.
79 u32 offset = 0;
80
81 // Settings for type = BackingMemory
82 /// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed.
83 u8* backing_memory = nullptr;
84
85 // Settings for type = MMIO
86 /// Physical address of the register area this VMA maps to.
87 PAddr paddr = 0;
88
89 /// Tests if this area can be merged to the right with `next`.
90 bool CanBeMergedWith(const VirtualMemoryArea& next) const;
91};
92
93/**
94 * Manages a process' virtual addressing space. This class maintains a list of allocated and free
95 * regions in the address space, along with their attributes, and allows kernel clients to
96 * manipulate it, adjusting the page table to match.
97 *
98 * This is similar in idea and purpose to the VM manager present in operating system kernels, with
99 * the main difference being that it doesn't have to support swapping or memory mapping of files.
100 * The implementation is also simplified by not having to allocate page frames. See these articles
101 * about the Linux kernel for an explantion of the concept and implementation:
102 * - http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/
103 * - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/
104 */
105class VMManager {
106 // TODO(yuriks): Make page tables switchable to support multiple VMManagers
107public:
108 /**
109 * The maximum amount of address space managed by the kernel. Addresses above this are never used.
110 * @note This is the limit used by the New 3DS kernel. Old 3DS used 0x20000000.
111 */
112 static const u32 MAX_ADDRESS = 0x40000000;
113
114 /**
115 * A map covering the entirety of the managed address space, keyed by the `base` field of each
116 * VMA. It must always be modified by splitting or merging VMAs, so that the invariant
117 * `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be
118 * merged when possible so that no two similar and adjacent regions exist that have not been
119 * merged.
120 */
121 std::map<VAddr, VirtualMemoryArea> vma_map;
122 using VMAHandle = decltype(vma_map)::const_iterator;
123
124 VMManager();
125
126 /// Clears the address space map, re-initializing with a single free area.
127 void Reset();
128
129 /// Finds the VMA in which the given address is included in, or `vma_map.end()`.
130 VMAHandle FindVMA(VAddr target) const;
131
132 // TODO(yuriks): Should these functions actually return the handle?
133
134 /**
135 * Maps part of a ref-counted block of memory at a given address.
136 *
137 * @param target The guest address to start the mapping at.
138 * @param block The block to be mapped.
139 * @param offset Offset into `block` to map from.
140 * @param size Size of the mapping.
141 * @param state MemoryState tag to attach to the VMA.
142 */
143 ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block,
144 u32 offset, u32 size, MemoryState state);
145
146 /**
147 * Maps an unmanaged host memory pointer at a given address.
148 *
149 * @param target The guest address to start the mapping at.
150 * @param memory The memory to be mapped.
151 * @param size Size of the mapping.
152 * @param state MemoryState tag to attach to the VMA.
153 */
154 ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u32 size, MemoryState state);
155
156 /**
157 * Maps a memory-mapped IO region at a given address.
158 *
159 * @param target The guest address to start the mapping at.
160 * @param paddr The physical address where the registers are present.
161 * @param size Size of the mapping.
162 * @param state MemoryState tag to attach to the VMA.
163 */
164 ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state);
165
166 /// Unmaps the given VMA.
167 void Unmap(VMAHandle vma);
168
169 /// Changes the permissions of the given VMA.
170 void Reprotect(VMAHandle vma, VMAPermission new_perms);
171
172private:
173 using VMAIter = decltype(vma_map)::iterator;
174
175 /// Converts a VMAHandle to a mutable VMAIter.
176 VMAIter StripIterConstness(const VMAHandle& iter);
177
178 /**
179 * Carves a VMA of a specific size at the specified address by splitting Free VMAs while doing
180 * the appropriate error checking.
181 */
182 ResultVal<VMAIter> CarveVMA(VAddr base, u32 size);
183
184 /**
185 * Splits a VMA in two, at the specified offset.
186 * @returns the right side of the split, with the original iterator becoming the left side.
187 */
188 VMAIter SplitVMA(VMAIter vma, u32 offset_in_vma);
189
190 /**
191 * Checks for and merges the specified VMA with adjacent ones if possible.
192 * @returns the merged VMA or the original if no merging was possible.
193 */
194 VMAIter MergeAdjacent(VMAIter vma);
195
196 /// Updates the pages corresponding to this VMA so they match the VMA's attributes.
197 void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
198};
199
200}
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 3fd4cfb08..5d14f393d 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) {
151 u32 handle = cmd_buff[6]; 151 u32 handle = cmd_buff[6];
152 u32 size = cmd_buff[7]; 152 u32 size = cmd_buff[7];
153 u32 in_param_buffer_ptr = cmd_buff[8]; 153 u32 in_param_buffer_ptr = cmd_buff[8];
154 154
155 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 155 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
156 156
157 LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," 157 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() {
283 AddService(new APT_A_Interface); 283 AddService(new APT_A_Interface);
284 AddService(new APT_S_Interface); 284 AddService(new APT_S_Interface);
285 AddService(new APT_U_Interface); 285 AddService(new APT_U_Interface);
286 286
287 // Load the shared system font (if available). 287 // Load the shared system font (if available).
288 // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header 288 // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header
289 // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided 289 // 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 e7fa39325..a03e1712a 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);
63 * 4 : Handle to shared font memory 63 * 4 : Handle to shared font memory
64 */ 64 */
65void GetSharedFont(Service::Interface* self); 65void GetSharedFont(Service::Interface* self);
66 66
67/** 67/**
68 * APT::NotifyToWait service function 68 * APT::NotifyToWait service function
69 * Inputs: 69 * Inputs:
@@ -88,7 +88,7 @@ void Enable(Service::Interface* self);
88 * 4 : Home Menu AppId 88 * 4 : Home Menu AppId
89 * 5 : AppID of currently active app 89 * 5 : AppID of currently active app
90 */ 90 */
91void GetAppletManInfo(Service::Interface* self); 91void GetAppletManInfo(Service::Interface* self);
92 92
93/** 93/**
94 * APT::IsRegistered service function. This returns whether the specified AppID is registered with NS yet. 94 * APT::IsRegistered service function. This returns whether the specified AppID is registered with NS yet.
@@ -100,14 +100,14 @@ void GetAppletManInfo(Service::Interface* self);
100 * Outputs: 100 * Outputs:
101 * 0 : Return header 101 * 0 : Return header
102 * 1 : Result of function, 0 on success, otherwise error code 102 * 1 : Result of function, 0 on success, otherwise error code
103 * 2 : Output, 0 = not registered, 1 = registered. 103 * 2 : Output, 0 = not registered, 1 = registered.
104 */ 104 */
105void IsRegistered(Service::Interface* self); 105void IsRegistered(Service::Interface* self);
106 106
107void InquireNotification(Service::Interface* self); 107void InquireNotification(Service::Interface* self);
108 108
109/** 109/**
110 * APT::SendParameter service function. This sets the parameter data state. 110 * APT::SendParameter service function. This sets the parameter data state.
111 * Inputs: 111 * Inputs:
112 * 1 : Source AppID 112 * 1 : Source AppID
113 * 2 : Destination AppID 113 * 2 : Destination AppID
diff --git a/src/core/hle/service/boss_p.h b/src/core/hle/service/boss_p.h
index 71f1e7464..6fb51d57d 100644
--- a/src/core/hle/service/boss_p.h
+++ b/src/core/hle/service/boss_p.h
@@ -14,7 +14,7 @@ namespace BOSS_P {
14class Interface : public Service::Interface { 14class Interface : public Service::Interface {
15public: 15public:
16 Interface(); 16 Interface();
17 17
18 std::string GetPortName() const override { 18 std::string GetPortName() const override {
19 return "boss:P"; 19 return "boss:P";
20 } 20 }
diff --git a/src/core/hle/service/boss_u.h b/src/core/hle/service/boss_u.h
index 2668f2dfd..89e77fe47 100644
--- a/src/core/hle/service/boss_u.h
+++ b/src/core/hle/service/boss_u.h
@@ -14,7 +14,7 @@ namespace BOSS_U {
14class Interface : public Service::Interface { 14class Interface : public Service::Interface {
15public: 15public:
16 Interface(); 16 Interface();
17 17
18 std::string GetPortName() const override { 18 std::string GetPortName() const override {
19 return "boss:U"; 19 return "boss:U";
20 } 20 }
diff --git a/src/core/hle/service/cam_u.cpp b/src/core/hle/service/cam_u.cpp
index fcfd87715..ecda0dbdf 100644
--- a/src/core/hle/service/cam_u.cpp
+++ b/src/core/hle/service/cam_u.cpp
@@ -19,5 +19,5 @@ namespace CAM_U {
19Interface::Interface() { 19Interface::Interface() {
20 //Register(FunctionTable); 20 //Register(FunctionTable);
21} 21}
22 22
23} // namespace 23} // namespace
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index d42682883..62ad90fdc 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -315,11 +315,11 @@ void Init() {
315 AddService(new CFG_I_Interface); 315 AddService(new CFG_I_Interface);
316 AddService(new CFG_S_Interface); 316 AddService(new CFG_S_Interface);
317 AddService(new CFG_U_Interface); 317 AddService(new CFG_U_Interface);
318 318
319 // Open the SystemSaveData archive 0x00010017 319 // Open the SystemSaveData archive 0x00010017
320 FileSys::Path archive_path(cfg_system_savedata_id); 320 FileSys::Path archive_path(cfg_system_savedata_id);
321 auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); 321 auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path);
322 322
323 // If the archive didn't exist, create the files inside 323 // If the archive didn't exist, create the files inside
324 if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { 324 if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {
325 // Format the archive to create the directories 325 // 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 6d4a9c7c9..7cab68024 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
254 254
255 CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path)); 255 CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path));
256 256
257 // This should never even happen in the first place with 64-bit handles, 257 // This should never even happen in the first place with 64-bit handles,
258 while (handle_map.count(next_handle) != 0) { 258 while (handle_map.count(next_handle) != 0) {
259 ++next_handle; 259 ++next_handle;
260 } 260 }
@@ -488,7 +488,7 @@ void ArchiveInit() {
488 RegisterArchiveType(std::move(sdmc_factory), ArchiveIdCode::SDMC); 488 RegisterArchiveType(std::move(sdmc_factory), ArchiveIdCode::SDMC);
489 else 489 else
490 LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); 490 LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());
491 491
492 // Create the SaveData archive 492 // Create the SaveData archive
493 auto savedata_factory = Common::make_unique<FileSys::ArchiveFactory_SaveData>(sdmc_directory); 493 auto savedata_factory = Common::make_unique<FileSys::ArchiveFactory_SaveData>(sdmc_directory);
494 RegisterArchiveType(std::move(savedata_factory), ArchiveIdCode::SaveData); 494 RegisterArchiveType(std::move(savedata_factory), ArchiveIdCode::SaveData);
@@ -503,7 +503,7 @@ void ArchiveInit() {
503 if (sharedextsavedata_factory->Initialize()) 503 if (sharedextsavedata_factory->Initialize())
504 RegisterArchiveType(std::move(sharedextsavedata_factory), ArchiveIdCode::SharedExtSaveData); 504 RegisterArchiveType(std::move(sharedextsavedata_factory), ArchiveIdCode::SharedExtSaveData);
505 else 505 else
506 LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s", 506 LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s",
507 sharedextsavedata_factory->GetMountPoint().c_str()); 507 sharedextsavedata_factory->GetMountPoint().c_str());
508 508
509 // Create the SaveDataCheck archive, basically a small variation of the RomFS archive 509 // 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 b25c8941d..32db773bb 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) {
434} 434}
435 435
436/** 436/**
437 * FS_User::FormatSaveData service function, 437 * FS_User::FormatSaveData service function,
438 * formats the SaveData specified by the input path. 438 * formats the SaveData specified by the input path.
439 * Inputs: 439 * Inputs:
440 * 0 : 0x084C0242 440 * 0 : 0x084C0242
@@ -520,7 +520,7 @@ static void CreateExtSaveData(Service::Interface* self) {
520 LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X " 520 LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X "
521 "cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X " 521 "cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X "
522 "cmd_buff[9]=%08X cmd_buff[10]=%08X cmd_buff[11]=%08X", save_high, save_low, 522 "cmd_buff[9]=%08X cmd_buff[10]=%08X cmd_buff[11]=%08X", save_high, save_low,
523 cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9], 523 cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9],
524 cmd_buff[10], cmd_buff[11]); 524 cmd_buff[10], cmd_buff[11]);
525 525
526 cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low).raw; 526 cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low).raw;
@@ -544,7 +544,7 @@ static void DeleteExtSaveData(Service::Interface* self) {
544 u32 save_high = cmd_buff[3]; 544 u32 save_high = cmd_buff[3];
545 u32 unknown = cmd_buff[4]; // TODO(Subv): Figure out what this is 545 u32 unknown = cmd_buff[4]; // TODO(Subv): Figure out what this is
546 546
547 LOG_WARNING(Service_FS, "(STUBBED) save_low=%08X save_high=%08X media_type=%08X unknown=%08X", 547 LOG_WARNING(Service_FS, "(STUBBED) save_low=%08X save_high=%08X media_type=%08X unknown=%08X",
548 save_low, save_high, cmd_buff[1] & 0xFF, unknown); 548 save_low, save_high, cmd_buff[1] & 0xFF, unknown);
549 549
550 cmd_buff[1] = DeleteExtSaveData(media_type, save_high, save_low).raw; 550 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 4af168bfc..4b0b4229d 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) {
167 u32* cmd_buff = Kernel::GetCommandBuffer(); 167 u32* cmd_buff = Kernel::GetCommandBuffer();
168 u32 reg_addr = cmd_buff[1]; 168 u32 reg_addr = cmd_buff[1];
169 u32 size = cmd_buff[2]; 169 u32 size = cmd_buff[2];
170 170
171 u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]); 171 u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]);
172 u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]); 172 u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]);
173 173
@@ -208,21 +208,21 @@ static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
208 PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left); 208 PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left);
209 PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right); 209 PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right);
210 if (info.active_fb == 0) { 210 if (info.active_fb == 0) {
211 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4, 211 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4,
212 &phys_address_left); 212 &phys_address_left);
213 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4, 213 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4,
214 &phys_address_right); 214 &phys_address_right);
215 } else { 215 } else {
216 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4, 216 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4,
217 &phys_address_left); 217 &phys_address_left);
218 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4, 218 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4,
219 &phys_address_right); 219 &phys_address_right);
220 } 220 }
221 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4, 221 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4,
222 &info.stride); 222 &info.stride);
223 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), 4, 223 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), 4,
224 &info.format); 224 &info.format);
225 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4, 225 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4,
226 &info.shown_fb); 226 &info.shown_fb);
227} 227}
228 228
@@ -374,7 +374,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
374 { 374 {
375 auto& params = command.set_command_list_last; 375 auto& params = command.set_command_list_last;
376 376
377 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.address)), 377 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.address)),
378 Memory::VirtualToPhysicalAddress(params.address) >> 3); 378 Memory::VirtualToPhysicalAddress(params.address) >> 3);
379 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.size)), params.size); 379 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.size)), params.size);
380 380
@@ -470,7 +470,7 @@ static void SetLcdForceBlack(Service::Interface* self) {
470 470
471 LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_top), data.raw); // Top LCD 471 LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_top), data.raw); // Top LCD
472 LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_bottom), data.raw); // Bottom LCD 472 LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_bottom), data.raw); // Bottom LCD
473 473
474 cmd_buff[1] = RESULT_SUCCESS.raw; 474 cmd_buff[1] = RESULT_SUCCESS.raw;
475} 475}
476 476
@@ -516,8 +516,8 @@ static void TriggerCmdReqQueue(Service::Interface* self) {
516 */ 516 */
517static void ImportDisplayCaptureInfo(Service::Interface* self) { 517static void ImportDisplayCaptureInfo(Service::Interface* self) {
518 u32* cmd_buff = Kernel::GetCommandBuffer(); 518 u32* cmd_buff = Kernel::GetCommandBuffer();
519 519
520 // TODO(Subv): We're always returning the framebuffer structures for thread_id = 0, 520 // TODO(Subv): We're always returning the framebuffer structures for thread_id = 0,
521 // because we only support a single running application at a time. 521 // because we only support a single running application at a time.
522 // This should always return the framebuffer data that is currently displayed on the screen. 522 // This should always return the framebuffer data that is currently displayed on the screen.
523 523
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index feac53816..c7c1bb5ab 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -106,7 +106,7 @@ void Update() {
106 mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks; 106 mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks;
107 mem->touch.index_reset_ticks = (s64)CoreTiming::GetTicks(); 107 mem->touch.index_reset_ticks = (s64)CoreTiming::GetTicks();
108 } 108 }
109 109
110 // Signal both handles when there's an update to Pad or touch 110 // Signal both handles when there's an update to Pad or touch
111 event_pad_or_touch_1->Signal(); 111 event_pad_or_touch_1->Signal();
112 event_pad_or_touch_2->Signal(); 112 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 02db12efd..532931ae0 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[] = {
25HID_SPVR_Interface::HID_SPVR_Interface() { 25HID_SPVR_Interface::HID_SPVR_Interface() {
26 Register(FunctionTable); 26 Register(FunctionTable);
27} 27}
28 28
29} // namespace HID 29} // namespace HID
30} // namespace Service 30} // namespace Service
diff --git a/src/core/hle/service/hid/hid_user.h b/src/core/hle/service/hid/hid_user.h
index 0eeec2c25..baf7fed79 100644
--- a/src/core/hle/service/hid/hid_user.h
+++ b/src/core/hle/service/hid/hid_user.h
@@ -11,7 +11,7 @@
11 11
12namespace Service { 12namespace Service {
13namespace HID { 13namespace HID {
14 14
15/** 15/**
16 * HID service interface. 16 * HID service interface.
17 */ 17 */
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h
index 493e6a11f..b690003cb 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 {
20 CompletelyFull = 5, 20 CompletelyFull = 5,
21}; 21};
22 22
23/** 23/**
24 * Represents the gamecoin file structure in the SharedExtData archive 24 * Represents the gamecoin file structure in the SharedExtData archive
25 * More information in 3dbrew (http://www.3dbrew.org/wiki/Extdata#Shared_Extdata_0xf000000b_gamecoin.dat) 25 * More information in 3dbrew (http://www.3dbrew.org/wiki/Extdata#Shared_Extdata_0xf000000b_gamecoin.dat)
26 */ 26 */
27struct GameCoin { 27struct GameCoin {
28 u32 magic; ///< Magic number: 0x4F00 28 u32 magic; ///< Magic number: 0x4F00
29 u16 total_coins; ///< Total Play Coins 29 u16 total_coins; ///< Total Play Coins
30 u16 total_coins_on_date; ///< Total Play Coins obtained on the date stored below. 30 u16 total_coins_on_date; ///< Total Play Coins obtained on the date stored below.
31 u32 step_count; ///< Total step count at the time a new Play Coin was obtained. 31 u32 step_count; ///< Total step count at the time a new Play Coin was obtained.
32 u32 last_step_count; ///< Step count for the day the last Play Coin was obtained 32 u32 last_step_count; ///< Step count for the day the last Play Coin was obtained
33 u16 year; 33 u16 year;
34 u8 month; 34 u8 month;
diff --git a/src/core/hle/service/ptm/ptm_play.cpp b/src/core/hle/service/ptm/ptm_play.cpp
index 48e68a3d8..7bb990193 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[] = {
18PTM_Play_Interface::PTM_Play_Interface() { 18PTM_Play_Interface::PTM_Play_Interface() {
19 Register(FunctionTable); 19 Register(FunctionTable);
20} 20}
21 21
22} // namespace PTM 22} // namespace PTM
23} // namespace Service \ No newline at end of file 23} // 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 64185c62e..dc667500c 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
52std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; 52std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services;
53 53
54/** 54/**
55 * Creates a function string for logging, complete with the name (or header code, depending 55 * Creates a function string for logging, complete with the name (or header code, depending
56 * on what's passed in) the port name, and all the cmd_buff arguments. 56 * on what's passed in) the port name, and all the cmd_buff arguments.
57 */ 57 */
58static std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) { 58static 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 39b8d65fd..1e0f5df9b 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) {
139 auto found = error_map.find(error); 139 auto found = error_map.find(error);
140 if (found != error_map.end()) 140 if (found != error_map.end())
141 return -found->second; 141 return -found->second;
142 142
143 return error; 143 return error;
144} 144}
145 145
@@ -346,7 +346,7 @@ static void Bind(Service::Interface* self) {
346 sockaddr sock_addr = CTRSockAddr::ToPlatform(*ctr_sock_addr); 346 sockaddr sock_addr = CTRSockAddr::ToPlatform(*ctr_sock_addr);
347 347
348 int res = ::bind(socket_handle, &sock_addr, std::max<u32>(sizeof(sock_addr), len)); 348 int res = ::bind(socket_handle, &sock_addr, std::max<u32>(sizeof(sock_addr), len));
349 349
350 int result = 0; 350 int result = 0;
351 if (res != 0) 351 if (res != 0)
352 result = TranslateError(GET_ERRNO); 352 result = TranslateError(GET_ERRNO);
@@ -360,14 +360,14 @@ static void Fcntl(Service::Interface* self) {
360 u32 socket_handle = cmd_buffer[1]; 360 u32 socket_handle = cmd_buffer[1];
361 u32 ctr_cmd = cmd_buffer[2]; 361 u32 ctr_cmd = cmd_buffer[2];
362 u32 ctr_arg = cmd_buffer[3]; 362 u32 ctr_arg = cmd_buffer[3];
363 363
364 int result = 0; 364 int result = 0;
365 u32 posix_ret = 0; // TODO: Check what hardware returns for F_SETFL (unspecified by POSIX) 365 u32 posix_ret = 0; // TODO: Check what hardware returns for F_SETFL (unspecified by POSIX)
366 SCOPE_EXIT({ 366 SCOPE_EXIT({
367 cmd_buffer[1] = result; 367 cmd_buffer[1] = result;
368 cmd_buffer[2] = posix_ret; 368 cmd_buffer[2] = posix_ret;
369 }); 369 });
370 370
371 if (ctr_cmd == 3) { // F_GETFL 371 if (ctr_cmd == 3) { // F_GETFL
372#if EMU_PLATFORM == PLATFORM_WINDOWS 372#if EMU_PLATFORM == PLATFORM_WINDOWS
373 posix_ret = 0; 373 posix_ret = 0;
@@ -404,11 +404,11 @@ static void Fcntl(Service::Interface* self) {
404 posix_ret = -1; 404 posix_ret = -1;
405 return; 405 return;
406 } 406 }
407 407
408 flags &= ~O_NONBLOCK; 408 flags &= ~O_NONBLOCK;
409 if (ctr_arg & 4) // O_NONBLOCK 409 if (ctr_arg & 4) // O_NONBLOCK
410 flags |= O_NONBLOCK; 410 flags |= O_NONBLOCK;
411 411
412 int ret = ::fcntl(socket_handle, F_SETFL, flags); 412 int ret = ::fcntl(socket_handle, F_SETFL, flags);
413 if (ret == SOCKET_ERROR_VALUE) { 413 if (ret == SOCKET_ERROR_VALUE) {
414 result = TranslateError(GET_ERRNO); 414 result = TranslateError(GET_ERRNO);
@@ -439,8 +439,8 @@ static void Listen(Service::Interface* self) {
439} 439}
440 440
441static void Accept(Service::Interface* self) { 441static void Accept(Service::Interface* self) {
442 // TODO(Subv): Calling this function on a blocking socket will block the emu thread, 442 // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
443 // preventing graceful shutdown when closing the emulator, this can be fixed by always 443 // preventing graceful shutdown when closing the emulator, this can be fixed by always
444 // performing nonblocking operations and spinlock until the data is available 444 // performing nonblocking operations and spinlock until the data is available
445 u32* cmd_buffer = Kernel::GetCommandBuffer(); 445 u32* cmd_buffer = Kernel::GetCommandBuffer();
446 u32 socket_handle = cmd_buffer[1]; 446 u32 socket_handle = cmd_buffer[1];
@@ -448,7 +448,7 @@ static void Accept(Service::Interface* self) {
448 sockaddr addr; 448 sockaddr addr;
449 socklen_t addr_len = sizeof(addr); 449 socklen_t addr_len = sizeof(addr);
450 u32 ret = static_cast<u32>(::accept(socket_handle, &addr, &addr_len)); 450 u32 ret = static_cast<u32>(::accept(socket_handle, &addr, &addr_len));
451 451
452 if ((s32)ret != SOCKET_ERROR_VALUE) 452 if ((s32)ret != SOCKET_ERROR_VALUE)
453 open_sockets[ret] = { ret, true }; 453 open_sockets[ret] = { ret, true };
454 454
@@ -525,8 +525,8 @@ static void SendTo(Service::Interface* self) {
525} 525}
526 526
527static void RecvFrom(Service::Interface* self) { 527static void RecvFrom(Service::Interface* self) {
528 // TODO(Subv): Calling this function on a blocking socket will block the emu thread, 528 // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
529 // preventing graceful shutdown when closing the emulator, this can be fixed by always 529 // preventing graceful shutdown when closing the emulator, this can be fixed by always
530 // performing nonblocking operations and spinlock until the data is available 530 // performing nonblocking operations and spinlock until the data is available
531 u32* cmd_buffer = Kernel::GetCommandBuffer(); 531 u32* cmd_buffer = Kernel::GetCommandBuffer();
532 u32 socket_handle = cmd_buffer[1]; 532 u32 socket_handle = cmd_buffer[1];
@@ -568,7 +568,7 @@ static void Poll(Service::Interface* self) {
568 pollfd* platform_pollfd = new pollfd[nfds]; 568 pollfd* platform_pollfd = new pollfd[nfds];
569 for (unsigned current_fds = 0; current_fds < nfds; ++current_fds) 569 for (unsigned current_fds = 0; current_fds < nfds; ++current_fds)
570 platform_pollfd[current_fds] = CTRPollFD::ToPlatform(input_fds[current_fds]); 570 platform_pollfd[current_fds] = CTRPollFD::ToPlatform(input_fds[current_fds]);
571 571
572 int ret = ::poll(platform_pollfd, nfds, timeout); 572 int ret = ::poll(platform_pollfd, nfds, timeout);
573 573
574 // Now update the output pollfd structure 574 // Now update the output pollfd structure
@@ -630,7 +630,7 @@ static void GetPeerName(Service::Interface* self) {
630 socklen_t len = cmd_buffer[2]; 630 socklen_t len = cmd_buffer[2];
631 631
632 CTRSockAddr* ctr_dest_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[0x104 >> 2])); 632 CTRSockAddr* ctr_dest_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[0x104 >> 2]));
633 633
634 sockaddr dest_addr; 634 sockaddr dest_addr;
635 socklen_t dest_addr_len = sizeof(dest_addr); 635 socklen_t dest_addr_len = sizeof(dest_addr);
636 int ret = ::getpeername(socket_handle, &dest_addr, &dest_addr_len); 636 int ret = ::getpeername(socket_handle, &dest_addr, &dest_addr_len);
@@ -651,8 +651,8 @@ static void GetPeerName(Service::Interface* self) {
651} 651}
652 652
653static void Connect(Service::Interface* self) { 653static void Connect(Service::Interface* self) {
654 // TODO(Subv): Calling this function on a blocking socket will block the emu thread, 654 // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
655 // preventing graceful shutdown when closing the emulator, this can be fixed by always 655 // preventing graceful shutdown when closing the emulator, this can be fixed by always
656 // performing nonblocking operations and spinlock until the data is available 656 // performing nonblocking operations and spinlock until the data is available
657 u32* cmd_buffer = Kernel::GetCommandBuffer(); 657 u32* cmd_buffer = Kernel::GetCommandBuffer();
658 u32 socket_handle = cmd_buffer[1]; 658 u32 socket_handle = cmd_buffer[1];
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index ca3ff3328..d1555c753 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
228 // Actually wait the current thread on each object if we decided to wait... 228 // Actually wait the current thread on each object if we decided to wait...
229 std::vector<SharedPtr<Kernel::WaitObject>> wait_objects; 229 std::vector<SharedPtr<Kernel::WaitObject>> wait_objects;
230 wait_objects.reserve(handle_count); 230 wait_objects.reserve(handle_count);
231 231
232 for (int i = 0; i < handle_count; ++i) { 232 for (int i = 0; i < handle_count; ++i) {
233 auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); 233 auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
234 object->AddWaitingThread(Kernel::GetCurrentThread()); 234 object->AddWaitingThread(Kernel::GetCurrentThread());
@@ -475,7 +475,7 @@ static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
475 return ERR_INVALID_HANDLE; 475 return ERR_INVALID_HANDLE;
476 476
477 const SharedPtr<Kernel::Process> process = thread->owner_process; 477 const SharedPtr<Kernel::Process> process = thread->owner_process;
478 478
479 ASSERT_MSG(process != nullptr, "Invalid parent process for thread=0x%08X", thread_handle); 479 ASSERT_MSG(process != nullptr, "Invalid parent process for thread=0x%08X", thread_handle);
480 480
481 *process_id = process->process_id; 481 *process_id = process->process_id;
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 99cfdaafc..789d3dda4 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) {
140 // Raw copies do not perform color conversion nor tiled->linear / linear->tiled conversions 140 // Raw copies do not perform color conversion nor tiled->linear / linear->tiled conversions
141 // TODO(Subv): Verify if raw copies perform scaling 141 // TODO(Subv): Verify if raw copies perform scaling
142 memcpy(dst_pointer, src_pointer, output_size); 142 memcpy(dst_pointer, src_pointer, output_size);
143 143
144 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", 144 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",
145 output_size, 145 output_size,
146 config.GetPhysicalInputAddress(), config.input_width.Value(), config.input_height.Value(), 146 config.GetPhysicalInputAddress(), config.input_width.Value(), config.input_height.Value(),
@@ -159,14 +159,14 @@ inline void Write(u32 addr, const T data) {
159 for (u32 x = 0; x < output_width; ++x) { 159 for (u32 x = 0; x < output_width; ++x) {
160 Math::Vec4<u8> src_color = { 0, 0, 0, 0 }; 160 Math::Vec4<u8> src_color = { 0, 0, 0, 0 };
161 161
162 // Calculate the [x,y] position of the input image 162 // Calculate the [x,y] position of the input image
163 // based on the current output position and the scale 163 // based on the current output position and the scale
164 u32 input_x = x * horizontal_scale; 164 u32 input_x = x * horizontal_scale;
165 u32 input_y = y * vertical_scale; 165 u32 input_y = y * vertical_scale;
166 166
167 if (config.flip_vertically) { 167 if (config.flip_vertically) {
168 // Flip the y value of the output data, 168 // Flip the y value of the output data,
169 // we do this after calculating the [x,y] position of the input image 169 // we do this after calculating the [x,y] position of the input image
170 // to account for the scaling options. 170 // to account for the scaling options.
171 y = output_height - y - 1; 171 y = output_height - y - 1;
172 } 172 }
@@ -302,7 +302,7 @@ static void VBlankCallback(u64 userdata, int cycles_late) {
302 // - If frameskip == 0 (disabled), always swap buffers 302 // - If frameskip == 0 (disabled), always swap buffers
303 // - If frameskip == 1, swap buffers every other frame (starting from the first frame) 303 // - If frameskip == 1, swap buffers every other frame (starting from the first frame)
304 // - If frameskip > 1, swap buffers every frameskip^n frames (starting from the second frame) 304 // - If frameskip > 1, swap buffers every frameskip^n frames (starting from the second frame)
305 if ((((Settings::values.frame_skip != 1) ^ last_skip_frame) && last_skip_frame != g_skip_frame) || 305 if ((((Settings::values.frame_skip != 1) ^ last_skip_frame) && last_skip_frame != g_skip_frame) ||
306 Settings::values.frame_skip == 0) { 306 Settings::values.frame_skip == 0) {
307 VideoCore::g_renderer->SwapBuffers(); 307 VideoCore::g_renderer->SwapBuffers();
308 } 308 }
diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp
index 09134c95b..963c8d981 100644
--- a/src/core/hw/lcd.cpp
+++ b/src/core/hw/lcd.cpp
@@ -66,5 +66,5 @@ void Init() {
66void Shutdown() { 66void Shutdown() {
67 LOG_DEBUG(HW_LCD, "shutdown OK"); 67 LOG_DEBUG(HW_LCD, "shutdown OK");
68} 68}
69 69
70} // namespace 70} // namespace
diff --git a/src/core/hw/lcd.h b/src/core/hw/lcd.h
index fb14c3b21..8631eb201 100644
--- a/src/core/hw/lcd.h
+++ b/src/core/hw/lcd.h
@@ -85,5 +85,5 @@ void Init();
85 85
86/// Shutdown hardware 86/// Shutdown hardware
87void Shutdown(); 87void Shutdown();
88 88
89} // namespace 89} // namespace
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index ad5e929ce..14aeebebb 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -234,7 +234,7 @@ ResultStatus AppLoader_THREEDSX::Load() {
234 Kernel::g_current_process = Kernel::Process::Create(filename, 0); 234 Kernel::g_current_process = Kernel::Process::Create(filename, 0);
235 Kernel::g_current_process->svc_access_mask.set(); 235 Kernel::g_current_process->svc_access_mask.set();
236 Kernel::g_current_process->address_mappings = default_address_mappings; 236 Kernel::g_current_process->address_mappings = default_address_mappings;
237 237
238 // Attach the default resource limit (APPLICATION) to the process 238 // Attach the default resource limit (APPLICATION) to the process
239 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 239 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
240 240
diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp
index 5ecec9566..bf814b945 100644
--- a/src/core/mem_map.cpp
+++ b/src/core/mem_map.cpp
@@ -8,6 +8,10 @@
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9 9
10#include "core/hle/config_mem.h" 10#include "core/hle/config_mem.h"
11#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/shared_memory.h"
13#include "core/hle/kernel/vm_manager.h"
14#include "core/hle/result.h"
11#include "core/hle/shared_page.h" 15#include "core/hle/shared_page.h"
12#include "core/mem_map.h" 16#include "core/mem_map.h"
13#include "core/memory.h" 17#include "core/memory.h"
@@ -17,31 +21,23 @@
17 21
18namespace Memory { 22namespace Memory {
19 23
20u8* g_exefs_code; ///< ExeFS:/.code is loaded here
21u8* g_heap; ///< Application heap (main memory)
22u8* g_shared_mem; ///< Shared memory
23u8* g_heap_linear; ///< Linear heap
24u8* g_vram; ///< Video memory (VRAM) pointer
25u8* g_dsp_mem; ///< DSP memory
26u8* g_tls_mem; ///< TLS memory
27
28namespace { 24namespace {
29 25
30struct MemoryArea { 26struct MemoryArea {
31 u8** ptr;
32 u32 base; 27 u32 base;
33 u32 size; 28 u32 size;
29 const char* name;
34}; 30};
35 31
36// We don't declare the IO regions in here since its handled by other means. 32// We don't declare the IO regions in here since its handled by other means.
37static MemoryArea memory_areas[] = { 33static MemoryArea memory_areas[] = {
38 {&g_exefs_code, PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE}, 34 {PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE, "Process Image"}, // ExeFS:/.code is loaded here
39 {&g_heap, HEAP_VADDR, HEAP_SIZE }, 35 {HEAP_VADDR, HEAP_SIZE, "Heap"}, // Application heap (main memory)
40 {&g_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE }, 36 {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory
41 {&g_heap_linear, LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE }, 37 {LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE, "Linear Heap"}, // Linear heap (main memory)
42 {&g_vram, VRAM_VADDR, VRAM_SIZE }, 38 {VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM)
43 {&g_dsp_mem, DSP_RAM_VADDR, DSP_RAM_SIZE }, 39 {DSP_RAM_VADDR, DSP_RAM_SIZE, "DSP RAM"}, // DSP memory
44 {&g_tls_mem, TLS_AREA_VADDR, TLS_AREA_SIZE }, 40 {TLS_AREA_VADDR, TLS_AREA_SIZE, "TLS Area"}, // TLS memory
45}; 41};
46 42
47/// Represents a block of memory mapped by ControlMemory/MapMemoryBlock 43/// Represents a block of memory mapped by ControlMemory/MapMemoryBlock
@@ -135,27 +131,34 @@ VAddr PhysicalToVirtualAddress(const PAddr addr) {
135 return addr | 0x80000000; 131 return addr | 0x80000000;
136} 132}
137 133
134// TODO(yuriks): Move this into Process
135static Kernel::VMManager address_space;
136
138void Init() { 137void Init() {
138 using namespace Kernel;
139
139 InitMemoryMap(); 140 InitMemoryMap();
140 141
141 for (MemoryArea& area : memory_areas) { 142 for (MemoryArea& area : memory_areas) {
142 *area.ptr = new u8[area.size]; 143 auto block = std::make_shared<std::vector<u8>>(area.size);
143 MapMemoryRegion(area.base, area.size, *area.ptr); 144 address_space.MapMemoryBlock(area.base, std::move(block), 0, area.size, MemoryState::Private).Unwrap();
144 } 145 }
145 MapMemoryRegion(CONFIG_MEMORY_VADDR, CONFIG_MEMORY_SIZE, (u8*)&ConfigMem::config_mem);
146 MapMemoryRegion(SHARED_PAGE_VADDR, SHARED_PAGE_SIZE, (u8*)&SharedPage::shared_page);
147 146
148 LOG_DEBUG(HW_Memory, "initialized OK, RAM at %p", g_heap); 147 auto cfg_mem_vma = address_space.MapBackingMemory(CONFIG_MEMORY_VADDR,
148 (u8*)&ConfigMem::config_mem, CONFIG_MEMORY_SIZE, MemoryState::Shared).MoveFrom();
149 address_space.Reprotect(cfg_mem_vma, VMAPermission::Read);
150
151 auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR,
152 (u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom();
153 address_space.Reprotect(shared_page_vma, VMAPermission::Read);
154
155 LOG_DEBUG(HW_Memory, "initialized OK");
149} 156}
150 157
151void Shutdown() { 158void Shutdown() {
152 heap_map.clear(); 159 heap_map.clear();
153 heap_linear_map.clear(); 160 heap_linear_map.clear();
154 161 address_space.Reset();
155 for (MemoryArea& area : memory_areas) {
156 delete[] *area.ptr;
157 *area.ptr = nullptr;
158 }
159 162
160 LOG_DEBUG(HW_Memory, "shutdown OK"); 163 LOG_DEBUG(HW_Memory, "shutdown OK");
161} 164}
diff --git a/src/core/mem_map.h b/src/core/mem_map.h
index 945815cd6..ba50914a8 100644
--- a/src/core/mem_map.h
+++ b/src/core/mem_map.h
@@ -8,14 +8,6 @@
8 8
9namespace Memory { 9namespace Memory {
10 10
11extern u8* g_exefs_code; ///< ExeFS:/.code is loaded here
12extern u8* g_heap; ///< Application heap (main memory)
13extern u8* g_shared_mem; ///< Shared memory
14extern u8* g_heap_linear; ///< Linear heap (main memory)
15extern u8* g_vram; ///< Video memory (VRAM)
16extern u8* g_dsp_mem; ///< DSP memory
17extern u8* g_tls_mem; ///< TLS memory
18
19void Init(); 11void Init();
20void Shutdown(); 12void Shutdown();
21 13
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 5d8069acd..28844a915 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -14,12 +14,10 @@
14#include "core/hw/hw.h" 14#include "core/hw/hw.h"
15#include "core/mem_map.h" 15#include "core/mem_map.h"
16#include "core/memory.h" 16#include "core/memory.h"
17#include "core/memory_setup.h"
17 18
18namespace Memory { 19namespace Memory {
19 20
20const u32 PAGE_MASK = PAGE_SIZE - 1;
21const int PAGE_BITS = 12;
22
23enum class PageType { 21enum class PageType {
24 /// Page is unmapped and should cause an access error. 22 /// Page is unmapped and should cause an access error.
25 Unmapped, 23 Unmapped,
@@ -64,7 +62,7 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) {
64 while (base != end) { 62 while (base != end) {
65 ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base); 63 ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base);
66 64
67 if (current_page_table->attributes[base] != PageType::Unmapped) { 65 if (current_page_table->attributes[base] != PageType::Unmapped && type != PageType::Unmapped) {
68 LOG_ERROR(HW_Memory, "overlapping memory ranges at %08X", base * PAGE_SIZE); 66 LOG_ERROR(HW_Memory, "overlapping memory ranges at %08X", base * PAGE_SIZE);
69 } 67 }
70 current_page_table->attributes[base] = type; 68 current_page_table->attributes[base] = type;
@@ -92,6 +90,12 @@ void MapIoRegion(VAddr base, u32 size) {
92 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special); 90 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special);
93} 91}
94 92
93void UnmapRegion(VAddr base, u32 size) {
94 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %08X", size);
95 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %08X", base);
96 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped);
97}
98
95template <typename T> 99template <typename T>
96T Read(const VAddr vaddr) { 100T Read(const VAddr vaddr) {
97 const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 101 const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
diff --git a/src/core/memory.h b/src/core/memory.h
index 2d225801b..0b8ff9ec4 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -97,7 +97,7 @@ enum : VAddr {
97 SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE, 97 SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE,
98 98
99 // TODO(yuriks): The size of this area is dynamic, the kernel grows 99 // TODO(yuriks): The size of this area is dynamic, the kernel grows
100 // it as more and more threads are created. For now we'll just use a 100 // it as more and more threads are created. For now we'll just use a
101 // hardcoded value. 101 // hardcoded value.
102 /// Area where TLS (Thread-Local Storage) buffers are allocated. 102 /// Area where TLS (Thread-Local Storage) buffers are allocated.
103 TLS_AREA_VADDR = 0x1FF82000, 103 TLS_AREA_VADDR = 0x1FF82000,
diff --git a/src/core/memory_setup.h b/src/core/memory_setup.h
index 46263495f..361bfc816 100644
--- a/src/core/memory_setup.h
+++ b/src/core/memory_setup.h
@@ -6,8 +6,13 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8 8
9#include "core/memory.h"
10
9namespace Memory { 11namespace Memory {
10 12
13const u32 PAGE_MASK = PAGE_SIZE - 1;
14const int PAGE_BITS = 12;
15
11void InitMemoryMap(); 16void InitMemoryMap();
12 17
13/** 18/**
@@ -26,4 +31,6 @@ void MapMemoryRegion(VAddr base, u32 size, u8* target);
26 */ 31 */
27void MapIoRegion(VAddr base, u32 size); 32void MapIoRegion(VAddr base, u32 size);
28 33
34void UnmapRegion(VAddr base, u32 size);
35
29} 36}
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index 100d8c7c1..b46fadd9f 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) {
56 // Trigger IRQ 56 // Trigger IRQ
57 case PICA_REG_INDEX(trigger_irq): 57 case PICA_REG_INDEX(trigger_irq):
58 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D); 58 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D);
59 return; 59 break;
60
61 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c):
62 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d):
63 {
64 unsigned index = id - PICA_REG_INDEX(command_buffer.trigger[0]);
65 u32* head_ptr = (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index));
66 g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr;
67 g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32);
68 break;
69 }
60 70
61 // It seems like these trigger vertex rendering 71 // It seems like these trigger vertex rendering
62 case PICA_REG_INDEX(trigger_draw): 72 case PICA_REG_INDEX(trigger_draw):
@@ -136,7 +146,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
136 input.attr[i][0].ToFloat32(), input.attr[i][1].ToFloat32(), 146 input.attr[i][0].ToFloat32(), input.attr[i][1].ToFloat32(),
137 input.attr[i][2].ToFloat32(), input.attr[i][3].ToFloat32()); 147 input.attr[i][2].ToFloat32(), input.attr[i][3].ToFloat32());
138 } 148 }
139 149
140 // Load per-vertex data from the loader arrays 150 // Load per-vertex data from the loader arrays
141 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { 151 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
142 const u8* srcdata = Memory::GetPhysicalPointer(vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]); 152 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) {
193 const Pica::VertexShader::OutputVertex& v2) { 203 const Pica::VertexShader::OutputVertex& v2) {
194 VideoCore::g_renderer->hw_rasterizer->AddTriangle(v0, v1, v2); 204 VideoCore::g_renderer->hw_rasterizer->AddTriangle(v0, v1, v2);
195 }; 205 };
196 206
197 primitive_assembler.SubmitVertex(output, AddHWTriangle); 207 primitive_assembler.SubmitVertex(output, AddHWTriangle);
198 } else { 208 } else {
199 // Send to triangle clipper 209 // Send to triangle clipper
@@ -282,7 +292,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
282 } 292 }
283 break; 293 break;
284 } 294 }
285 295
286 // Load default vertex input attributes 296 // Load default vertex input attributes
287 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233): 297 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233):
288 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234): 298 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) {
306 } 316 }
307 317
308 Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index]; 318 Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index];
309 319
310 // NOTE: The destination component order indeed is "backwards" 320 // NOTE: The destination component order indeed is "backwards"
311 attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8); 321 attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8);
312 attribute.z = float24::FromRawFloat24(((default_attr_write_buffer[0] & 0xFF) << 16) | ((default_attr_write_buffer[1] >> 16) & 0xFFFF)); 322 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) {
363 g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id)); 373 g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id));
364} 374}
365 375
366static std::ptrdiff_t ExecuteCommandBlock(const u32* first_command_word) {
367 const CommandHeader& header = *(const CommandHeader*)(&first_command_word[1]);
368
369 u32* read_pointer = (u32*)first_command_word;
370
371 const u32 write_mask = ((header.parameter_mask & 0x1) ? (0xFFu << 0) : 0u) |
372 ((header.parameter_mask & 0x2) ? (0xFFu << 8) : 0u) |
373 ((header.parameter_mask & 0x4) ? (0xFFu << 16) : 0u) |
374 ((header.parameter_mask & 0x8) ? (0xFFu << 24) : 0u);
375
376 WritePicaReg(header.cmd_id, *read_pointer, write_mask);
377 read_pointer += 2;
378
379 for (unsigned int i = 1; i < 1+header.extra_data_length; ++i) {
380 u32 cmd = header.cmd_id + ((header.group_commands) ? i : 0);
381 WritePicaReg(cmd, *read_pointer, write_mask);
382 ++read_pointer;
383 }
384
385 // align read pointer to 8 bytes
386 if ((first_command_word - read_pointer) % 2)
387 ++read_pointer;
388
389 return read_pointer - first_command_word;
390}
391
392void ProcessCommandList(const u32* list, u32 size) { 376void ProcessCommandList(const u32* list, u32 size) {
393 u32* read_pointer = (u32*)list; 377 g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = list;
394 u32 list_length = size / sizeof(u32); 378 g_state.cmd_list.length = size / sizeof(u32);
395 379
396 while (read_pointer < list + list_length) { 380 while (g_state.cmd_list.current_ptr < g_state.cmd_list.head_ptr + g_state.cmd_list.length) {
397 read_pointer += ExecuteCommandBlock(read_pointer); 381 // Expand a 4-bit mask to 4-byte mask, e.g. 0b0101 -> 0x00FF00FF
382 static const u32 expand_bits_to_bytes[] = {
383 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
384 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
385 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
386 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff
387 };
388
389 // Align read pointer to 8 bytes
390 if ((g_state.cmd_list.head_ptr - g_state.cmd_list.current_ptr) % 2 != 0)
391 ++g_state.cmd_list.current_ptr;
392
393 u32 value = *g_state.cmd_list.current_ptr++;
394 const CommandHeader header = { *g_state.cmd_list.current_ptr++ };
395 const u32 write_mask = expand_bits_to_bytes[header.parameter_mask];
396 u32 cmd = header.cmd_id;
397
398 WritePicaReg(cmd, value, write_mask);
399
400 for (unsigned i = 0; i < header.extra_data_length; ++i) {
401 u32 cmd = header.cmd_id + (header.group_commands ? i + 1 : 0);
402 WritePicaReg(cmd, *g_state.cmd_list.current_ptr++, write_mask);
403 }
398 } 404 }
399} 405}
400 406
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 7987b922c..b92cd1a7e 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
319 // TODO(neobrain): Fix code design to unify vertical block offsets! 319 // TODO(neobrain): Fix code design to unify vertical block offsets!
320 source += coarse_y * info.stride; 320 source += coarse_y * info.stride;
321 } 321 }
322 322
323 // TODO: Assert that width/height are multiples of block dimensions 323 // TODO: Assert that width/height are multiples of block dimensions
324 324
325 switch (info.format) { 325 switch (info.format) {
diff --git a/src/video_core/math.h b/src/video_core/math.h
index f9a822658..4928c9bf2 100644
--- a/src/video_core/math.h
+++ b/src/video_core/math.h
@@ -461,7 +461,7 @@ public:
461 // e.g. Vec2 uv() { return Vec2(x,y); } 461 // e.g. Vec2 uv() { return Vec2(x,y); }
462 462
463 // _DEFINE_SWIZZLER2 defines a single such function 463 // _DEFINE_SWIZZLER2 defines a single such function
464 // DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r) 464 // DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r)
465 // DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and permutations (xy<->yx) 465 // DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and permutations (xy<->yx)
466#define _DEFINE_SWIZZLER2(a, b, name) const Vec2<T> name() const { return Vec2<T>(a, b); } 466#define _DEFINE_SWIZZLER2(a, b, name) const Vec2<T> name() const { return Vec2<T>(a, b); }
467#define DEFINE_SWIZZLER2_COMP1(a, a2) \ 467#define DEFINE_SWIZZLER2_COMP1(a, a2) \
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index b67dce1a9..8ad47a928 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -16,7 +16,7 @@
16#include "common/common_types.h" 16#include "common/common_types.h"
17#include "common/logging/log.h" 17#include "common/logging/log.h"
18 18
19#include "math.h" 19#include "math.h"
20 20
21namespace Pica { 21namespace Pica {
22 22
@@ -162,6 +162,25 @@ struct Regs {
162 ETC1A4 = 13, // compressed 162 ETC1A4 = 13, // compressed
163 }; 163 };
164 164
165 enum class LogicOp : u32 {
166 Clear = 0,
167 And = 1,
168 AndReverse = 2,
169 Copy = 3,
170 Set = 4,
171 CopyInverted = 5,
172 NoOp = 6,
173 Invert = 7,
174 Nand = 8,
175 Or = 9,
176 Nor = 10,
177 Xor = 11,
178 Equiv = 12,
179 AndInverted = 13,
180 OrReverse = 14,
181 OrInverted = 15,
182 };
183
165 static unsigned NibblesPerPixel(TextureFormat format) { 184 static unsigned NibblesPerPixel(TextureFormat format) {
166 switch (format) { 185 switch (format) {
167 case TextureFormat::RGBA8: 186 case TextureFormat::RGBA8:
@@ -221,6 +240,7 @@ struct Regs {
221 enum class Source : u32 { 240 enum class Source : u32 {
222 PrimaryColor = 0x0, 241 PrimaryColor = 0x0,
223 PrimaryFragmentColor = 0x1, 242 PrimaryFragmentColor = 0x1,
243 SecondaryFragmentColor = 0x2,
224 244
225 Texture0 = 0x3, 245 Texture0 = 0x3,
226 Texture1 = 0x4, 246 Texture1 = 0x4,
@@ -337,7 +357,7 @@ struct Regs {
337 return (stage_index < 4) && (update_mask_a & (1 << stage_index)); 357 return (stage_index < 4) && (update_mask_a & (1 << stage_index));
338 } 358 }
339 } tev_combiner_buffer_input; 359 } tev_combiner_buffer_input;
340 360
341 INSERT_PADDING_WORDS(0xf); 361 INSERT_PADDING_WORDS(0xf);
342 TevStageConfig tev_stage4; 362 TevStageConfig tev_stage4;
343 INSERT_PADDING_WORDS(0x3); 363 INSERT_PADDING_WORDS(0x3);
@@ -413,12 +433,8 @@ struct Regs {
413 } alpha_blending; 433 } alpha_blending;
414 434
415 union { 435 union {
416 enum Op { 436 BitField<0, 4, LogicOp> logic_op;
417 Set = 4, 437 };
418 };
419
420 BitField<0, 4, Op> op;
421 } logic_op;
422 438
423 union { 439 union {
424 BitField< 0, 8, u32> r; 440 BitField< 0, 8, u32> r;
@@ -703,12 +719,38 @@ struct Regs {
703 struct { 719 struct {
704 // Index of the current default attribute 720 // Index of the current default attribute
705 u32 index; 721 u32 index;
706 722
707 // Writing to these registers sets the "current" default attribute. 723 // Writing to these registers sets the "current" default attribute.
708 u32 set_value[3]; 724 u32 set_value[3];
709 } vs_default_attributes_setup; 725 } vs_default_attributes_setup;
710 726
711 INSERT_PADDING_WORDS(0x28); 727 INSERT_PADDING_WORDS(0x2);
728
729 struct {
730 // There are two channels that can be used to configure the next command buffer, which
731 // can be then executed by writing to the "trigger" registers. There are two reasons why a
732 // game might use this feature:
733 // 1) With this, an arbitrary number of additional command buffers may be executed in
734 // sequence without requiring any intervention of the CPU after the initial one is
735 // kicked off.
736 // 2) Games can configure these registers to provide a command list subroutine mechanism.
737
738 BitField< 0, 20, u32> size[2]; ///< Size (in bytes / 8) of each channel's command buffer
739 BitField< 0, 28, u32> addr[2]; ///< Physical address / 8 of each channel's command buffer
740 u32 trigger[2]; ///< Triggers execution of the channel's command buffer when written to
741
742 unsigned GetSize(unsigned index) const {
743 ASSERT(index < 2);
744 return 8 * size[index];
745 }
746
747 PAddr GetPhysicalAddress(unsigned index) const {
748 ASSERT(index < 2);
749 return (PAddr)(8 * addr[index]);
750 }
751 } command_buffer;
752
753 INSERT_PADDING_WORDS(0x20);
712 754
713 enum class TriangleTopology : u32 { 755 enum class TriangleTopology : u32 {
714 List = 0, 756 List = 0,
@@ -861,6 +903,7 @@ struct Regs {
861 ADD_FIELD(trigger_draw); 903 ADD_FIELD(trigger_draw);
862 ADD_FIELD(trigger_draw_indexed); 904 ADD_FIELD(trigger_draw_indexed);
863 ADD_FIELD(vs_default_attributes_setup); 905 ADD_FIELD(vs_default_attributes_setup);
906 ADD_FIELD(command_buffer);
864 ADD_FIELD(triangle_topology); 907 ADD_FIELD(triangle_topology);
865 ADD_FIELD(vs_bool_uniforms); 908 ADD_FIELD(vs_bool_uniforms);
866 ADD_FIELD(vs_int_uniforms); 909 ADD_FIELD(vs_int_uniforms);
@@ -938,6 +981,7 @@ ASSERT_REG_POSITION(num_vertices, 0x228);
938ASSERT_REG_POSITION(trigger_draw, 0x22e); 981ASSERT_REG_POSITION(trigger_draw, 0x22e);
939ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f); 982ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f);
940ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232); 983ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232);
984ASSERT_REG_POSITION(command_buffer, 0x238);
941ASSERT_REG_POSITION(triangle_topology, 0x25e); 985ASSERT_REG_POSITION(triangle_topology, 0x25e);
942ASSERT_REG_POSITION(vs_bool_uniforms, 0x2b0); 986ASSERT_REG_POSITION(vs_bool_uniforms, 0x2b0);
943ASSERT_REG_POSITION(vs_int_uniforms, 0x2b1); 987ASSERT_REG_POSITION(vs_int_uniforms, 0x2b1);
@@ -1053,21 +1097,12 @@ private:
1053 float value; 1097 float value;
1054}; 1098};
1055 1099
1056union CommandHeader {
1057 CommandHeader(u32 h) : hex(h) {}
1058
1059 u32 hex;
1060
1061 BitField< 0, 16, u32> cmd_id;
1062 BitField<16, 4, u32> parameter_mask;
1063 BitField<20, 11, u32> extra_data_length;
1064 BitField<31, 1, u32> group_commands;
1065};
1066
1067/// Struct used to describe current Pica state 1100/// Struct used to describe current Pica state
1068struct State { 1101struct State {
1102 /// Pica registers
1069 Regs regs; 1103 Regs regs;
1070 1104
1105 /// Vertex shader memory
1071 struct { 1106 struct {
1072 struct { 1107 struct {
1073 Math::Vec4<float24> f[96]; 1108 Math::Vec4<float24> f[96];
@@ -1080,6 +1115,13 @@ struct State {
1080 std::array<u32, 1024> program_code; 1115 std::array<u32, 1024> program_code;
1081 std::array<u32, 1024> swizzle_data; 1116 std::array<u32, 1024> swizzle_data;
1082 } vs; 1117 } vs;
1118
1119 /// Current Pica command list
1120 struct {
1121 const u32* head_ptr;
1122 const u32* current_ptr;
1123 u32 length;
1124 } cmd_list;
1083}; 1125};
1084 1126
1085/// Initialize Pica state 1127/// Initialize Pica state
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 767ff4205..113b573f8 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -104,7 +104,7 @@ static u32 GetDepth(int x, int y) {
104 u8* depth_buffer = Memory::GetPhysicalPointer(addr); 104 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
105 105
106 y = framebuffer.height - y; 106 y = framebuffer.height - y;
107 107
108 const u32 coarse_y = y & ~7; 108 const u32 coarse_y = y & ~7;
109 u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format); 109 u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format);
110 u32 stride = framebuffer.width * bytes_per_pixel; 110 u32 stride = framebuffer.width * bytes_per_pixel;
@@ -402,11 +402,16 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
402 402
403 auto GetSource = [&](Source source) -> Math::Vec4<u8> { 403 auto GetSource = [&](Source source) -> Math::Vec4<u8> {
404 switch (source) { 404 switch (source) {
405 // TODO: What's the difference between these two?
406 case Source::PrimaryColor: 405 case Source::PrimaryColor:
406
407 // HACK: Until we implement fragment lighting, use primary_color
407 case Source::PrimaryFragmentColor: 408 case Source::PrimaryFragmentColor:
408 return primary_color; 409 return primary_color;
409 410
411 // HACK: Until we implement fragment lighting, use zero
412 case Source::SecondaryFragmentColor:
413 return {0, 0, 0, 0};
414
410 case Source::Texture0: 415 case Source::Texture0:
411 return texture_color[0]; 416 return texture_color[0];
412 417
@@ -570,6 +575,13 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
570 case Operation::Add: 575 case Operation::Add:
571 return std::min(255, input[0] + input[1]); 576 return std::min(255, input[0] + input[1]);
572 577
578 case Operation::AddSigned:
579 {
580 // TODO(bunnei): Verify that the color conversion from (float) 0.5f to (byte) 128 is correct
581 auto result = static_cast<int>(input[0]) + static_cast<int>(input[1]) - 128;
582 return static_cast<u8>(MathUtil::Clamp<int>(result, 0, 255));
583 }
584
573 case Operation::Lerp: 585 case Operation::Lerp:
574 return (input[0] * input[2] + input[1] * (255 - input[2])) / 255; 586 return (input[0] * input[2] + input[1] * (255 - input[2])) / 255;
575 587
@@ -808,10 +820,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
808 } 820 }
809 }; 821 };
810 822
811 using BlendEquation = Regs::BlendEquation;
812 static auto EvaluateBlendEquation = [](const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor, 823 static auto EvaluateBlendEquation = [](const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor,
813 const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor, 824 const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor,
814 BlendEquation equation) { 825 Regs::BlendEquation equation) {
815 Math::Vec4<int> result; 826 Math::Vec4<int> result;
816 827
817 auto src_result = (src * srcfactor).Cast<int>(); 828 auto src_result = (src * srcfactor).Cast<int>();
@@ -866,8 +877,63 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
866 blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb); 877 blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb);
867 blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a(); 878 blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a();
868 } else { 879 } else {
869 LOG_CRITICAL(HW_GPU, "logic op: %x", output_merger.logic_op); 880 static auto LogicOp = [](u8 src, u8 dest, Regs::LogicOp op) -> u8 {
870 UNIMPLEMENTED(); 881 switch (op) {
882 case Regs::LogicOp::Clear:
883 return 0;
884
885 case Regs::LogicOp::And:
886 return src & dest;
887
888 case Regs::LogicOp::AndReverse:
889 return src & ~dest;
890
891 case Regs::LogicOp::Copy:
892 return src;
893
894 case Regs::LogicOp::Set:
895 return 255;
896
897 case Regs::LogicOp::CopyInverted:
898 return ~src;
899
900 case Regs::LogicOp::NoOp:
901 return dest;
902
903 case Regs::LogicOp::Invert:
904 return ~dest;
905
906 case Regs::LogicOp::Nand:
907 return ~(src & dest);
908
909 case Regs::LogicOp::Or:
910 return src | dest;
911
912 case Regs::LogicOp::Nor:
913 return ~(src | dest);
914
915 case Regs::LogicOp::Xor:
916 return src ^ dest;
917
918 case Regs::LogicOp::Equiv:
919 return ~(src ^ dest);
920
921 case Regs::LogicOp::AndInverted:
922 return ~src & dest;
923
924 case Regs::LogicOp::OrReverse:
925 return src | ~dest;
926
927 case Regs::LogicOp::OrInverted:
928 return ~src | dest;
929 }
930 };
931
932 blend_output = Math::MakeVec(
933 LogicOp(combiner_output.r(), dest.r(), output_merger.logic_op),
934 LogicOp(combiner_output.g(), dest.g(), output_merger.logic_op),
935 LogicOp(combiner_output.b(), dest.b(), output_merger.logic_op),
936 LogicOp(combiner_output.a(), dest.a(), output_merger.logic_op));
871 } 937 }
872 938
873 const Math::Vec4<u8> result = { 939 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 ef29972d7..95fd29c0a 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)
62 ptrdiff_t iTest; 62 ptrdiff_t iTest;
63 if(!pTest) return 0; 63 if(!pTest) return 0;
64 iTest = (ptrdiff_t)pTest; 64 iTest = (ptrdiff_t)pTest;
65 65
66 if(iTest == 1 || iTest == 2 || iTest == 3 || iTest == -1) return 0; 66 if(iTest == 1 || iTest == 2 || iTest == 3 || iTest == -1) return 0;
67 67
68 return 1; 68 return 1;
69} 69}
70 70
@@ -79,7 +79,7 @@ static PROC WinGetProcAddress(const char *name)
79 glMod = GetModuleHandleA("OpenGL32.dll"); 79 glMod = GetModuleHandleA("OpenGL32.dll");
80 return (PROC)GetProcAddress(glMod, (LPCSTR)name); 80 return (PROC)GetProcAddress(glMod, (LPCSTR)name);
81} 81}
82 82
83#define IntGetProcAddress(name) WinGetProcAddress(name) 83#define IntGetProcAddress(name) WinGetProcAddress(name)
84#else 84#else
85 #if defined(__APPLE__) 85 #if defined(__APPLE__)
@@ -1083,7 +1083,7 @@ static ogl_StrToExtMap *FindExtEntry(const char *extensionName)
1083 if(strcmp(extensionName, currLoc->extensionName) == 0) 1083 if(strcmp(extensionName, currLoc->extensionName) == 0)
1084 return currLoc; 1084 return currLoc;
1085 } 1085 }
1086 1086
1087 return NULL; 1087 return NULL;
1088} 1088}
1089 1089
@@ -1135,15 +1135,15 @@ int ogl_LoadFunctions()
1135{ 1135{
1136 int numFailed = 0; 1136 int numFailed = 0;
1137 ClearExtensionVars(); 1137 ClearExtensionVars();
1138 1138
1139 _ptrc_glGetIntegerv = (void (CODEGEN_FUNCPTR *)(GLenum, GLint *))IntGetProcAddress("glGetIntegerv"); 1139 _ptrc_glGetIntegerv = (void (CODEGEN_FUNCPTR *)(GLenum, GLint *))IntGetProcAddress("glGetIntegerv");
1140 if(!_ptrc_glGetIntegerv) return ogl_LOAD_FAILED; 1140 if(!_ptrc_glGetIntegerv) return ogl_LOAD_FAILED;
1141 _ptrc_glGetStringi = (const GLubyte * (CODEGEN_FUNCPTR *)(GLenum, GLuint))IntGetProcAddress("glGetStringi"); 1141 _ptrc_glGetStringi = (const GLubyte * (CODEGEN_FUNCPTR *)(GLenum, GLuint))IntGetProcAddress("glGetStringi");
1142 if(!_ptrc_glGetStringi) return ogl_LOAD_FAILED; 1142 if(!_ptrc_glGetStringi) return ogl_LOAD_FAILED;
1143 1143
1144 ProcExtsFromExtList(); 1144 ProcExtsFromExtList();
1145 numFailed = Load_Version_3_2(); 1145 numFailed = Load_Version_3_2();
1146 1146
1147 if(numFailed == 0) 1147 if(numFailed == 0)
1148 return ogl_LOAD_SUCCEEDED; 1148 return ogl_LOAD_SUCCEEDED;
1149 else 1149 else
@@ -1177,7 +1177,7 @@ int ogl_IsVersionGEQ(int majorVersion, int minorVersion)
1177{ 1177{
1178 if(g_major_version == 0) 1178 if(g_major_version == 0)
1179 GetGLVersion(); 1179 GetGLVersion();
1180 1180
1181 if(majorVersion > g_major_version) return 1; 1181 if(majorVersion > g_major_version) return 1;
1182 if(majorVersion < g_major_version) return 0; 1182 if(majorVersion < g_major_version) return 0;
1183 if(minorVersion >= g_minor_version) return 1; 1183 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 4b7d099a5..b51f8efdf 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() {
135 SyncBlendFuncs(); 135 SyncBlendFuncs();
136 SyncBlendColor(); 136 SyncBlendColor();
137 SyncAlphaTest(); 137 SyncAlphaTest();
138 SyncLogicOp();
138 SyncStencilTest(); 139 SyncStencilTest();
139 SyncDepthTest(); 140 SyncDepthTest();
140 141
@@ -249,6 +250,11 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
249 SyncDepthTest(); 250 SyncDepthTest();
250 break; 251 break;
251 252
253 // Logic op
254 case PICA_REG_INDEX(output_merger.logic_op):
255 SyncLogicOp();
256 break;
257
252 // TEV stage 0 258 // TEV stage 0
253 case PICA_REG_INDEX(tev_stage0.color_source1): 259 case PICA_REG_INDEX(tev_stage0.color_source1):
254 SyncTevSources(0, regs.tev_stage0); 260 SyncTevSources(0, regs.tev_stage0);
@@ -350,7 +356,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
350 case PICA_REG_INDEX(tev_stage5.color_scale): 356 case PICA_REG_INDEX(tev_stage5.color_scale):
351 SyncTevMultipliers(5, regs.tev_stage5); 357 SyncTevMultipliers(5, regs.tev_stage5);
352 break; 358 break;
353 359
354 // TEV combiner buffer color 360 // TEV combiner buffer color
355 case PICA_REG_INDEX(tev_combiner_buffer_color): 361 case PICA_REG_INDEX(tev_combiner_buffer_color):
356 SyncCombinerColor(); 362 SyncCombinerColor();
@@ -633,6 +639,10 @@ void RasterizerOpenGL::SyncAlphaTest() {
633 glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f); 639 glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f);
634} 640}
635 641
642void RasterizerOpenGL::SyncLogicOp() {
643 state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op);
644}
645
636void RasterizerOpenGL::SyncStencilTest() { 646void RasterizerOpenGL::SyncStencilTest() {
637 // TODO: Implement stencil test, mask, and op 647 // TODO: Implement stencil test, mask, and op
638} 648}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 9896f8d04..d7d422b1f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -125,6 +125,9 @@ private:
125 /// Syncs the alpha test states to match the PICA register 125 /// Syncs the alpha test states to match the PICA register
126 void SyncAlphaTest(); 126 void SyncAlphaTest();
127 127
128 /// Syncs the logic op states to match the PICA register
129 void SyncLogicOp();
130
128 /// Syncs the stencil test states to match the PICA register 131 /// Syncs the stencil test states to match the PICA register
129 void SyncStencilTest(); 132 void SyncStencilTest();
130 133
diff --git a/src/video_core/renderer_opengl/gl_shaders.h b/src/video_core/renderer_opengl/gl_shaders.h
index 8f0941230..a8cb2f595 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"(
69#define NUM_VTX_ATTR 7 69#define NUM_VTX_ATTR 7
70#define NUM_TEV_STAGES 6 70#define NUM_TEV_STAGES 6
71 71
72#define SOURCE_PRIMARYCOLOR 0x0 72#define SOURCE_PRIMARYCOLOR 0x0
73#define SOURCE_PRIMARYFRAGMENTCOLOR 0x1 73#define SOURCE_PRIMARYFRAGMENTCOLOR 0x1
74#define SOURCE_TEXTURE0 0x3 74#define SOURCE_SECONDARYFRAGMENTCOLOR 0x2
75#define SOURCE_TEXTURE1 0x4 75#define SOURCE_TEXTURE0 0x3
76#define SOURCE_TEXTURE2 0x5 76#define SOURCE_TEXTURE1 0x4
77#define SOURCE_TEXTURE3 0x6 77#define SOURCE_TEXTURE2 0x5
78#define SOURCE_PREVIOUSBUFFER 0xd 78#define SOURCE_TEXTURE3 0x6
79#define SOURCE_CONSTANT 0xe 79#define SOURCE_PREVIOUSBUFFER 0xd
80#define SOURCE_PREVIOUS 0xf 80#define SOURCE_CONSTANT 0xe
81#define SOURCE_PREVIOUS 0xf
81 82
82#define COLORMODIFIER_SOURCECOLOR 0x0 83#define COLORMODIFIER_SOURCECOLOR 0x0
83#define COLORMODIFIER_ONEMINUSSOURCECOLOR 0x1 84#define COLORMODIFIER_ONEMINUSSOURCECOLOR 0x1
@@ -151,8 +152,11 @@ vec4 GetSource(int source) {
151 if (source == SOURCE_PRIMARYCOLOR) { 152 if (source == SOURCE_PRIMARYCOLOR) {
152 return o[2]; 153 return o[2];
153 } else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) { 154 } else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) {
154 // HACK: Uses color value, but should really use fragment lighting output 155 // HACK: Until we implement fragment lighting, use primary_color
155 return o[2]; 156 return o[2];
157 } else if (source == SOURCE_SECONDARYFRAGMENTCOLOR) {
158 // HACK: Until we implement fragment lighting, use zero
159 return vec4(0.0, 0.0, 0.0, 0.0);
156 } else if (source == SOURCE_TEXTURE0) { 160 } else if (source == SOURCE_TEXTURE0) {
157 return texture(tex[0], o[3].xy); 161 return texture(tex[0], o[3].xy);
158 } else if (source == SOURCE_TEXTURE1) { 162 } 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 1afa58c99..9c5f38f94 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() {
32 blend.color.blue = 0.0f; 32 blend.color.blue = 0.0f;
33 blend.color.alpha = 0.0f; 33 blend.color.alpha = 0.0f;
34 34
35 logic_op = GL_COPY;
36
35 for (auto& texture_unit : texture_units) { 37 for (auto& texture_unit : texture_units) {
36 texture_unit.enabled_2d = false; 38 texture_unit.enabled_2d = false;
37 texture_unit.texture_2d = 0; 39 texture_unit.texture_2d = 0;
@@ -82,7 +84,7 @@ void OpenGLState::Apply() {
82 } else { 84 } else {
83 glDisable(GL_STENCIL_TEST); 85 glDisable(GL_STENCIL_TEST);
84 } 86 }
85 } 87 }
86 88
87 if (stencil.test_func != cur_state.stencil.test_func || 89 if (stencil.test_func != cur_state.stencil.test_func ||
88 stencil.test_ref != cur_state.stencil.test_ref || 90 stencil.test_ref != cur_state.stencil.test_ref ||
@@ -99,8 +101,13 @@ void OpenGLState::Apply() {
99 if (blend.enabled != cur_state.blend.enabled) { 101 if (blend.enabled != cur_state.blend.enabled) {
100 if (blend.enabled) { 102 if (blend.enabled) {
101 glEnable(GL_BLEND); 103 glEnable(GL_BLEND);
104
105 cur_state.logic_op = GL_COPY;
106 glLogicOp(cur_state.logic_op);
107 glDisable(GL_COLOR_LOGIC_OP);
102 } else { 108 } else {
103 glDisable(GL_BLEND); 109 glDisable(GL_BLEND);
110 glEnable(GL_COLOR_LOGIC_OP);
104 } 111 }
105 } 112 }
106 113
@@ -118,6 +125,10 @@ void OpenGLState::Apply() {
118 glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, blend.dst_a_func); 125 glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, blend.dst_a_func);
119 } 126 }
120 127
128 if (logic_op != cur_state.logic_op) {
129 glLogicOp(logic_op);
130 }
131
121 // Textures 132 // Textures
122 for (unsigned texture_index = 0; texture_index < ARRAY_SIZE(texture_units); ++texture_index) { 133 for (unsigned texture_index = 0; texture_index < ARRAY_SIZE(texture_units); ++texture_index) {
123 if (texture_units[texture_index].enabled_2d != cur_state.texture_units[texture_index].enabled_2d) { 134 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 281b7cad5..6b97721d6 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -42,6 +42,8 @@ public:
42 } color; // GL_BLEND_COLOR 42 } color; // GL_BLEND_COLOR
43 } blend; 43 } blend;
44 44
45 GLenum logic_op; // GL_LOGIC_OP_MODE
46
45 // 3 texture units - one for each that is used in PICA fragment shader emulation 47 // 3 texture units - one for each that is used in PICA fragment shader emulation
46 struct { 48 struct {
47 bool enabled_2d; // GL_TEXTURE_2D 49 bool enabled_2d; // GL_TEXTURE_2D
@@ -61,7 +63,7 @@ public:
61 static const OpenGLState& GetCurState() { 63 static const OpenGLState& GetCurState() {
62 return cur_state; 64 return cur_state;
63 } 65 }
64 66
65 /// Apply this state as the current OpenGL state 67 /// Apply this state as the current OpenGL state
66 void Apply(); 68 void Apply();
67 69
diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h
index f8763e71b..e566f9f7a 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) {
71 return blend_func_table[(unsigned)factor]; 71 return blend_func_table[(unsigned)factor];
72} 72}
73 73
74inline GLenum LogicOp(Pica::Regs::LogicOp op) {
75 static const GLenum logic_op_table[] = {
76 GL_CLEAR, // Clear
77 GL_AND, // And
78 GL_AND_REVERSE, // AndReverse
79 GL_COPY, // Copy
80 GL_SET, // Set
81 GL_COPY_INVERTED, // CopyInverted
82 GL_NOOP, // NoOp
83 GL_INVERT, // Invert
84 GL_NAND, // Nand
85 GL_OR, // Or
86 GL_NOR, // Nor
87 GL_XOR, // Xor
88 GL_EQUIV, // Equiv
89 GL_AND_INVERTED, // AndInverted
90 GL_OR_REVERSE, // OrReverse
91 GL_OR_INVERTED, // OrInverted
92 };
93
94 // Range check table for input
95 if ((unsigned)op >= ARRAY_SIZE(logic_op_table)) {
96 LOG_CRITICAL(Render_OpenGL, "Unknown logic op %d", op);
97 UNREACHABLE();
98
99 return GL_COPY;
100 }
101
102 return logic_op_table[(unsigned)op];
103}
104
74inline GLenum CompareFunc(Pica::Regs::CompareFunc func) { 105inline GLenum CompareFunc(Pica::Regs::CompareFunc func) {
75 static const GLenum compare_func_table[] = { 106 static const GLenum compare_func_table[] = {
76 GL_NEVER, // CompareFunc::Never 107 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 16cf92e20..382aeaa05 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&
157 state.texture_units[0].enabled_2d = true; 157 state.texture_units[0].enabled_2d = true;
158 state.texture_units[0].texture_2d = texture.handle; 158 state.texture_units[0].texture_2d = texture.handle;
159 state.Apply(); 159 state.Apply();
160 160
161 glActiveTexture(GL_TEXTURE0); 161 glActiveTexture(GL_TEXTURE0);
162 glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride); 162 glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride);
163 163
diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp
index 7d68998f1..87006a832 100644
--- a/src/video_core/vertex_shader.cpp
+++ b/src/video_core/vertex_shader.cpp
@@ -119,17 +119,13 @@ static void ProcessShaderCode(VertexShaderState& state) {
119 switch (instr.opcode.Value().GetInfo().type) { 119 switch (instr.opcode.Value().GetInfo().type) {
120 case OpCode::Type::Arithmetic: 120 case OpCode::Type::Arithmetic:
121 { 121 {
122 bool is_inverted = 0 != (instr.opcode.Value().GetInfo().subtype & OpCode::Info::SrcInversed); 122 const bool is_inverted = (0 != (instr.opcode.Value().GetInfo().subtype & OpCode::Info::SrcInversed));
123 // TODO: We don't really support this properly: For instance, the address register
124 // offset needs to be applied to SRC2 instead, etc.
125 // For now, we just abort in this situation.
126 ASSERT_MSG(!is_inverted, "Bad condition...");
127 123
128 const int address_offset = (instr.common.address_register_index == 0) 124 const int address_offset = (instr.common.address_register_index == 0)
129 ? 0 : state.address_registers[instr.common.address_register_index - 1]; 125 ? 0 : state.address_registers[instr.common.address_register_index - 1];
130 126
131 const float24* src1_ = LookupSourceRegister(instr.common.GetSrc1(is_inverted) + address_offset); 127 const float24* src1_ = LookupSourceRegister(instr.common.GetSrc1(is_inverted) + (!is_inverted * address_offset));
132 const float24* src2_ = LookupSourceRegister(instr.common.GetSrc2(is_inverted)); 128 const float24* src2_ = LookupSourceRegister(instr.common.GetSrc2(is_inverted) + ( is_inverted * address_offset));
133 129
134 const bool negate_src1 = ((bool)swizzle.negate_src1 != false); 130 const bool negate_src1 = ((bool)swizzle.negate_src1 != false);
135 const bool negate_src2 = ((bool)swizzle.negate_src2 != false); 131 const bool negate_src2 = ((bool)swizzle.negate_src2 != false);
@@ -208,6 +204,15 @@ static void ProcessShaderCode(VertexShaderState& state) {
208 } 204 }
209 break; 205 break;
210 206
207 case OpCode::Id::MIN:
208 for (int i = 0; i < 4; ++i) {
209 if (!swizzle.DestComponentEnabled(i))
210 continue;
211
212 dest[i] = std::min(src1[i], src2[i]);
213 }
214 break;
215
211 case OpCode::Id::DP3: 216 case OpCode::Id::DP3:
212 case OpCode::Id::DP4: 217 case OpCode::Id::DP4:
213 { 218 {
@@ -279,6 +284,16 @@ static void ProcessShaderCode(VertexShaderState& state) {
279 break; 284 break;
280 } 285 }
281 286
287 case OpCode::Id::SLT:
288 case OpCode::Id::SLTI:
289 for (int i = 0; i < 4; ++i) {
290 if (!swizzle.DestComponentEnabled(i))
291 continue;
292
293 dest[i] = (src1[i] < src2[i]) ? float24::FromFloat32(1.0f) : float24::FromFloat32(0.0f);
294 }
295 break;
296
282 case OpCode::Id::CMP: 297 case OpCode::Id::CMP:
283 for (int i = 0; i < 2; ++i) { 298 for (int i = 0; i < 2; ++i) {
284 // TODO: Can you restrict to one compare via dest masking? 299 // TODO: Can you restrict to one compare via dest masking?
@@ -330,7 +345,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
330 345
331 case OpCode::Type::MultiplyAdd: 346 case OpCode::Type::MultiplyAdd:
332 { 347 {
333 if ((instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD) || 348 if ((instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD) ||
334 (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MADI)) { 349 (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MADI)) {
335 const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.mad.operand_desc_id]; 350 const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.mad.operand_desc_id];
336 351
@@ -547,7 +562,7 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes) {
547 const auto& attribute_register_map = regs.vs_input_register_map; 562 const auto& attribute_register_map = regs.vs_input_register_map;
548 float24 dummy_register; 563 float24 dummy_register;
549 boost::fill(state.input_register_table, &dummy_register); 564 boost::fill(state.input_register_table, &dummy_register);
550 565
551 if (num_attributes > 0) state.input_register_table[attribute_register_map.attribute0_register] = &input.attr[0].x; 566 if (num_attributes > 0) state.input_register_table[attribute_register_map.attribute0_register] = &input.attr[0].x;
552 if (num_attributes > 1) state.input_register_table[attribute_register_map.attribute1_register] = &input.attr[1].x; 567 if (num_attributes > 1) state.input_register_table[attribute_register_map.attribute1_register] = &input.attr[1].x;
553 if (num_attributes > 2) state.input_register_table[attribute_register_map.attribute2_register] = &input.attr[2].x; 568 if (num_attributes > 2) state.input_register_table[attribute_register_map.attribute2_register] = &input.attr[2].x;