summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--appveyor.yml2
-rw-r--r--src/common/common_types.h26
-rw-r--r--src/core/arm/skyeye_common/arm_regformat.h2
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.cpp20
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.h4
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpinstr.cpp75
-rw-r--r--src/core/hle/service/soc_u.cpp18
-rw-r--r--src/core/hw/gpu.cpp79
-rw-r--r--src/core/loader/ncch.cpp1
9 files changed, 115 insertions, 112 deletions
diff --git a/appveyor.yml b/appveyor.yml
index 7e9155e6d..5dc147639 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -13,7 +13,7 @@ configuration:
13 - Release 13 - Release
14 14
15install: 15install:
16 - git submodule update --init --recursive --depth 20 16 - git submodule update --init --recursive
17 17
18before_build: 18before_build:
19 - mkdir build 19 - mkdir build
diff --git a/src/common/common_types.h b/src/common/common_types.h
index ebfd7824a..fa3e0b8d6 100644
--- a/src/common/common_types.h
+++ b/src/common/common_types.h
@@ -50,32 +50,6 @@ typedef double f64; ///< 64-bit floating point
50typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space. 50typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space.
51typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space. 51typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space.
52 52
53/// Union for fast 16-bit type casting
54union t16 {
55 u8 _u8[2]; ///< 8-bit unsigned char(s)
56 u16 _u16; ///< 16-bit unsigned shorts(s)
57};
58
59/// Union for fast 32-bit type casting
60union t32 {
61 f32 _f32; ///< 32-bit floating point(s)
62 u32 _u32; ///< 32-bit unsigned int(s)
63 s32 _s32; ///< 32-bit signed int(s)
64 u16 _u16[2]; ///< 16-bit unsigned shorts(s)
65 u8 _u8[4]; ///< 8-bit unsigned char(s)
66};
67
68/// Union for fast 64-bit type casting
69union t64 {
70 f64 _f64; ///< 64-bit floating point
71 u64 _u64; ///< 64-bit unsigned long
72 f32 _f32[2]; ///< 32-bit floating point(s)
73 u32 _u32[2]; ///< 32-bit unsigned int(s)
74 s32 _s32[2]; ///< 32-bit signed int(s)
75 u16 _u16[4]; ///< 16-bit unsigned shorts(s)
76 u8 _u8[8]; ///< 8-bit unsigned char(s)
77};
78
79// An inheritable class to disallow the copy constructor and operator= functions 53// An inheritable class to disallow the copy constructor and operator= functions
80class NonCopyable { 54class NonCopyable {
81protected: 55protected:
diff --git a/src/core/arm/skyeye_common/arm_regformat.h b/src/core/arm/skyeye_common/arm_regformat.h
index a92effbb4..d1c721809 100644
--- a/src/core/arm/skyeye_common/arm_regformat.h
+++ b/src/core/arm/skyeye_common/arm_regformat.h
@@ -59,6 +59,8 @@ enum {
59 VFP_FPSID, 59 VFP_FPSID,
60 VFP_FPSCR, 60 VFP_FPSCR,
61 VFP_FPEXC, 61 VFP_FPEXC,
62 VFP_FPINST,
63 VFP_FPINST2,
62 VFP_MVFR0, 64 VFP_MVFR0,
63 VFP_MVFR1, 65 VFP_MVFR1,
64 66
diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp
index bbe11f690..1ffc1f9af 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfp.cpp
@@ -27,30 +27,20 @@
27#include "core/arm/skyeye_common/vfp/asm_vfp.h" 27#include "core/arm/skyeye_common/vfp/asm_vfp.h"
28#include "core/arm/skyeye_common/vfp/vfp.h" 28#include "core/arm/skyeye_common/vfp/vfp.h"
29 29
30unsigned VFPInit(ARMul_State* state) 30void VFPInit(ARMul_State* state)
31{ 31{
32 state->VFP[VFP_FPSID] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 | 32 state->VFP[VFP_FPSID] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 |
33 VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION; 33 VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
34 state->VFP[VFP_FPEXC] = 0; 34 state->VFP[VFP_FPEXC] = 0;
35 state->VFP[VFP_FPSCR] = 0; 35 state->VFP[VFP_FPSCR] = 0;
36 36
37 // ARM11 MPCore instruction register reset values.
38 state->VFP[VFP_FPINST] = 0xEE000A00;
39 state->VFP[VFP_FPINST2] = 0;
40
37 // ARM11 MPCore feature register values. 41 // ARM11 MPCore feature register values.
38 state->VFP[VFP_MVFR0] = 0x11111111; 42 state->VFP[VFP_MVFR0] = 0x11111111;
39 state->VFP[VFP_MVFR1] = 0; 43 state->VFP[VFP_MVFR1] = 0;
40
41 return 0;
42}
43
44void VMSR(ARMul_State* state, ARMword reg, ARMword Rt)
45{
46 if (reg == 1)
47 {
48 state->VFP[VFP_FPSCR] = state->Reg[Rt];
49 }
50 else if (reg == 8)
51 {
52 state->VFP[VFP_FPEXC] = state->Reg[Rt];
53 }
54} 44}
55 45
56void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value) 46void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value)
diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h
index acefae9bb..80ca93ccd 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.h
+++ b/src/core/arm/skyeye_common/vfp/vfp.h
@@ -26,7 +26,7 @@
26#define CHECK_VFP_ENABLED 26#define CHECK_VFP_ENABLED
27#define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]); 27#define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
28 28
29unsigned VFPInit(ARMul_State* state); 29void VFPInit(ARMul_State* state);
30 30
31s32 vfp_get_float(ARMul_State* state, u32 reg); 31s32 vfp_get_float(ARMul_State* state, u32 reg);
32void vfp_put_float(ARMul_State* state, s32 val, u32 reg); 32void vfp_put_float(ARMul_State* state, s32 val, u32 reg);
@@ -36,10 +36,8 @@ void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpsc
36u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr); 36u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
37u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr); 37u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
38 38
39void VMSR(ARMul_State* state, ARMword reg, ARMword Rt);
40void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value); 39void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value);
41void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2); 40void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2);
42void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2); 41void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2);
43void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm); 42void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm);
44void VMOVR(ARMul_State* state, ARMword single, ARMword d, ARMword imm); 43void VMOVR(ARMul_State* state, ARMword single, ARMword d, ARMword imm);
45
diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
index 67fe63aa4..8efcbab1c 100644
--- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
@@ -995,7 +995,7 @@ VMOVBRS_INST:
995#ifdef VFP_INTERPRETER_STRUCT 995#ifdef VFP_INTERPRETER_STRUCT
996struct vmsr_inst { 996struct vmsr_inst {
997 unsigned int reg; 997 unsigned int reg;
998 unsigned int Rd; 998 unsigned int Rt;
999}; 999};
1000#endif 1000#endif
1001#ifdef VFP_INTERPRETER_TRANS 1001#ifdef VFP_INTERPRETER_TRANS
@@ -1009,7 +1009,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmsr)(unsigned int inst, int index)
1009 inst_base->br = NON_BRANCH; 1009 inst_base->br = NON_BRANCH;
1010 1010
1011 inst_cream->reg = BITS(inst, 16, 19); 1011 inst_cream->reg = BITS(inst, 16, 19);
1012 inst_cream->Rd = BITS(inst, 12, 15); 1012 inst_cream->Rt = BITS(inst, 12, 15);
1013 1013
1014 return inst_base; 1014 return inst_base;
1015} 1015}
@@ -1017,15 +1017,30 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmsr)(unsigned int inst, int index)
1017#ifdef VFP_INTERPRETER_IMPL 1017#ifdef VFP_INTERPRETER_IMPL
1018VMSR_INST: 1018VMSR_INST:
1019{ 1019{
1020 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1020 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
1021 /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled , 1021 /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled ,
1022 and in privileged mode */ 1022 and in privileged mode */
1023 /* Exceptions must be checked, according to v7 ref manual */ 1023 /* Exceptions must be checked, according to v7 ref manual */
1024 CHECK_VFP_ENABLED; 1024 CHECK_VFP_ENABLED;
1025 1025
1026 vmsr_inst *inst_cream = (vmsr_inst *)inst_base->component; 1026 vmsr_inst* const inst_cream = (vmsr_inst*)inst_base->component;
1027
1028 unsigned int reg = inst_cream->reg;
1029 unsigned int rt = inst_cream->Rt;
1027 1030
1028 VMSR(cpu, inst_cream->reg, inst_cream->Rd); 1031 if (reg == 1)
1032 {
1033 cpu->VFP[VFP_FPSCR] = cpu->Reg[rt];
1034 }
1035 else if (InAPrivilegedMode(cpu))
1036 {
1037 if (reg == 8)
1038 cpu->VFP[VFP_FPEXC] = cpu->Reg[rt];
1039 else if (reg == 9)
1040 cpu->VFP[VFP_FPINST] = cpu->Reg[rt];
1041 else if (reg == 10)
1042 cpu->VFP[VFP_FPINST2] = cpu->Reg[rt];
1043 }
1029 } 1044 }
1030 cpu->Reg[15] += GET_INST_SIZE(cpu); 1045 cpu->Reg[15] += GET_INST_SIZE(cpu);
1031 INC_PC(sizeof(vmsr_inst)); 1046 INC_PC(sizeof(vmsr_inst));
@@ -1111,19 +1126,22 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmrs)(unsigned int inst, int index)
1111#ifdef VFP_INTERPRETER_IMPL 1126#ifdef VFP_INTERPRETER_IMPL
1112VMRS_INST: 1127VMRS_INST:
1113{ 1128{
1114 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1129 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
1115 /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled, 1130 /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled,
1116 and in privileged mode */ 1131 and in privileged mode */
1117 /* Exceptions must be checked, according to v7 ref manual */ 1132 /* Exceptions must be checked, according to v7 ref manual */
1118 CHECK_VFP_ENABLED; 1133 CHECK_VFP_ENABLED;
1119 1134
1120 vmrs_inst *inst_cream = (vmrs_inst *)inst_base->component; 1135 vmrs_inst* const inst_cream = (vmrs_inst*)inst_base->component;
1121 1136
1122 if (inst_cream->reg == 1) /* FPSCR */ 1137 unsigned int reg = inst_cream->reg;
1138 unsigned int rt = inst_cream->Rt;
1139
1140 if (reg == 1) // FPSCR
1123 { 1141 {
1124 if (inst_cream->Rt != 15) 1142 if (rt != 15)
1125 { 1143 {
1126 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPSCR]; 1144 cpu->Reg[rt] = cpu->VFP[VFP_FPSCR];
1127 } 1145 }
1128 else 1146 else
1129 { 1147 {
@@ -1133,25 +1151,26 @@ VMRS_INST:
1133 cpu->VFlag = (cpu->VFP[VFP_FPSCR] >> 28) & 1; 1151 cpu->VFlag = (cpu->VFP[VFP_FPSCR] >> 28) & 1;
1134 } 1152 }
1135 } 1153 }
1136 else 1154 else if (reg == 0)
1137 { 1155 {
1138 switch (inst_cream->reg) 1156 cpu->Reg[rt] = cpu->VFP[VFP_FPSID];
1139 { 1157 }
1140 case 0: 1158 else if (reg == 6)
1141 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPSID]; 1159 {
1142 break; 1160 cpu->Reg[rt] = cpu->VFP[VFP_MVFR1];
1143 case 6: 1161 }
1144 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_MVFR1]; 1162 else if (reg == 7)
1145 break; 1163 {
1146 case 7: 1164 cpu->Reg[rt] = cpu->VFP[VFP_MVFR0];
1147 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_MVFR0]; 1165 }
1148 break; 1166 else if (InAPrivilegedMode(cpu))
1149 case 8: 1167 {
1150 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPEXC]; 1168 if (reg == 8)
1151 break; 1169 cpu->Reg[rt] = cpu->VFP[VFP_FPEXC];
1152 default: 1170 else if (reg == 9)
1153 break; 1171 cpu->Reg[rt] = cpu->VFP[VFP_FPINST];
1154 } 1172 else if (reg == 10)
1173 cpu->Reg[rt] = cpu->VFP[VFP_FPINST2];
1155 } 1174 }
1156 } 1175 }
1157 cpu->Reg[15] += GET_INST_SIZE(cpu); 1176 cpu->Reg[15] += GET_INST_SIZE(cpu);
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index 5b2a643d8..d0e166fdf 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -335,6 +335,7 @@ static void Socket(Service::Interface* self) {
335 if ((s32)socket_handle == SOCKET_ERROR_VALUE) 335 if ((s32)socket_handle == SOCKET_ERROR_VALUE)
336 result = TranslateError(GET_ERRNO); 336 result = TranslateError(GET_ERRNO);
337 337
338 cmd_buffer[0] = IPC::MakeHeader(2, 2, 0);
338 cmd_buffer[1] = result; 339 cmd_buffer[1] = result;
339 cmd_buffer[2] = socket_handle; 340 cmd_buffer[2] = socket_handle;
340} 341}
@@ -358,8 +359,9 @@ static void Bind(Service::Interface* self) {
358 if (res != 0) 359 if (res != 0)
359 result = TranslateError(GET_ERRNO); 360 result = TranslateError(GET_ERRNO);
360 361
361 cmd_buffer[2] = res; 362 cmd_buffer[0] = IPC::MakeHeader(5, 2, 0);
362 cmd_buffer[1] = result; 363 cmd_buffer[1] = result;
364 cmd_buffer[2] = res;
363} 365}
364 366
365static void Fcntl(Service::Interface* self) { 367static void Fcntl(Service::Interface* self) {
@@ -441,8 +443,9 @@ static void Listen(Service::Interface* self) {
441 if (ret != 0) 443 if (ret != 0)
442 result = TranslateError(GET_ERRNO); 444 result = TranslateError(GET_ERRNO);
443 445
444 cmd_buffer[2] = ret; 446 cmd_buffer[0] = IPC::MakeHeader(3, 2, 0);
445 cmd_buffer[1] = result; 447 cmd_buffer[1] = result;
448 cmd_buffer[2] = ret;
446} 449}
447 450
448static void Accept(Service::Interface* self) { 451static void Accept(Service::Interface* self) {
@@ -467,8 +470,10 @@ static void Accept(Service::Interface* self) {
467 Memory::WriteBlock(cmd_buffer[0x104 >> 2], (const u8*)&ctr_addr, max_addr_len); 470 Memory::WriteBlock(cmd_buffer[0x104 >> 2], (const u8*)&ctr_addr, max_addr_len);
468 } 471 }
469 472
470 cmd_buffer[2] = ret; 473 cmd_buffer[0] = IPC::MakeHeader(4, 2, 2);
471 cmd_buffer[1] = result; 474 cmd_buffer[1] = result;
475 cmd_buffer[2] = ret;
476 cmd_buffer[3] = IPC::StaticBufferDesc(static_cast<u32>(max_addr_len), 0);
472} 477}
473 478
474static void GetHostId(Service::Interface* self) { 479static void GetHostId(Service::Interface* self) {
@@ -676,8 +681,10 @@ static void Connect(Service::Interface* self) {
676 int result = 0; 681 int result = 0;
677 if (ret != 0) 682 if (ret != 0)
678 result = TranslateError(GET_ERRNO); 683 result = TranslateError(GET_ERRNO);
679 cmd_buffer[2] = ret; 684
685 cmd_buffer[0] = IPC::MakeHeader(6, 2, 0);
680 cmd_buffer[1] = result; 686 cmd_buffer[1] = result;
687 cmd_buffer[2] = ret;
681} 688}
682 689
683static void InitializeSockets(Service::Interface* self) { 690static void InitializeSockets(Service::Interface* self) {
@@ -688,7 +695,8 @@ static void InitializeSockets(Service::Interface* self) {
688#endif 695#endif
689 696
690 u32* cmd_buffer = Kernel::GetCommandBuffer(); 697 u32* cmd_buffer = Kernel::GetCommandBuffer();
691 cmd_buffer[1] = 0; 698 cmd_buffer[0] = IPC::MakeHeader(1, 1, 0);
699 cmd_buffer[1] = RESULT_SUCCESS.raw;
692} 700}
693 701
694static void ShutdownSockets(Service::Interface* self) { 702static void ShutdownSockets(Service::Interface* self) {
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 901519a8b..a1789f9c7 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -56,6 +56,29 @@ inline void Read(T &var, const u32 raw_addr) {
56 var = g_regs[addr / 4]; 56 var = g_regs[addr / 4];
57} 57}
58 58
59static Math::Vec4<u8> DecodePixel(Regs::PixelFormat input_format, const u8* src_pixel) {
60 switch (input_format) {
61 case Regs::PixelFormat::RGBA8:
62 return Color::DecodeRGBA8(src_pixel);
63
64 case Regs::PixelFormat::RGB8:
65 return Color::DecodeRGB8(src_pixel);
66
67 case Regs::PixelFormat::RGB565:
68 return Color::DecodeRGB565(src_pixel);
69
70 case Regs::PixelFormat::RGB5A1:
71 return Color::DecodeRGB5A1(src_pixel);
72
73 case Regs::PixelFormat::RGBA4:
74 return Color::DecodeRGBA4(src_pixel);
75
76 default:
77 LOG_ERROR(HW_GPU, "Unknown source framebuffer format %x", input_format);
78 return {0, 0, 0, 0};
79 }
80}
81
59template <typename T> 82template <typename T>
60inline void Write(u32 addr, const T data) { 83inline void Write(u32 addr, const T data) {
61 addr -= HW::VADDR_GPU; 84 addr -= HW::VADDR_GPU;
@@ -128,11 +151,18 @@ inline void Write(u32 addr, const T data) {
128 break; 151 break;
129 } 152 }
130 153
131 unsigned horizontal_scale = (config.scaling != config.NoScale) ? 2 : 1; 154 if (config.output_tiled &&
132 unsigned vertical_scale = (config.scaling == config.ScaleXY) ? 2 : 1; 155 (config.scaling == config.ScaleXY || config.scaling == config.ScaleX)) {
156 LOG_CRITICAL(HW_GPU, "Scaling is only implemented on tiled input");
157 UNIMPLEMENTED();
158 break;
159 }
133 160
134 u32 output_width = config.output_width / horizontal_scale; 161 bool horizontal_scale = config.scaling != config.NoScale;
135 u32 output_height = config.output_height / vertical_scale; 162 bool vertical_scale = config.scaling == config.ScaleXY;
163
164 u32 output_width = config.output_width >> horizontal_scale;
165 u32 output_height = config.output_height >> vertical_scale;
136 166
137 u32 input_size = config.input_width * config.input_height * GPU::Regs::BytesPerPixel(config.input_format); 167 u32 input_size = config.input_width * config.input_height * GPU::Regs::BytesPerPixel(config.input_format);
138 u32 output_size = output_width * output_height * GPU::Regs::BytesPerPixel(config.output_format); 168 u32 output_size = output_width * output_height * GPU::Regs::BytesPerPixel(config.output_format);
@@ -156,16 +186,14 @@ inline void Write(u32 addr, const T data) {
156 break; 186 break;
157 } 187 }
158 188
159 // TODO(Subv): Implement the box filter when scaling is enabled
160 // right now we're just skipping the extra pixels.
161 for (u32 y = 0; y < output_height; ++y) { 189 for (u32 y = 0; y < output_height; ++y) {
162 for (u32 x = 0; x < output_width; ++x) { 190 for (u32 x = 0; x < output_width; ++x) {
163 Math::Vec4<u8> src_color = { 0, 0, 0, 0 }; 191 Math::Vec4<u8> src_color;
164 192
165 // Calculate the [x,y] position of the input image 193 // Calculate the [x,y] position of the input image
166 // based on the current output position and the scale 194 // based on the current output position and the scale
167 u32 input_x = x * horizontal_scale; 195 u32 input_x = x << horizontal_scale;
168 u32 input_y = y * vertical_scale; 196 u32 input_y = y << vertical_scale;
169 197
170 if (config.flip_vertically) { 198 if (config.flip_vertically) {
171 // Flip the y value of the output data, 199 // Flip the y value of the output data,
@@ -196,30 +224,15 @@ inline void Write(u32 addr, const T data) {
196 } 224 }
197 225
198 const u8* src_pixel = src_pointer + src_offset; 226 const u8* src_pixel = src_pointer + src_offset;
199 switch (config.input_format) { 227 src_color = DecodePixel(config.input_format, src_pixel);
200 case Regs::PixelFormat::RGBA8: 228 if (config.scaling == config.ScaleX) {
201 src_color = Color::DecodeRGBA8(src_pixel); 229 Math::Vec4<u8> pixel = DecodePixel(config.input_format, src_pixel + src_bytes_per_pixel);
202 break; 230 src_color = ((src_color + pixel) / 2).Cast<u8>();
203 231 } else if (config.scaling == config.ScaleXY) {
204 case Regs::PixelFormat::RGB8: 232 Math::Vec4<u8> pixel1 = DecodePixel(config.input_format, src_pixel + 1 * src_bytes_per_pixel);
205 src_color = Color::DecodeRGB8(src_pixel); 233 Math::Vec4<u8> pixel2 = DecodePixel(config.input_format, src_pixel + 2 * src_bytes_per_pixel);
206 break; 234 Math::Vec4<u8> pixel3 = DecodePixel(config.input_format, src_pixel + 3 * src_bytes_per_pixel);
207 235 src_color = (((src_color + pixel1) + (pixel2 + pixel3)) / 4).Cast<u8>();
208 case Regs::PixelFormat::RGB565:
209 src_color = Color::DecodeRGB565(src_pixel);
210 break;
211
212 case Regs::PixelFormat::RGB5A1:
213 src_color = Color::DecodeRGB5A1(src_pixel);
214 break;
215
216 case Regs::PixelFormat::RGBA4:
217 src_color = Color::DecodeRGBA4(src_pixel);
218 break;
219
220 default:
221 LOG_ERROR(HW_GPU, "Unknown source framebuffer format %x", config.input_format.Value());
222 break;
223 } 236 }
224 237
225 u8* dst_pixel = dst_pointer + dst_offset; 238 u8* dst_pixel = dst_pointer + dst_offset;
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index a8f8f78b7..2b26b31cf 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -240,7 +240,6 @@ ResultStatus AppLoader_NCCH::Load() {
240 LOG_DEBUG(Loader, "Bss size: 0x%08X", bss_size); 240 LOG_DEBUG(Loader, "Bss size: 0x%08X", bss_size);
241 LOG_DEBUG(Loader, "Core version: %d" , core_version); 241 LOG_DEBUG(Loader, "Core version: %d" , core_version);
242 LOG_DEBUG(Loader, "Thread priority: 0x%X" , priority); 242 LOG_DEBUG(Loader, "Thread priority: 0x%X" , priority);
243 LOG_DEBUG(Loader, "Resource limit descriptor: 0x%08X", exheader_header.arm11_system_local_caps.resource_limit_descriptor);
244 LOG_DEBUG(Loader, "Resource limit category: %d" , resource_limit_category); 243 LOG_DEBUG(Loader, "Resource limit category: %d" , resource_limit_category);
245 244
246 // Read ExeFS... 245 // Read ExeFS...