From 7a8176f63f497375450e03e839fa4067a74043a7 Mon Sep 17 00:00:00 2001 From: lizzie Date: Tue, 31 Mar 2026 02:53:51 +0200 Subject: [PATCH 01/54] [dynarmic] implement missing SSE3 implementations (#3301) Implementations for SSE3 CPUs (prescott) Instead of fixing some of the bugs with HostCall when paired with vectors, i'll simply remove as many host calls as I can within the most used vector instructions - then just minimize their usage to memory read/writes. Emitting the raw assembly code is faster than doing a HostCall, HostCalls are VERY expensive. So this is the desired output anyways. Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3301 Reviewed-by: crueter Reviewed-by: MaranBr Reviewed-by: Maufeat Co-authored-by: lizzie Co-committed-by: lizzie --- .../dynarmic/backend/x64/emit_x64_vector.cpp | 2337 ++++++++++------- src/dynarmic/tests/A64/a64.cpp | 99 + 2 files changed, 1447 insertions(+), 989 deletions(-) diff --git a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp index a0fd944041..6f53580997 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector.cpp @@ -38,33 +38,21 @@ template static void EmitVectorOperation(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); + auto const xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); (code.*fn)(xmm_a, xmm_b); ctx.reg_alloc.DefineValue(code, inst, xmm_a); } -template -static void EmitAVXVectorOperation(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) { - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - - const Xbyak::Xmm xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); - - (code.*fn)(xmm_a, xmm_a, xmm_b); - - ctx.reg_alloc.DefineValue(code, inst, xmm_a); -} - template static void EmitOneArgumentFallback(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Lambda lambda) { const auto fn = static_cast*>(lambda); constexpr u32 stack_space = 2 * 16; auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm arg1 = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const arg1 = ctx.reg_alloc.UseXmm(code, args[0]); + auto const result = ctx.reg_alloc.ScratchXmm(code); ctx.reg_alloc.EndOfAllocScope(); ctx.reg_alloc.HostCall(code, nullptr); @@ -86,8 +74,8 @@ static void EmitOneArgumentFallbackWithSaturation(BlockOfCode& code, EmitContext const auto fn = static_cast*>(lambda); constexpr u32 stack_space = 2 * 16; auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm arg1 = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const arg1 = ctx.reg_alloc.UseXmm(code, args[0]); + auto const result = ctx.reg_alloc.ScratchXmm(code); ctx.reg_alloc.EndOfAllocScope(); ctx.reg_alloc.HostCall(code, nullptr); @@ -111,9 +99,9 @@ static void EmitTwoArgumentFallbackWithSaturation(BlockOfCode& code, EmitContext const auto fn = static_cast*>(lambda); constexpr u32 stack_space = 3 * 16; auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm arg1 = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm arg2 = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const arg1 = ctx.reg_alloc.UseXmm(code, args[0]); + auto const arg2 = ctx.reg_alloc.UseXmm(code, args[1]); + auto const result = ctx.reg_alloc.ScratchXmm(code); ctx.reg_alloc.EndOfAllocScope(); ctx.reg_alloc.HostCall(code, nullptr); @@ -139,9 +127,9 @@ static void EmitTwoArgumentFallbackWithSaturationAndImmediate(BlockOfCode& code, const auto fn = static_cast*>(lambda); constexpr u32 stack_space = 2 * 16; auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm arg1 = ctx.reg_alloc.UseXmm(code, args[0]); + auto const arg1 = ctx.reg_alloc.UseXmm(code, args[0]); const u8 arg2 = args[1].GetImmediateU8(); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const result = ctx.reg_alloc.ScratchXmm(code); ctx.reg_alloc.EndOfAllocScope(); ctx.reg_alloc.HostCall(code, nullptr); @@ -166,9 +154,9 @@ static void EmitTwoArgumentFallback(BlockOfCode& code, EmitContext& ctx, IR::Ins const auto fn = static_cast*>(lambda); constexpr u32 stack_space = 3 * 16; auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm arg1 = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm arg2 = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const arg1 = ctx.reg_alloc.UseXmm(code, args[0]); + auto const arg2 = ctx.reg_alloc.UseXmm(code, args[1]); + auto const result = ctx.reg_alloc.ScratchXmm(code); ctx.reg_alloc.EndOfAllocScope(); ctx.reg_alloc.HostCall(code, nullptr); @@ -194,7 +182,7 @@ void EmitX64::EmitVectorGetElement8(EmitContext& ctx, IR::Inst* inst) { // TODO: DefineValue directly on Argument for index == 0 - const Xbyak::Xmm source = ctx.reg_alloc.UseXmm(code, args[0]); + auto const source = ctx.reg_alloc.UseXmm(code, args[0]); const Xbyak::Reg32 dest = ctx.reg_alloc.ScratchGpr(code).cvt32(); if (code.HasHostFeature(HostFeature::SSE41)) { @@ -218,7 +206,7 @@ void EmitX64::EmitVectorGetElement16(EmitContext& ctx, IR::Inst* inst) { // TODO: DefineValue directly on Argument for index == 0 - const Xbyak::Xmm source = ctx.reg_alloc.UseXmm(code, args[0]); + auto const source = ctx.reg_alloc.UseXmm(code, args[0]); const Xbyak::Reg32 dest = ctx.reg_alloc.ScratchGpr(code).cvt32(); code.pextrw(dest, source, index); ctx.reg_alloc.DefineValue(code, inst, dest); @@ -234,10 +222,10 @@ void EmitX64::EmitVectorGetElement32(EmitContext& ctx, IR::Inst* inst) { const Xbyak::Reg32 dest = ctx.reg_alloc.ScratchGpr(code).cvt32(); if (code.HasHostFeature(HostFeature::SSE41)) { - const Xbyak::Xmm source = ctx.reg_alloc.UseXmm(code, args[0]); + auto const source = ctx.reg_alloc.UseXmm(code, args[0]); code.pextrd(dest, source, index); } else { - const Xbyak::Xmm source = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const source = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.pshufd(source, source, index); code.movd(dest, source); } @@ -253,7 +241,7 @@ void EmitX64::EmitVectorGetElement64(EmitContext& ctx, IR::Inst* inst) { if (index == 0) { // TODO: DefineValue directly on Argument for index == 0 const Xbyak::Reg64 dest = ctx.reg_alloc.ScratchGpr(code).cvt64(); - const Xbyak::Xmm source = ctx.reg_alloc.UseXmm(code, args[0]); + auto const source = ctx.reg_alloc.UseXmm(code, args[0]); code.movq(dest, source); ctx.reg_alloc.DefineValue(code, inst, dest); return; @@ -262,10 +250,10 @@ void EmitX64::EmitVectorGetElement64(EmitContext& ctx, IR::Inst* inst) { const Xbyak::Reg64 dest = ctx.reg_alloc.ScratchGpr(code).cvt64(); if (code.HasHostFeature(HostFeature::SSE41)) { - const Xbyak::Xmm source = ctx.reg_alloc.UseXmm(code, args[0]); + auto const source = ctx.reg_alloc.UseXmm(code, args[0]); code.pextrq(dest, source, 1); } else { - const Xbyak::Xmm source = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const source = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.punpckhqdq(source, source); code.movq(dest, source); } @@ -277,7 +265,7 @@ void EmitX64::EmitVectorSetElement8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); ASSERT(args[1].IsImmediate()); const u8 index = args[1].GetImmediateU8(); - const Xbyak::Xmm source_vector = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const source_vector = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::SSE41)) { const Xbyak::Reg8 source_elem = ctx.reg_alloc.UseGpr(code, args[2]).cvt8(); @@ -310,7 +298,7 @@ void EmitX64::EmitVectorSetElement16(EmitContext& ctx, IR::Inst* inst) { ASSERT(args[1].IsImmediate()); const u8 index = args[1].GetImmediateU8(); - const Xbyak::Xmm source_vector = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const source_vector = ctx.reg_alloc.UseScratchXmm(code, args[0]); const Xbyak::Reg16 source_elem = ctx.reg_alloc.UseGpr(code, args[2]).cvt16(); code.pinsrw(source_vector, source_elem.cvt32(), index); @@ -322,7 +310,7 @@ void EmitX64::EmitVectorSetElement32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); ASSERT(args[1].IsImmediate()); const u8 index = args[1].GetImmediateU8(); - const Xbyak::Xmm source_vector = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const source_vector = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::SSE41)) { const Xbyak::Reg32 source_elem = ctx.reg_alloc.UseGpr(code, args[2]).cvt32(); @@ -345,7 +333,7 @@ void EmitX64::EmitVectorSetElement64(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); ASSERT(args[1].IsImmediate()); const u8 index = args[1].GetImmediateU8(); - const Xbyak::Xmm source_vector = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const source_vector = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::SSE41)) { const Xbyak::Reg64 source_elem = ctx.reg_alloc.UseGpr(code, args[2]); @@ -355,7 +343,7 @@ void EmitX64::EmitVectorSetElement64(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.DefineValue(code, inst, source_vector); } else { const Xbyak::Reg64 source_elem = ctx.reg_alloc.UseGpr(code, args[2]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.movq(tmp, source_elem); @@ -369,72 +357,53 @@ void EmitX64::EmitVectorSetElement64(EmitContext& ctx, IR::Inst* inst) { } } -static void VectorAbs8(BlockOfCode& code, EmitContext& ctx, const Xbyak::Xmm& data) { - if (code.HasHostFeature(HostFeature::SSSE3)) { - code.pabsb(data, data); - } else { - const Xbyak::Xmm temp = ctx.reg_alloc.ScratchXmm(code); - code.pxor(temp, temp); - code.psubb(temp, data); - code.pminub(data, temp); - } -} - -static void VectorAbs16(BlockOfCode& code, EmitContext& ctx, const Xbyak::Xmm& data) { - if (code.HasHostFeature(HostFeature::SSSE3)) { - code.pabsw(data, data); - } else { - const Xbyak::Xmm temp = ctx.reg_alloc.ScratchXmm(code); - code.pxor(temp, temp); - code.psubw(temp, data); - code.pmaxsw(data, temp); - } -} - -static void VectorAbs32(BlockOfCode& code, EmitContext& ctx, const Xbyak::Xmm& data) { - if (code.HasHostFeature(HostFeature::SSSE3)) { - code.pabsd(data, data); - } else { - const Xbyak::Xmm temp = ctx.reg_alloc.ScratchXmm(code); - code.movdqa(temp, data); - code.psrad(temp, 31); - code.pxor(data, temp); - code.psubd(data, temp); - } -} - -static void VectorAbs64(BlockOfCode& code, EmitContext& ctx, const Xbyak::Xmm& data) { - if (code.HasHostFeature(HostFeature::AVX512_Ortho)) { - code.vpabsq(data, data); - } else { - const Xbyak::Xmm temp = ctx.reg_alloc.ScratchXmm(code); - code.pshufd(temp, data, 0b11110101); - code.psrad(temp, 31); - code.pxor(data, temp); - code.psubq(data, temp); - } -} - static void EmitVectorAbs(size_t esize, EmitContext& ctx, IR::Inst* inst, BlockOfCode& code) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - - const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(code, args[0]); - + auto const data = ctx.reg_alloc.UseScratchXmm(code, args[0]); switch (esize) { case 8: - VectorAbs8(code, ctx, data); + if (code.HasHostFeature(HostFeature::SSSE3)) { + code.pabsb(data, data); + } else { + auto const temp = ctx.reg_alloc.ScratchXmm(code); + code.pxor(temp, temp); + code.psubb(temp, data); + code.pminub(data, temp); + } break; case 16: - VectorAbs16(code, ctx, data); + if (code.HasHostFeature(HostFeature::SSSE3)) { + code.pabsw(data, data); + } else { + auto const temp = ctx.reg_alloc.ScratchXmm(code); + code.pxor(temp, temp); + code.psubw(temp, data); + code.pmaxsw(data, temp); + } break; case 32: - VectorAbs32(code, ctx, data); + if (code.HasHostFeature(HostFeature::SSSE3)) { + code.pabsd(data, data); + } else { + auto const temp = ctx.reg_alloc.ScratchXmm(code); + code.movdqa(temp, data); + code.psrad(temp, 31); + code.pxor(data, temp); + code.psubd(data, temp); + } break; case 64: - VectorAbs64(code, ctx, data); + if (code.HasHostFeature(HostFeature::AVX512_Ortho)) { + code.vpabsq(data, data); + } else { + auto const temp = ctx.reg_alloc.ScratchXmm(code); + code.pshufd(temp, data, 0b11110101); + code.psrad(temp, 31); + code.pxor(data, temp); + code.psubq(data, temp); + } break; } - ctx.reg_alloc.DefineValue(code, inst, data); } @@ -477,15 +446,15 @@ void EmitX64::EmitVectorAnd(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorAndNot(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm xmm_a = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm xmm_b = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const xmm_a = ctx.reg_alloc.UseXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.UseScratchXmm(code, args[1]); code.pandn(xmm_b, xmm_a); ctx.reg_alloc.DefineValue(code, inst, xmm_b); } -static void ArithmeticShiftRightByte(EmitContext& ctx, BlockOfCode& code, const Xbyak::Xmm& result, u8 shift_amount) { +static void ArithmeticShiftRightByte(EmitContext& ctx, BlockOfCode& code, auto const& result, u8 shift_amount) { if (code.HasHostFeature(HostFeature::GFNI)) { const u64 shift_matrix = shift_amount < 8 ? (0x0102040810204080 << (shift_amount * 8)) | (0x8080808080808080 >> (64 - shift_amount * 8)) @@ -494,7 +463,7 @@ static void ArithmeticShiftRightByte(EmitContext& ctx, BlockOfCode& code, const return; } - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.punpckhbw(tmp, result); code.punpcklbw(result, result); @@ -506,7 +475,7 @@ static void ArithmeticShiftRightByte(EmitContext& ctx, BlockOfCode& code, const void EmitX64::EmitVectorArithmeticShiftRight8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); const u8 shift_amount = args[1].GetImmediateU8(); ArithmeticShiftRightByte(ctx, code, result, shift_amount); @@ -517,7 +486,7 @@ void EmitX64::EmitVectorArithmeticShiftRight8(EmitContext& ctx, IR::Inst* inst) void EmitX64::EmitVectorArithmeticShiftRight16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); const u8 shift_amount = args[1].GetImmediateU8(); code.psraw(result, shift_amount); @@ -528,7 +497,7 @@ void EmitX64::EmitVectorArithmeticShiftRight16(EmitContext& ctx, IR::Inst* inst) void EmitX64::EmitVectorArithmeticShiftRight32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); const u8 shift_amount = args[1].GetImmediateU8(); code.psrad(result, shift_amount); @@ -538,14 +507,14 @@ void EmitX64::EmitVectorArithmeticShiftRight32(EmitContext& ctx, IR::Inst* inst) void EmitX64::EmitVectorArithmeticShiftRight64(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); const u8 shift_amount = (std::min)(args[1].GetImmediateU8(), u8(63)); if (code.HasHostFeature(HostFeature::AVX512_Ortho)) { code.vpsraq(result, result, shift_amount); } else { - const Xbyak::Xmm tmp1 = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp1 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); const u64 sign_bit = 0x80000000'00000000u >> shift_amount; @@ -660,12 +629,12 @@ void EmitX64::EmitVectorArithmeticVShift64(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorBroadcastLower8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::AVX2)) { code.vpbroadcastb(a, a); code.vmovq(a, a); } else if (code.HasHostFeature(HostFeature::SSSE3)) { - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.pxor(tmp, tmp); code.pshufb(a, tmp); code.movq(a, a); @@ -678,7 +647,7 @@ void EmitX64::EmitVectorBroadcastLower8(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorBroadcastLower16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.pshuflw(a, a, 0); @@ -687,7 +656,7 @@ void EmitX64::EmitVectorBroadcastLower16(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorBroadcastLower32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.pshuflw(a, a, 0b01000100); @@ -696,11 +665,11 @@ void EmitX64::EmitVectorBroadcastLower32(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorBroadcast8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::AVX2)) { code.vpbroadcastb(a, a); } else if (code.HasHostFeature(HostFeature::SSSE3)) { - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.pxor(tmp, tmp); code.pshufb(a, tmp); } else { @@ -713,7 +682,7 @@ void EmitX64::EmitVectorBroadcast8(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorBroadcast16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::AVX2)) { code.vpbroadcastw(a, a); } else { @@ -725,7 +694,7 @@ void EmitX64::EmitVectorBroadcast16(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorBroadcast32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::AVX2)) { code.vpbroadcastd(a, a); } else { @@ -736,7 +705,7 @@ void EmitX64::EmitVectorBroadcast32(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorBroadcast64(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::AVX2)) { code.vpbroadcastq(a, a); } else { @@ -747,7 +716,7 @@ void EmitX64::EmitVectorBroadcast64(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorBroadcastElementLower8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); ASSERT(args[1].IsImmediate()); const u8 index = args[1].GetImmediateU8(); ASSERT(index < 16); @@ -758,7 +727,7 @@ void EmitX64::EmitVectorBroadcastElementLower8(EmitContext& ctx, IR::Inst* inst) code.vpbroadcastb(a, a); code.vmovq(a, a); } else if (code.HasHostFeature(HostFeature::SSSE3)) { - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.pxor(tmp, tmp); code.pshufb(a, tmp); code.movq(a, a); @@ -771,7 +740,7 @@ void EmitX64::EmitVectorBroadcastElementLower8(EmitContext& ctx, IR::Inst* inst) void EmitX64::EmitVectorBroadcastElementLower16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); ASSERT(args[1].IsImmediate()); const u8 index = args[1].GetImmediateU8(); ASSERT(index < 8); @@ -784,7 +753,7 @@ void EmitX64::EmitVectorBroadcastElementLower16(EmitContext& ctx, IR::Inst* inst void EmitX64::EmitVectorBroadcastElementLower32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); ASSERT(args[1].IsImmediate()); const u8 index = args[1].GetImmediateU8(); ASSERT(index < 4); @@ -800,7 +769,7 @@ void EmitX64::EmitVectorBroadcastElementLower32(EmitContext& ctx, IR::Inst* inst void EmitX64::EmitVectorBroadcastElement8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); ASSERT(args[1].IsImmediate()); const u8 index = args[1].GetImmediateU8(); ASSERT(index < 16); @@ -810,7 +779,7 @@ void EmitX64::EmitVectorBroadcastElement8(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::AVX2)) { code.vpbroadcastb(a, a); } else if (code.HasHostFeature(HostFeature::SSSE3)) { - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.pxor(tmp, tmp); code.pshufb(a, tmp); @@ -824,7 +793,7 @@ void EmitX64::EmitVectorBroadcastElement8(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorBroadcastElement16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); ASSERT(args[1].IsImmediate()); const u8 index = args[1].GetImmediateU8(); ASSERT(index < 8); @@ -844,7 +813,7 @@ void EmitX64::EmitVectorBroadcastElement16(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorBroadcastElement32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); ASSERT(args[1].IsImmediate()); const u8 index = args[1].GetImmediateU8(); ASSERT(index < 4); @@ -856,7 +825,7 @@ void EmitX64::EmitVectorBroadcastElement32(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorBroadcastElement64(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); ASSERT(args[1].IsImmediate()); const u8 index = args[1].GetImmediateU8(); ASSERT(index < 2); @@ -1043,9 +1012,9 @@ void EmitX64::EmitVectorCountLeadingZeros32(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorDeinterleaveEven8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm rhs = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const rhs = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.movdqa(tmp, code.Const(xword, 0x00FF00FF00FF00FF, 0x00FF00FF00FF00FF)); code.pand(lhs, tmp); @@ -1057,11 +1026,11 @@ void EmitX64::EmitVectorDeinterleaveEven8(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorDeinterleaveEven16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm rhs = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const rhs = ctx.reg_alloc.UseScratchXmm(code, args[1]); if (code.HasHostFeature(HostFeature::SSE41)) { - const Xbyak::Xmm zero = ctx.reg_alloc.ScratchXmm(code); + auto const zero = ctx.reg_alloc.ScratchXmm(code); code.pxor(zero, zero); code.pblendw(lhs, zero, 0b10101010); @@ -1082,8 +1051,8 @@ void EmitX64::EmitVectorDeinterleaveEven16(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorDeinterleaveEven32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm rhs = ctx.reg_alloc.UseXmm(code, args[1]); + auto const lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const rhs = ctx.reg_alloc.UseXmm(code, args[1]); code.shufps(lhs, rhs, 0b10001000); @@ -1092,8 +1061,8 @@ void EmitX64::EmitVectorDeinterleaveEven32(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorDeinterleaveEven64(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm rhs = ctx.reg_alloc.UseXmm(code, args[1]); + auto const lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const rhs = ctx.reg_alloc.UseXmm(code, args[1]); code.shufpd(lhs, rhs, 0b00); @@ -1102,16 +1071,16 @@ void EmitX64::EmitVectorDeinterleaveEven64(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorDeinterleaveEvenLower8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::SSSE3)) { - const Xbyak::Xmm rhs = ctx.reg_alloc.UseXmm(code, args[1]); + auto const rhs = ctx.reg_alloc.UseXmm(code, args[1]); code.punpcklbw(lhs, rhs); code.pshufb(lhs, code.Const(xword, 0x0D'09'05'01'0C'08'04'00, 0x8080808080808080)); } else { - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm rhs = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); + auto const rhs = ctx.reg_alloc.UseScratchXmm(code, args[1]); code.movdqa(tmp, code.Const(xword, 0x00FF00FF00FF00FF, 0x00FF00FF00FF00FF)); code.pand(lhs, tmp); @@ -1126,15 +1095,15 @@ void EmitX64::EmitVectorDeinterleaveEvenLower8(EmitContext& ctx, IR::Inst* inst) void EmitX64::EmitVectorDeinterleaveEvenLower16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::SSSE3)) { - const Xbyak::Xmm rhs = ctx.reg_alloc.UseXmm(code, args[1]); + auto const rhs = ctx.reg_alloc.UseXmm(code, args[1]); code.punpcklwd(lhs, rhs); code.pshufb(lhs, code.Const(xword, 0x0B0A'0302'0908'0100, 0x8080'8080'8080'8080)); } else { - const Xbyak::Xmm rhs = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const rhs = ctx.reg_alloc.UseScratchXmm(code, args[1]); code.pslld(lhs, 16); code.psrad(lhs, 16); @@ -1152,8 +1121,8 @@ void EmitX64::EmitVectorDeinterleaveEvenLower16(EmitContext& ctx, IR::Inst* inst void EmitX64::EmitVectorDeinterleaveEvenLower32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm rhs = ctx.reg_alloc.UseXmm(code, args[1]); + auto const lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const rhs = ctx.reg_alloc.UseXmm(code, args[1]); if (code.HasHostFeature(HostFeature::SSE41)) { // copy bytes 0:3 of rhs to lhs, zero out upper 8 bytes @@ -1168,8 +1137,8 @@ void EmitX64::EmitVectorDeinterleaveEvenLower32(EmitContext& ctx, IR::Inst* inst void EmitX64::EmitVectorDeinterleaveOdd8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm rhs = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const rhs = ctx.reg_alloc.UseScratchXmm(code, args[1]); code.psraw(lhs, 8); code.psraw(rhs, 8); @@ -1180,8 +1149,8 @@ void EmitX64::EmitVectorDeinterleaveOdd8(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorDeinterleaveOdd16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm rhs = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const rhs = ctx.reg_alloc.UseScratchXmm(code, args[1]); code.psrad(lhs, 16); code.psrad(rhs, 16); @@ -1192,8 +1161,8 @@ void EmitX64::EmitVectorDeinterleaveOdd16(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorDeinterleaveOdd32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm rhs = ctx.reg_alloc.UseXmm(code, args[1]); + auto const lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const rhs = ctx.reg_alloc.UseXmm(code, args[1]); code.shufps(lhs, rhs, 0b11011101); @@ -1202,8 +1171,8 @@ void EmitX64::EmitVectorDeinterleaveOdd32(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorDeinterleaveOdd64(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm rhs = ctx.reg_alloc.UseXmm(code, args[1]); + auto const lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const rhs = ctx.reg_alloc.UseXmm(code, args[1]); code.shufpd(lhs, rhs, 0b11); @@ -1212,15 +1181,15 @@ void EmitX64::EmitVectorDeinterleaveOdd64(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorDeinterleaveOddLower8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::SSSE3)) { - const Xbyak::Xmm rhs = ctx.reg_alloc.UseXmm(code, args[1]); + auto const rhs = ctx.reg_alloc.UseXmm(code, args[1]); code.punpcklbw(lhs, rhs); code.pshufb(lhs, code.Const(xword, 0x0F'0B'07'03'0E'0A'06'02, 0x8080808080808080)); } else { - const Xbyak::Xmm rhs = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const rhs = ctx.reg_alloc.UseScratchXmm(code, args[1]); code.psraw(lhs, 8); code.psraw(rhs, 8); @@ -1234,15 +1203,15 @@ void EmitX64::EmitVectorDeinterleaveOddLower8(EmitContext& ctx, IR::Inst* inst) void EmitX64::EmitVectorDeinterleaveOddLower16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::SSSE3)) { - const Xbyak::Xmm rhs = ctx.reg_alloc.UseXmm(code, args[1]); + auto const rhs = ctx.reg_alloc.UseXmm(code, args[1]); code.punpcklwd(lhs, rhs); code.pshufb(lhs, code.Const(xword, 0x0F0E'0706'0D0C'0504, 0x8080'8080'8080'8080)); } else { - const Xbyak::Xmm rhs = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const rhs = ctx.reg_alloc.UseScratchXmm(code, args[1]); code.psrad(lhs, 16); code.psrad(rhs, 16); @@ -1258,17 +1227,17 @@ void EmitX64::EmitVectorDeinterleaveOddLower32(EmitContext& ctx, IR::Inst* inst) auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::SSE41)) { - const Xbyak::Xmm lhs = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm rhs = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const lhs = ctx.reg_alloc.UseXmm(code, args[0]); + auto const rhs = ctx.reg_alloc.UseScratchXmm(code, args[1]); // copy bytes 4:7 of lhs to bytes 0:3 of rhs, zero out upper 8 bytes code.insertps(rhs, lhs, 0b01001100); ctx.reg_alloc.DefineValue(code, inst, rhs); } else { - const Xbyak::Xmm lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm rhs = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm zero = ctx.reg_alloc.ScratchXmm(code); + auto const lhs = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const rhs = ctx.reg_alloc.UseXmm(code, args[1]); + auto const zero = ctx.reg_alloc.ScratchXmm(code); code.xorps(zero, zero); code.unpcklps(lhs, rhs); @@ -1302,9 +1271,9 @@ void EmitX64::EmitVectorEqual64(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.pcmpeqd(xmm_a, xmm_b); code.pshufd(tmp, xmm_a, 0b10110001); @@ -1317,9 +1286,9 @@ void EmitX64::EmitVectorEqual128(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::SSE41)) { - const Xbyak::Xmm xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.pcmpeqq(xmm_a, xmm_b); code.pshufd(tmp, xmm_a, 0b01001110); @@ -1327,9 +1296,9 @@ void EmitX64::EmitVectorEqual128(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.DefineValue(code, inst, xmm_a); } else { - const Xbyak::Xmm xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.pcmpeqd(xmm_a, xmm_b); code.pshufd(tmp, xmm_a, 0b10110001); @@ -1353,16 +1322,16 @@ void EmitX64::EmitVectorExtract(EmitContext& ctx, IR::Inst* inst) { } if (code.HasHostFeature(HostFeature::SSSE3)) { - const Xbyak::Xmm xmm_a = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm xmm_b = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const xmm_a = ctx.reg_alloc.UseXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.UseScratchXmm(code, args[1]); code.palignr(xmm_b, xmm_a, position / 8); ctx.reg_alloc.DefineValue(code, inst, xmm_b); return; } - const Xbyak::Xmm xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm xmm_b = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.UseScratchXmm(code, args[1]); code.psrldq(xmm_a, position / 8); code.pslldq(xmm_b, (128 - position) / 8); @@ -1374,13 +1343,13 @@ void EmitX64::EmitVectorExtract(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorExtractLower(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); const u8 position = args[2].GetImmediateU8(); ASSERT(position % 8 == 0); if (position != 0) { - const Xbyak::Xmm xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); + auto const xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); code.punpcklqdq(xmm_a, xmm_b); code.psrldq(xmm_a, position / 8); @@ -1405,22 +1374,33 @@ void EmitX64::EmitVectorGreaterS32(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorGreaterS64(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSE42)) { EmitVectorOperation(code, ctx, inst, &Xbyak::CodeGenerator::pcmpgtq); - return; + } else { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp3 = ctx.reg_alloc.ScratchXmm(code); + code.movdqa(tmp2, code.Const(xword, 0x80000000, 0x80000000)); + code.pxor(tmp0, tmp2); + code.pxor(tmp1, tmp2); + code.movdqa(tmp2, tmp0); + code.pcmpeqd(tmp0, tmp1); + code.pcmpgtd(tmp2, tmp1); + code.pshufd(tmp1, tmp0, 245); + code.pshufd(tmp3, tmp2, 160); + code.pshufd(tmp0, tmp2, 245); + code.pand(tmp1, tmp3); + code.por(tmp0, tmp1); + ctx.reg_alloc.DefineValue(code, inst, tmp0); } - - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - for (size_t i = 0; i < result.size(); ++i) { - result[i] = (a[i] > b[i]) ? ~u64(0) : 0; - } - }); } static void EmitVectorHalvingAddSigned(size_t esize, EmitContext& ctx, IR::Inst* inst, BlockOfCode& code) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.movdqa(tmp, b); code.pand(tmp, a); @@ -1459,9 +1439,9 @@ void EmitX64::EmitVectorHalvingAddS32(EmitContext& ctx, IR::Inst* inst) { static void EmitVectorHalvingAddUnsigned(size_t esize, EmitContext& ctx, IR::Inst* inst, BlockOfCode& code) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.movdqa(tmp, b); @@ -1504,12 +1484,12 @@ void EmitX64::EmitVectorHalvingAddU32(EmitContext& ctx, IR::Inst* inst) { static void EmitVectorHalvingSubSigned(size_t esize, EmitContext& ctx, IR::Inst* inst, BlockOfCode& code) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseScratchXmm(code, args[1]); switch (esize) { case 8: { - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.movdqa(tmp, code.Const(xword, 0x8080808080808080, 0x8080808080808080)); code.pxor(a, tmp); code.pxor(b, tmp); @@ -1518,7 +1498,7 @@ static void EmitVectorHalvingSubSigned(size_t esize, EmitContext& ctx, IR::Inst* break; } case 16: { - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.movdqa(tmp, code.Const(xword, 0x8000800080008000, 0x8000800080008000)); code.pxor(a, tmp); code.pxor(b, tmp); @@ -1552,8 +1532,8 @@ void EmitX64::EmitVectorHalvingSubS32(EmitContext& ctx, IR::Inst* inst) { static void EmitVectorHalvingSubUnsigned(size_t esize, EmitContext& ctx, IR::Inst* inst, BlockOfCode& code) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseScratchXmm(code, args[1]); switch (esize) { case 8: @@ -1590,8 +1570,8 @@ void EmitX64::EmitVectorHalvingSubU32(EmitContext& ctx, IR::Inst* inst) { static void EmitVectorInterleaveLower(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int size) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseXmm(code, args[1]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseXmm(code, args[1]); switch (size) { case 8: @@ -1630,8 +1610,8 @@ void EmitX64::EmitVectorInterleaveLower64(EmitContext& ctx, IR::Inst* inst) { static void EmitVectorInterleaveUpper(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, int size) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseXmm(code, args[1]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseXmm(code, args[1]); switch (size) { case 8: @@ -1670,7 +1650,7 @@ void EmitX64::EmitVectorInterleaveUpper64(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorLogicalShiftLeft8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); const u8 shift_amount = args[1].GetImmediateU8(); if (shift_amount == 0) { @@ -1696,7 +1676,7 @@ void EmitX64::EmitVectorLogicalShiftLeft8(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorLogicalShiftLeft16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); const u8 shift_amount = args[1].GetImmediateU8(); code.psllw(result, shift_amount); @@ -1707,7 +1687,7 @@ void EmitX64::EmitVectorLogicalShiftLeft16(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorLogicalShiftLeft32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); const u8 shift_amount = args[1].GetImmediateU8(); code.pslld(result, shift_amount); @@ -1718,7 +1698,7 @@ void EmitX64::EmitVectorLogicalShiftLeft32(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorLogicalShiftLeft64(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); const u8 shift_amount = args[1].GetImmediateU8(); code.psllq(result, shift_amount); @@ -1729,7 +1709,7 @@ void EmitX64::EmitVectorLogicalShiftLeft64(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorLogicalShiftRight8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); const u8 shift_amount = args[1].GetImmediateU8(); if (shift_amount == 0) { @@ -1753,7 +1733,7 @@ void EmitX64::EmitVectorLogicalShiftRight8(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorLogicalShiftRight16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); const u8 shift_amount = args[1].GetImmediateU8(); code.psrlw(result, shift_amount); @@ -1764,7 +1744,7 @@ void EmitX64::EmitVectorLogicalShiftRight16(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorLogicalShiftRight32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); const u8 shift_amount = args[1].GetImmediateU8(); code.psrld(result, shift_amount); @@ -1775,7 +1755,7 @@ void EmitX64::EmitVectorLogicalShiftRight32(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorLogicalShiftRight64(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); const u8 shift_amount = args[1].GetImmediateU8(); code.psrlq(result, shift_amount); @@ -1783,41 +1763,12 @@ void EmitX64::EmitVectorLogicalShiftRight64(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.DefineValue(code, inst, result); } -template -static void EmitVectorLogicalVShiftAVX2(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { - static_assert(esize == 32 || esize == 64); - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); - - // store sign bit of lowest byte of each element of b to select left/right shift later - ICODE(vpsll)(xmm0, b, u8(esize - 8)); - - // sse/avx shifts are only positive, with dedicated left/right forms - shift by lowest byte of abs(b) - code.vpabsb(b, b); - code.vpand(b, b, code.BConst(xword, 0xFF)); - - // calculate shifts - ICODE(vpsllv)(result, a, b); - ICODE(vpsrlv)(a, a, b); - - // implicit argument: xmm0 (sign of lowest byte of b) - if (esize == 32) { - code.blendvps(result, a); - } else { - code.blendvpd(result, a); - } - ctx.reg_alloc.DefineValue(code, inst, result); -} - void EmitX64::EmitVectorLogicalVShift8(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::AVX512_Ortho | HostFeature::AVX512BW | HostFeature::GFNI)) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm left_shift = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const left_shift = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); const Xbyak::Opmask negative_mask = k1; code.pxor(tmp, tmp); @@ -1862,10 +1813,10 @@ void EmitX64::EmitVectorLogicalVShift16(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::AVX512_Ortho | HostFeature::AVX512BW)) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm left_shift = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm right_shift = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const left_shift = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const right_shift = ctx.reg_alloc.ScratchXmm(code); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.vmovdqa32(tmp, code.Const(xword, 0x00FF00FF00FF00FF, 0x00FF00FF00FF00FF)); code.vpxord(right_shift, right_shift, right_shift); @@ -1886,18 +1837,87 @@ void EmitX64::EmitVectorLogicalVShift16(EmitContext& ctx, IR::Inst* inst) { } void EmitX64::EmitVectorLogicalVShift32(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::AVX2)) { - EmitVectorLogicalVShiftAVX2<32>(code, ctx, inst); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const result = ctx.reg_alloc.ScratchXmm(code); + auto const mask = ctx.reg_alloc.ScratchXmm(code); + // store sign bit of lowest byte of each element of b to select left/right shift later + code.vpslld(mask, b, u8(32 - 8)); + // sse/avx shifts are only positive, with dedicated left/right forms - shift by lowest byte of abs(b) + code.vpabsb(b, b); + code.vpand(b, b, code.BConst<32>(xword, 0xFF)); + // calculate shifts + code.vpsllvd(result, a, b); + code.vpsrlvd(a, a, b); + code.vblendvps(result, result, a, mask); + ctx.reg_alloc.DefineValue(code, inst, result); } else { - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - std::transform(a.begin(), a.end(), b.begin(), result.begin(), VShift); - }); + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp3 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp4 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp5 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp6 = ctx.reg_alloc.ScratchXmm(code); + code.pxor(tmp3, tmp3); + code.movdqa(tmp2, tmp0); + code.psubb(tmp3, tmp1); + code.movdqa(tmp4, tmp2); + code.movdqa(tmp6, tmp2); + code.pminub(tmp3, tmp1); + code.pslld(tmp1, 24); + code.pand(tmp3, code.Const(xword, 0x000000ff'000000ff, 0x000000ff'000000ff)); + code.psrad(tmp1, 31); + code.pshuflw(tmp0, tmp3, 254); + code.pshuflw(tmp5, tmp3, 84); + code.psrld(tmp4, tmp0); + code.movdqa(tmp0, tmp2); + code.psrld(tmp0, tmp5); + code.punpcklqdq(tmp0, tmp4); + code.pshufd(tmp4, tmp3, 238); + code.pslld(tmp3, 23); + code.paddd(tmp3, code.Const(xword, 0x3F80'00003F80'0000, 0x3F80'00003F80'0000)); + code.pshuflw(tmp5, tmp4, 254); + code.pshuflw(tmp4, tmp4, 84); + code.psrld(tmp6, tmp5); + code.movdqa(tmp5, tmp2); + code.psrld(tmp5, tmp4); + code.pshufd(tmp4, tmp2, 245); + code.punpckhqdq(tmp5, tmp6); + code.cvttps2dq(tmp3, tmp3); + code.shufps(tmp0, tmp5, 204); + code.pmuludq(tmp2, tmp3); + code.pshufd(tmp3, tmp3, 245); + code.andps(tmp0, tmp1); + code.pmuludq(tmp3, tmp4); + code.pshufd(tmp2, tmp2, 232); + code.pshufd(tmp3, tmp3, 232); + code.punpckldq(tmp2, tmp3); + code.pandn(tmp1, tmp2); + code.orps(tmp0, tmp1); + ctx.reg_alloc.DefineValue(code, inst, tmp0); } } void EmitX64::EmitVectorLogicalVShift64(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::AVX2)) { - EmitVectorLogicalVShiftAVX2<64>(code, ctx, inst); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const result = ctx.reg_alloc.ScratchXmm(code); + auto const mask = ctx.reg_alloc.ScratchXmm(code); + // store sign bit of lowest byte of each element of b to select left/right shift later + code.vpsllq(mask, b, u8(64 - 8)); + // sse/avx shifts are only positive, with dedicated left/right forms - shift by lowest byte of abs(b) + code.vpabsb(b, b); + code.vpand(b, b, code.BConst<64>(xword, 0xFF)); + // calculate shifts + code.vpsllvq(result, a, b); + code.vpsrlvq(a, a, b); + code.vblendvpd(result, result, a, mask); + ctx.reg_alloc.DefineValue(code, inst, result); } else { EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { std::transform(a.begin(), a.end(), b.begin(), result.begin(), VShift); @@ -1912,28 +1932,11 @@ enum class MinMaxOperation { Max, }; -// Compute the minimum/maximum of two vectors of signed 8-bit integers, using only SSE2 instructons. -// The result of the operation is placed in operand a, while b is unmodified. -void FallbackMinMaxS8(BlockOfCode& code, EmitContext& ctx, const Xbyak::Xmm& a, const Xbyak::Xmm& b, MinMaxOperation op) { - const Xbyak::Xmm c = ctx.reg_alloc.ScratchXmm(code); - if(op == MinMaxOperation::Min) { - code.movdqa(c, b); - code.pcmpgtb(c, a); - } else { - code.movdqa(c, a); - code.pcmpgtb(c, b); - } - - code.pand(a, c); - code.pandn(c, b); - code.por(a, c); -} - // Compute the minimum/maximum of two vectors of unsigned 16-bit integers, using only SSE2 instructons. // The result of the operation is placed in operand a, while b is unmodified. -void FallbackMinMaxU16(BlockOfCode& code, EmitContext& ctx, const Xbyak::Xmm& a, const Xbyak::Xmm& b, MinMaxOperation op) { +void FallbackMinMaxU16(BlockOfCode& code, EmitContext& ctx, auto const& a, auto const& b, MinMaxOperation op) { if(op == MinMaxOperation::Min) { - const Xbyak::Xmm c = ctx.reg_alloc.ScratchXmm(code); + auto const c = ctx.reg_alloc.ScratchXmm(code); code.movdqa(c, a); code.psubusw(c, b); code.psubw(a, c); @@ -1945,8 +1948,8 @@ void FallbackMinMaxU16(BlockOfCode& code, EmitContext& ctx, const Xbyak::Xmm& a, // Compute the minimum/maximum of two vectors of signed 32-bit integers, using only SSE2 instructons. // The result of the operation is placed in operand a, while b is unmodified. -void FallbackMinMaxS32(BlockOfCode& code, EmitContext& ctx, const Xbyak::Xmm& a, const Xbyak::Xmm& b, MinMaxOperation op) { - const Xbyak::Xmm c = ctx.reg_alloc.ScratchXmm(code); +void FallbackMinMaxS32(BlockOfCode& code, EmitContext& ctx, auto const& a, auto const& b, MinMaxOperation op) { + auto const c = ctx.reg_alloc.ScratchXmm(code); if(op == MinMaxOperation::Min) { code.movdqa(c, b); code.pcmpgtd(c, a); @@ -1962,12 +1965,12 @@ void FallbackMinMaxS32(BlockOfCode& code, EmitContext& ctx, const Xbyak::Xmm& a, // Compute the minimum/maximum of two vectors of unsigned 32-bit integers, using only SSE2 instructons. // The result of the operation is placed in operand a, while b is unmodified. -void FallbackMinMaxU32(BlockOfCode& code, EmitContext& ctx, const Xbyak::Xmm& a, const Xbyak::Xmm& b, MinMaxOperation op) { - const Xbyak::Xmm c = ctx.reg_alloc.ScratchXmm(code); +void FallbackMinMaxU32(BlockOfCode& code, EmitContext& ctx, auto const& a, auto const& b, MinMaxOperation op) { + auto const c = ctx.reg_alloc.ScratchXmm(code); code.movdqa(c, code.BConst<32>(xword, 0x80000000)); // bias a and b by XORing their sign bits, then use the signed comparison function - const Xbyak::Xmm d = ctx.reg_alloc.ScratchXmm(code); + auto const d = ctx.reg_alloc.ScratchXmm(code); if(op == MinMaxOperation::Min) { code.movdqa(d, a); code.pxor(d, c); @@ -1989,11 +1992,16 @@ void EmitX64::EmitVectorMaxS8(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSE41)) { EmitVectorOperation(code, ctx, inst, &Xbyak::CodeGenerator::pmaxsb); } else { - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseXmm(code, args[1]); - FallbackMinMaxS8(code, ctx, a, b, MinMaxOperation::Max); - ctx.reg_alloc.DefineValue(code, inst, a); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseXmm(code, args[1]); + auto const c = ctx.reg_alloc.ScratchXmm(code); + code.movdqa(c, a); + code.pcmpgtb(c, b); + code.pand(a, c); + code.pandn(c, b); + code.por(a, c); + ctx.reg_alloc.DefineValue(code, inst, a); } } @@ -2005,31 +2013,55 @@ void EmitX64::EmitVectorMaxS32(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSE41)) { EmitVectorOperation(code, ctx, inst, &Xbyak::CodeGenerator::pmaxsd); } else { - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseXmm(code, args[1]); - FallbackMinMaxS32(code, ctx, a, b, MinMaxOperation::Max); - ctx.reg_alloc.DefineValue(code, inst, a); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + code.movdqa(tmp2, tmp0); + code.pcmpgtd(tmp2, tmp1); + code.pand(tmp0, tmp2); + code.pandn(tmp2, tmp1); + code.por(tmp0, tmp2); + ctx.reg_alloc.DefineValue(code, inst, tmp0); } } void EmitX64::EmitVectorMaxS64(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::AVX512_Ortho)) { - EmitAVXVectorOperation(code, ctx, inst, &Xbyak::CodeGenerator::vpmaxsq); + auto const xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); + code.vpmaxsq(xmm_a, xmm_a, xmm_b); + ctx.reg_alloc.DefineValue(code, inst, xmm_a); } else if (code.HasHostFeature(HostFeature::AVX)) { - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseXmm(code, args[1]); - + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseXmm(code, args[1]); code.vpcmpgtq(xmm0, y, x); code.pblendvb(x, y); - ctx.reg_alloc.DefineValue(code, inst, x); } else { - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - std::transform(a.begin(), a.end(), b.begin(), result.begin(), [](auto x, auto y) { return (std::max)(x, y); }); - }); + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp3 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp4 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp5 = ctx.reg_alloc.ScratchXmm(code); + code.movdqa(tmp2, code.Const(xword, 0x8000'0000, 0x8000'0000)); + code.movdqa(tmp3, tmp1); + code.pxor(tmp3, tmp2); + code.pxor(tmp2, tmp0); + code.movdqa(tmp4, tmp2); + code.pcmpeqd(tmp2, tmp3); + code.pcmpgtd(tmp4, tmp3); + code.pshufd(tmp2, tmp2, 245); + code.pshufd(tmp5, tmp4, 160); + code.pshufd(tmp3, tmp4, 245); + code.pand(tmp2, tmp5); + code.por(tmp3, tmp2); + code.pand(tmp0, tmp3); + code.pandn(tmp3, tmp1); + code.por(tmp0, tmp3); + ctx.reg_alloc.DefineValue(code, inst, tmp0); } } @@ -2041,11 +2073,11 @@ void EmitX64::EmitVectorMaxU16(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSE41)) { EmitVectorOperation(code, ctx, inst, &Xbyak::CodeGenerator::pmaxuw); } else { - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseXmm(code, args[1]); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseXmm(code, args[1]); FallbackMinMaxU16(code, ctx, a, b, MinMaxOperation::Max); - ctx.reg_alloc.DefineValue(code, inst, a); + ctx.reg_alloc.DefineValue(code, inst, a); } } @@ -2053,35 +2085,54 @@ void EmitX64::EmitVectorMaxU32(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSE41)) { EmitVectorOperation(code, ctx, inst, &Xbyak::CodeGenerator::pmaxud); } else { - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseXmm(code, args[1]); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseXmm(code, args[1]); FallbackMinMaxU32(code, ctx, a, b, MinMaxOperation::Max); - ctx.reg_alloc.DefineValue(code, inst, a); + ctx.reg_alloc.DefineValue(code, inst, a); } } void EmitX64::EmitVectorMaxU64(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::AVX512_Ortho)) { - EmitAVXVectorOperation(code, ctx, inst, &Xbyak::CodeGenerator::vpmaxuq); + auto const xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); + code.vpmaxuq(xmm_a, xmm_a, xmm_b); + ctx.reg_alloc.DefineValue(code, inst, xmm_a); } else if (code.HasHostFeature(HostFeature::AVX)) { - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); - + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.vmovdqa(xmm0, code.Const(xword, 0x8000000000000000, 0x8000000000000000)); code.vpsubq(tmp, y, xmm0); code.vpsubq(xmm0, x, xmm0); code.vpcmpgtq(xmm0, tmp, xmm0); code.pblendvb(x, y); - ctx.reg_alloc.DefineValue(code, inst, x); } else { - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - std::transform(a.begin(), a.end(), b.begin(), result.begin(), [](auto x, auto y) { return (std::max)(x, y); }); - }); + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp3 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp4 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp5 = ctx.reg_alloc.ScratchXmm(code); + code.movdqa(tmp2, code.Const(xword, 0x8000000080000000, 0x8000000080000000)); + code.movdqa(tmp3, tmp1); + code.pxor(tmp3, tmp2); + code.pxor(tmp2, tmp0); + code.movdqa(tmp4, tmp2); + code.pcmpeqd(tmp2, tmp3); + code.pcmpgtd(tmp4, tmp3); + code.pshufd(tmp2, tmp2, 245); + code.pshufd(tmp5, tmp4, 160); + code.pshufd(tmp3, tmp4, 245); + code.pand(tmp2, tmp5); + code.por(tmp3, tmp2); + code.pand(tmp0, tmp3); + code.pandn(tmp3, tmp1); + code.por(tmp0, tmp3); + ctx.reg_alloc.DefineValue(code, inst, tmp0); } } @@ -2089,11 +2140,16 @@ void EmitX64::EmitVectorMinS8(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSE41)) { EmitVectorOperation(code, ctx, inst, &Xbyak::CodeGenerator::pminsb); } else { - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseXmm(code, args[1]); - FallbackMinMaxS8(code, ctx, a, b, MinMaxOperation::Min); - ctx.reg_alloc.DefineValue(code, inst, a); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseXmm(code, args[1]); + auto const c = ctx.reg_alloc.ScratchXmm(code); + code.movdqa(c, b); + code.pcmpgtb(c, a); + code.pand(a, c); + code.pandn(c, b); + code.por(a, c); + ctx.reg_alloc.DefineValue(code, inst, a); } } @@ -2105,31 +2161,51 @@ void EmitX64::EmitVectorMinS32(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSE41)) { EmitVectorOperation(code, ctx, inst, &Xbyak::CodeGenerator::pminsd); } else { - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseXmm(code, args[1]); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseXmm(code, args[1]); FallbackMinMaxS32(code, ctx, a, b, MinMaxOperation::Min); - ctx.reg_alloc.DefineValue(code, inst, a); + ctx.reg_alloc.DefineValue(code, inst, a); } } void EmitX64::EmitVectorMinS64(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::AVX512_Ortho)) { - EmitAVXVectorOperation(code, ctx, inst, &Xbyak::CodeGenerator::vpminsq); + auto const xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); + code.vpminsq(xmm_a, xmm_a, xmm_b); + ctx.reg_alloc.DefineValue(code, inst, xmm_a); } else if (code.HasHostFeature(HostFeature::AVX)) { - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - - const Xbyak::Xmm x = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(code, args[1]); - + auto const x = ctx.reg_alloc.UseXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); code.vpcmpgtq(xmm0, y, x); code.pblendvb(y, x); - ctx.reg_alloc.DefineValue(code, inst, y); } else { - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - std::transform(a.begin(), a.end(), b.begin(), result.begin(), [](auto x, auto y) { return (std::min)(x, y); }); - }); + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp3 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp4 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp5 = ctx.reg_alloc.ScratchXmm(code); + code.movdqa(tmp2, code.Const(xword, 0x8000'0000, 0x8000'0000)); + code.movdqa(tmp3, tmp1); + code.pxor(tmp3, tmp2); + code.pxor(tmp2, tmp0); + code.movdqa(tmp4, tmp2); + code.pcmpeqd(tmp2, tmp3); + code.pcmpgtd(tmp4, tmp3); + code.pshufd(tmp3, tmp2, 245); + code.pshufd(tmp5, tmp4, 160); + code.pshufd(tmp2, tmp4, 245); + code.pand(tmp3, tmp5); + code.por(tmp2, tmp3); + code.pand(tmp1, tmp2); + code.pandn(tmp2, tmp0); + code.por(tmp2, tmp1); + //code.movdqa(tmp0, tmp2); + ctx.reg_alloc.DefineValue(code, inst, tmp2); } } @@ -2141,11 +2217,11 @@ void EmitX64::EmitVectorMinU16(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSE41)) { EmitVectorOperation(code, ctx, inst, &Xbyak::CodeGenerator::pminuw); } else { - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseXmm(code, args[1]); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseXmm(code, args[1]); FallbackMinMaxU16(code, ctx, a, b, MinMaxOperation::Min); - ctx.reg_alloc.DefineValue(code, inst, a); + ctx.reg_alloc.DefineValue(code, inst, a); } } @@ -2153,57 +2229,93 @@ void EmitX64::EmitVectorMinU32(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSE41)) { EmitVectorOperation(code, ctx, inst, &Xbyak::CodeGenerator::pminud); } else { - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseXmm(code, args[1]); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseXmm(code, args[1]); FallbackMinMaxU32(code, ctx, a, b, MinMaxOperation::Min); - ctx.reg_alloc.DefineValue(code, inst, a); + ctx.reg_alloc.DefineValue(code, inst, a); } } void EmitX64::EmitVectorMinU64(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::AVX512_Ortho)) { - EmitAVXVectorOperation(code, ctx, inst, &Xbyak::CodeGenerator::vpminuq); + auto const xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); + code.vpminuq(xmm_a, xmm_a, xmm_b); + ctx.reg_alloc.DefineValue(code, inst, xmm_a); } else if (code.HasHostFeature(HostFeature::AVX)) { - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - - const Xbyak::Xmm x = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); - + auto const x = ctx.reg_alloc.UseXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.vmovdqa(xmm0, code.Const(xword, 0x8000000000000000, 0x8000000000000000)); code.vpsubq(tmp, y, xmm0); code.vpsubq(xmm0, x, xmm0); code.vpcmpgtq(xmm0, tmp, xmm0); code.pblendvb(y, x); - ctx.reg_alloc.DefineValue(code, inst, y); } else { - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - std::transform(a.begin(), a.end(), b.begin(), result.begin(), [](auto x, auto y) { return (std::min)(x, y); }); - }); + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp3 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp4 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp5 = ctx.reg_alloc.ScratchXmm(code); + code.movdqa(tmp2, code.Const(xword, 0x8000000080000000, 0x8000000080000000)); + code.movdqa(tmp3, tmp1); + code.pxor(tmp3, tmp2); + code.pxor(tmp2, tmp0); + code.movdqa(tmp4, tmp2); + code.pcmpeqd(tmp2, tmp3); + code.pcmpgtd(tmp4, tmp3); + code.pshufd(tmp3, tmp2, 245); + code.pshufd(tmp5, tmp4, 160); + code.pshufd(tmp2, tmp4, 245); + code.pand(tmp3, tmp5); + code.por(tmp2, tmp3); + code.pand(tmp1, tmp2); + code.pandn(tmp2, tmp0); + code.por(tmp2, tmp1); + //code.movdqa(tmp0, tmp2); + ctx.reg_alloc.DefineValue(code, inst, tmp2); } } void EmitX64::EmitVectorMultiply8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm tmp_a = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm tmp_b = ctx.reg_alloc.ScratchXmm(code); - - // TODO: Optimize - code.movdqa(tmp_a, a); - code.movdqa(tmp_b, b); - code.pmullw(a, b); - code.psrlw(tmp_a, 8); - code.psrlw(tmp_b, 8); - code.pmullw(tmp_a, tmp_b); - code.pand(a, code.Const(xword, 0x00FF00FF00FF00FF, 0x00FF00FF00FF00FF)); - code.psllw(tmp_a, 8); - code.por(a, tmp_a); - - ctx.reg_alloc.DefineValue(code, inst, a); + if (code.HasHostFeature(HostFeature::AVX)) { + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp3 = ctx.reg_alloc.ScratchXmm(code); + code.vbroadcastss(tmp3, code.Const(dword, 0x00ff'00ff)); + code.vpmullw(tmp2, tmp1, tmp0); + code.vpandn(tmp0, tmp3, tmp0); + code.vpand(tmp2, tmp2, tmp3); + code.vpmaddubsw(tmp0, tmp1, tmp0); + code.vpsllw(tmp0, tmp0, 8); + code.vpor(tmp0, tmp2, tmp0); + ctx.reg_alloc.DefineValue(code, inst, tmp0); + } else { + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp3 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp4 = ctx.reg_alloc.ScratchXmm(code); + code.movdqa(tmp2, tmp0); + code.movdqa(tmp3, tmp1); + code.movdqa(tmp4, code.Const(xword, 0x00FF00FF00FF00FF, 0x00FF00FF00FF00FF)); + code.punpckhbw(tmp2, tmp2); + code.punpckhbw(tmp3, tmp3); + code.punpcklbw(tmp0, tmp0); + code.punpcklbw(tmp1, tmp1); + code.pmullw(tmp3, tmp2); + code.pmullw(tmp0, tmp1); + code.pand(tmp3, tmp4); + code.pand(tmp0, tmp4); + code.packuswb(tmp0, tmp3); + ctx.reg_alloc.DefineValue(code, inst, tmp0); + } } void EmitX64::EmitVectorMultiply16(EmitContext& ctx, IR::Inst* inst) { @@ -2214,31 +2326,32 @@ void EmitX64::EmitVectorMultiply32(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSE41)) { EmitVectorOperation(code, ctx, inst, &Xbyak::CodeGenerator::pmulld); } else { - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); - - code.movdqa(tmp, a); - code.psrlq(a, 32); - code.pmuludq(tmp, b); - code.psrlq(b, 32); - code.pmuludq(a, b); - code.pshufd(tmp, tmp, 0b00001000); - code.pshufd(b, a, 0b00001000); - code.punpckldq(tmp, b); - - ctx.reg_alloc.DefineValue(code, inst, tmp); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); + code.movdqa(tmp, a); + code.psrlq(a, 32); + code.pmuludq(tmp, b); + code.psrlq(b, 32); + code.pmuludq(a, b); + code.pshufd(tmp, tmp, 0b00001000); + code.pshufd(b, a, 0b00001000); + code.punpckldq(tmp, b); + ctx.reg_alloc.DefineValue(code, inst, tmp); } } void EmitX64::EmitVectorMultiply64(EmitContext& ctx, IR::Inst* inst) { - if (code.HasHostFeature(HostFeature::AVX512_Ortho | HostFeature::AVX512DQ)) { - EmitAVXVectorOperation(code, ctx, inst, &Xbyak::CodeGenerator::vpmullq); - } else if (code.HasHostFeature(HostFeature::SSE41)) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseXmm(code, args[1]); + if (code.HasHostFeature(HostFeature::AVX512_Ortho | HostFeature::AVX512DQ)) { + auto const xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); + code.vpmullq(xmm_a, xmm_a, xmm_b); + ctx.reg_alloc.DefineValue(code, inst, xmm_a); + } else if (code.HasHostFeature(HostFeature::SSE41)) { + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseXmm(code, args[1]); const Xbyak::Reg64 tmp1 = ctx.reg_alloc.ScratchGpr(code); const Xbyak::Reg64 tmp2 = ctx.reg_alloc.ScratchGpr(code); @@ -2253,29 +2366,28 @@ void EmitX64::EmitVectorMultiply64(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.DefineValue(code, inst, a); } else { - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm tmp1 = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm tmp2 = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm tmp3 = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp1 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp3 = ctx.reg_alloc.ScratchXmm(code); - code.movdqa(tmp1, a); - code.movdqa(tmp2, a); - code.movdqa(tmp3, b); + code.movdqa(tmp1, a); + code.movdqa(tmp2, a); + code.movdqa(tmp3, b); - code.psrlq(tmp1, 32); - code.psrlq(tmp3, 32); + code.psrlq(tmp1, 32); + code.psrlq(tmp3, 32); - code.pmuludq(tmp2, b); - code.pmuludq(tmp3, a); - code.pmuludq(b, tmp1); + code.pmuludq(tmp2, b); + code.pmuludq(tmp3, a); + code.pmuludq(b, tmp1); - code.paddq(b, tmp3); - code.psllq(b, 32); - code.paddq(tmp2, b); + code.paddq(b, tmp3); + code.psllq(b, 32); + code.paddq(tmp2, b); - ctx.reg_alloc.DefineValue(code, inst, tmp2); + ctx.reg_alloc.DefineValue(code, inst, tmp2); } } @@ -2307,15 +2419,15 @@ void EmitX64::EmitVectorNarrow16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::AVX512_Ortho | HostFeature::AVX512BW)) { - const Xbyak::Xmm a = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseXmm(code, args[0]); + auto const result = ctx.reg_alloc.ScratchXmm(code); code.vpmovwb(result, a); ctx.reg_alloc.DefineValue(code, inst, result); } else { - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm zeros = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const zeros = ctx.reg_alloc.ScratchXmm(code); code.pxor(zeros, zeros); code.pand(a, code.Const(xword, 0x00FF00FF00FF00FF, 0x00FF00FF00FF00FF)); @@ -2328,13 +2440,13 @@ void EmitX64::EmitVectorNarrow16(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorNarrow32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::AVX512_Ortho)) { - const Xbyak::Xmm a = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseXmm(code, args[0]); + auto const result = ctx.reg_alloc.ScratchXmm(code); code.vpmovdw(result, a); ctx.reg_alloc.DefineValue(code, inst, result); } else { - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm zeros = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const zeros = ctx.reg_alloc.ScratchXmm(code); code.pxor(zeros, zeros); if (code.HasHostFeature(HostFeature::SSE41)) { code.pblendw(a, zeros, 0b10101010); @@ -2352,15 +2464,15 @@ void EmitX64::EmitVectorNarrow64(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::AVX512_Ortho)) { - const Xbyak::Xmm a = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseXmm(code, args[0]); + auto const result = ctx.reg_alloc.ScratchXmm(code); code.vpmovqd(result, a); ctx.reg_alloc.DefineValue(code, inst, result); } else { - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm zeros = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const zeros = ctx.reg_alloc.ScratchXmm(code); code.pxor(zeros, zeros); code.shufps(a, zeros, 0b00001000); @@ -2373,13 +2485,13 @@ void EmitX64::EmitVectorNot(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::AVX512_Ortho)) { - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm operand = ctx.reg_alloc.UseXmm(code, args[0]); + auto const result = ctx.reg_alloc.ScratchXmm(code); + auto const operand = ctx.reg_alloc.UseXmm(code, args[0]); code.vpternlogq(result, operand, operand, u8(~Tern::c)); ctx.reg_alloc.DefineValue(code, inst, result); } else { - const Xbyak::Xmm xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm xmm_b = ctx.reg_alloc.ScratchXmm(code); + auto const xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.ScratchXmm(code); code.pcmpeqw(xmm_b, xmm_b); code.pxor(xmm_a, xmm_b); ctx.reg_alloc.DefineValue(code, inst, xmm_a); @@ -2393,9 +2505,9 @@ void EmitX64::EmitVectorOr(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorPairedAddLower8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.punpcklqdq(xmm_a, xmm_b); code.movdqa(tmp, xmm_a); @@ -2411,9 +2523,9 @@ void EmitX64::EmitVectorPairedAddLower8(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorPairedAddLower16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.punpcklqdq(xmm_a, xmm_b); if (code.HasHostFeature(HostFeature::SSSE3)) { @@ -2434,9 +2546,9 @@ void EmitX64::EmitVectorPairedAddLower16(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorPairedAddLower32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.punpcklqdq(xmm_a, xmm_b); if (code.HasHostFeature(HostFeature::SSSE3)) { @@ -2456,10 +2568,10 @@ void EmitX64::EmitVectorPairedAddLower32(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorPairedAdd8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm c = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm d = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const c = ctx.reg_alloc.ScratchXmm(code); + auto const d = ctx.reg_alloc.ScratchXmm(code); code.movdqa(c, a); code.movdqa(d, b); @@ -2478,17 +2590,17 @@ void EmitX64::EmitVectorPairedAdd16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::SSSE3)) { - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseXmm(code, args[1]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseXmm(code, args[1]); code.phaddw(a, b); ctx.reg_alloc.DefineValue(code, inst, a); } else { - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm c = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm d = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const c = ctx.reg_alloc.ScratchXmm(code); + auto const d = ctx.reg_alloc.ScratchXmm(code); code.movdqa(c, a); code.movdqa(d, b); @@ -2508,17 +2620,17 @@ void EmitX64::EmitVectorPairedAdd32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::SSSE3)) { - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseXmm(code, args[1]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseXmm(code, args[1]); code.phaddd(a, b); ctx.reg_alloc.DefineValue(code, inst, a); } else { - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm c = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm d = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const c = ctx.reg_alloc.ScratchXmm(code); + auto const d = ctx.reg_alloc.ScratchXmm(code); code.movdqa(c, a); code.movdqa(d, b); @@ -2535,9 +2647,9 @@ void EmitX64::EmitVectorPairedAdd32(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorPairedAdd64(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm c = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseXmm(code, args[1]); + auto const c = ctx.reg_alloc.ScratchXmm(code); code.movdqa(c, a); code.punpcklqdq(a, b); @@ -2550,8 +2662,8 @@ void EmitX64::EmitVectorPairedAdd64(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorPairedAddSignedWiden8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm c = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const c = ctx.reg_alloc.ScratchXmm(code); code.movdqa(c, a); code.psllw(a, 8); @@ -2565,8 +2677,8 @@ void EmitX64::EmitVectorPairedAddSignedWiden8(EmitContext& ctx, IR::Inst* inst) void EmitX64::EmitVectorPairedAddSignedWiden16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm c = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const c = ctx.reg_alloc.ScratchXmm(code); code.movdqa(c, a); code.pslld(a, 16); @@ -2580,18 +2692,18 @@ void EmitX64::EmitVectorPairedAddSignedWiden16(EmitContext& ctx, IR::Inst* inst) void EmitX64::EmitVectorPairedAddSignedWiden32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::AVX512_Ortho)) { - const Xbyak::Xmm c = ctx.reg_alloc.ScratchXmm(code); + auto const c = ctx.reg_alloc.ScratchXmm(code); code.vpsraq(c, a, 32); code.vpsllq(a, a, 32); code.vpsraq(a, a, 32); code.vpaddq(a, a, c); } else { - const Xbyak::Xmm tmp1 = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm tmp2 = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm c = ctx.reg_alloc.ScratchXmm(code); + auto const tmp1 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const c = ctx.reg_alloc.ScratchXmm(code); code.movdqa(c, a); code.psllq(a, 32); @@ -2613,8 +2725,8 @@ void EmitX64::EmitVectorPairedAddSignedWiden32(EmitContext& ctx, IR::Inst* inst) void EmitX64::EmitVectorPairedAddUnsignedWiden8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm c = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const c = ctx.reg_alloc.ScratchXmm(code); code.movdqa(c, a); code.psllw(a, 8); @@ -2628,8 +2740,8 @@ void EmitX64::EmitVectorPairedAddUnsignedWiden8(EmitContext& ctx, IR::Inst* inst void EmitX64::EmitVectorPairedAddUnsignedWiden16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm c = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const c = ctx.reg_alloc.ScratchXmm(code); code.movdqa(c, a); code.pslld(a, 16); @@ -2643,8 +2755,8 @@ void EmitX64::EmitVectorPairedAddUnsignedWiden16(EmitContext& ctx, IR::Inst* ins void EmitX64::EmitVectorPairedAddUnsignedWiden32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm c = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const c = ctx.reg_alloc.ScratchXmm(code); code.movdqa(c, a); code.psllq(a, 32); @@ -2658,14 +2770,10 @@ void EmitX64::EmitVectorPairedAddUnsignedWiden32(EmitContext& ctx, IR::Inst* ins template static void PairedOperation(VectorArray& result, const VectorArray& x, const VectorArray& y, Function fn) { const size_t range = x.size() / 2; - - for (size_t i = 0; i < range; i++) { + for (size_t i = 0; i < range; i++) result[i] = fn(x[2 * i], x[2 * i + 1]); - } - - for (size_t i = 0; i < range; i++) { + for (size_t i = 0; i < range; i++) result[range + i] = fn(y[2 * i], y[2 * i + 1]); - } } template @@ -2686,11 +2794,6 @@ static void PairedMax(VectorArray& result, const VectorArray& x, const Vec PairedOperation(result, x, y, [](auto a, auto b) { return (std::max)(a, b); }); } -template -static void PairedMin(VectorArray& result, const VectorArray& x, const VectorArray& y) { - PairedOperation(result, x, y, [](auto a, auto b) { return (std::min)(a, b); }); -} - template static void LowerPairedMax(VectorArray& result, const VectorArray& x, const VectorArray& y) { LowerPairedOperation(result, x, y, [](auto a, auto b) { return (std::max)(a, b); }); @@ -2705,19 +2808,16 @@ template static void EmitVectorPairedMinMax8(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.movdqa(tmp, code.Const(xword, 0x0E'0C'0A'08'06'04'02'00, 0x0F'0D'0B'09'07'05'03'01)); code.pshufb(x, tmp); code.pshufb(y, tmp); - code.movaps(tmp, x); code.shufps(tmp, y, 0b01'00'01'00); - code.shufps(x, y, 0b11'10'11'10); - if constexpr (std::is_member_function_pointer_v) { (code.*fn)(x, tmp); } else { @@ -2730,21 +2830,17 @@ static void EmitVectorPairedMinMax8(BlockOfCode& code, EmitContext& ctx, IR::Ins template static void EmitVectorPairedMinMaxLower8(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(code, args[1]); - + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); code.punpcklqdq(x, y); code.pshufb(x, code.Const(xword, 0x0E'0C'0A'08'06'04'02'00, 0x0F'0D'0B'09'07'05'03'01)); code.movhlps(y, x); code.movq(x, x); - if constexpr (std::is_member_function_pointer_v) { (code.*fn)(x, y); } else { fn(x, y); } - ctx.reg_alloc.DefineValue(code, inst, x); } @@ -2752,9 +2848,9 @@ template static void EmitVectorPairedMinMax16(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); // swap idxs 1 and 2 within 64-bit lanes so that both registers contain [even, odd, even, odd]-indexed pairs of elements code.pshuflw(x, x, 0b11'01'10'00); @@ -2780,63 +2876,31 @@ static void EmitVectorPairedMinMax16(BlockOfCode& code, EmitContext& ctx, IR::In ctx.reg_alloc.DefineValue(code, inst, x); } -template -static void EmitVectorPairedMinMaxLower16(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) { - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); - - // swap idxs 1 and 2 so that both registers contain even then odd-indexed pairs of elements - code.pshuflw(x, x, 0b11'01'10'00); - code.pshuflw(y, y, 0b11'01'10'00); - - // move pairs of even/odd-indexed elements into one register each - - // tmp = x[0, 2], y[0, 2], 0s... - code.movaps(tmp, y); - code.insertps(tmp, x, 0b01001100); - // x = x[1, 3], y[1, 3], 0s... - code.insertps(x, y, 0b00011100); - - (code.*fn)(x, tmp); - - ctx.reg_alloc.DefineValue(code, inst, x); -} - -static void EmitVectorPairedMinMaxLower32(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, void (Xbyak::CodeGenerator::*fn)(const Xbyak::Xmm&, const Xbyak::Operand&)) { - auto args = ctx.reg_alloc.GetArgumentInfo(inst); - - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); - - // tmp = x[1], y[1], 0, 0 - code.movaps(tmp, y); - code.insertps(tmp, x, 0b01001100); - // x = x[0], y[0], 0, 0 - code.insertps(x, y, 0b00011100); - - (code.*fn)(x, tmp); - - ctx.reg_alloc.DefineValue(code, inst, x); -} void EmitX64::EmitVectorPairedMaxS8(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); + code.movdqa(tmp, code.Const(xword, 0x0E'0C'0A'08'06'04'02'00, 0x0F'0D'0B'09'07'05'03'01)); + code.pshufb(x, tmp); + code.pshufb(y, tmp); + code.movaps(tmp, x); + code.shufps(tmp, y, 0b01'00'01'00); + code.shufps(x, y, 0b11'10'11'10); if (code.HasHostFeature(HostFeature::SSE41)) { - EmitVectorPairedMinMax8(code, ctx, inst, &Xbyak::CodeGenerator::pmaxsb); - return; - } else if (code.HasHostFeature(HostFeature::SSSE3)) { - EmitVectorPairedMinMax8(code, ctx, inst, [&](const auto& lhs, const auto& rhs) { - FallbackMinMaxS8(code, ctx, lhs, rhs, MinMaxOperation::Max); - }); - return; + code.pmaxsb(x, tmp); + } else { + auto const a = x; + auto const b = tmp; + auto const c = ctx.reg_alloc.ScratchXmm(code); + code.movdqa(c, a); + code.pcmpgtb(c, b); + code.pand(a, c); + code.pandn(c, b); + code.por(a, c); } - - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - PairedMax(result, a, b); - }); + ctx.reg_alloc.DefineValue(code, inst, x); } void EmitX64::EmitVectorPairedMaxS16(EmitContext& ctx, IR::Inst* inst) { @@ -2846,9 +2910,9 @@ void EmitX64::EmitVectorPairedMaxS16(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorPairedMaxS32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.movdqa(tmp, x); code.shufps(tmp, y, 0b10001000); @@ -2866,12 +2930,24 @@ void EmitX64::EmitVectorPairedMaxS32(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorPairedMaxU8(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSSE3)) { EmitVectorPairedMinMax8(code, ctx, inst, &Xbyak::CodeGenerator::pmaxub); - return; + } else { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp3 = ctx.reg_alloc.ScratchXmm(code); + auto const constant_00ff = code.Const(xword, 0x00FF00FF00FF00FF, 0x00FF00FF00FF00FF); + code.movdqa(tmp2, constant_00ff); + code.movdqa(tmp3, tmp1); + code.pand(tmp3, tmp2); + code.pand(tmp2, tmp0); + code.packuswb(tmp2, tmp3); + code.psrlw(tmp1, 8); + code.psrlw(tmp0, 8); + code.packuswb(tmp0, tmp1); + code.pmaxub(tmp0, tmp2); + ctx.reg_alloc.DefineValue(code, inst, tmp0); } - - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - PairedMax(result, a, b); - }); } void EmitX64::EmitVectorPairedMaxU16(EmitContext& ctx, IR::Inst* inst) { @@ -2887,9 +2963,9 @@ void EmitX64::EmitVectorPairedMaxU16(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorPairedMaxU32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.movdqa(tmp, x); code.shufps(tmp, y, 0b10001000); @@ -2907,14 +2983,15 @@ void EmitX64::EmitVectorPairedMaxU32(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorPairedMinS8(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSE41)) { EmitVectorPairedMinMax8(code, ctx, inst, &Xbyak::CodeGenerator::pminsb); - } else if (code.HasHostFeature(HostFeature::SSSE3)) { - EmitVectorPairedMinMax8(code, ctx, inst, [&](const auto& lhs, const auto& rhs) { - FallbackMinMaxS8(code, ctx, lhs, rhs, MinMaxOperation::Min); - }); } else { - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - PairedMin(result, a, b); - }); + EmitVectorPairedMinMax8(code, ctx, inst, [&](const auto& a, const auto& b) { + auto const c = ctx.reg_alloc.ScratchXmm(code); + code.movdqa(c, b); + code.pcmpgtb(c, a); + code.pand(a, c); + code.pandn(c, b); + code.por(a, c); + }); } } @@ -2925,9 +3002,9 @@ void EmitX64::EmitVectorPairedMinS16(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorPairedMinS32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.movdqa(tmp, x); code.shufps(tmp, y, 0b10001000); @@ -2943,12 +3020,25 @@ void EmitX64::EmitVectorPairedMinS32(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorPairedMinU8(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSSE3)) { EmitVectorPairedMinMax8(code, ctx, inst, &Xbyak::CodeGenerator::pminub); - return; + } else { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp3 = ctx.reg_alloc.ScratchXmm(code); + auto const constant_00ff = code.Const(xword, 0x00FF00FF00FF00FF, 0x00FF00FF00FF00FF); + code.movdqa(tmp2, tmp1); + code.psrlw(tmp2, 8); + code.movdqa(tmp3, tmp0); + code.psrlw(tmp3, 8); + code.packuswb(tmp3, tmp2); + code.movdqa(tmp2, constant_00ff); + code.pand(tmp1, tmp2); + code.pand(tmp0, tmp2); + code.packuswb(tmp0, tmp1); + code.pminub(tmp0, tmp3); + ctx.reg_alloc.DefineValue(code, inst, tmp0); } - - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - PairedMin(result, a, b); - }); } void EmitX64::EmitVectorPairedMinU16(EmitContext& ctx, IR::Inst* inst) { @@ -2964,9 +3054,9 @@ void EmitX64::EmitVectorPairedMinU16(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorPairedMinU32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.movdqa(tmp, x); code.shufps(tmp, y, 0b10001000); @@ -2982,41 +3072,88 @@ void EmitX64::EmitVectorPairedMinU32(EmitContext& ctx, IR::Inst* inst) { } void EmitX64::EmitVectorPairedMaxLowerS8(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); if (code.HasHostFeature(HostFeature::SSE41)) { - EmitVectorPairedMinMaxLower8(code, ctx, inst, &Xbyak::CodeGenerator::pmaxsb); - return; - } else if (code.HasHostFeature(HostFeature::SSSE3)) { - EmitVectorPairedMinMaxLower8(code, ctx, inst, [&](const auto& lhs, const auto& rhs) { - FallbackMinMaxS8(code, ctx, lhs, rhs, MinMaxOperation::Max); - }); - return; + code.punpcklqdq(x, y); + code.pshufb(x, code.Const(xword, 0x0E'0C'0A'08'06'04'02'00, 0x0F'0D'0B'09'07'05'03'01)); + code.movhlps(y, x); + code.movq(x, x); + code.pmaxsb(x, y); + } else { + auto const c = ctx.reg_alloc.ScratchXmm(code); + code.punpcklqdq(x, y); + code.pshufb(x, code.Const(xword, 0x0E'0C'0A'08'06'04'02'00, 0x0F'0D'0B'09'07'05'03'01)); + code.movhlps(y, x); + code.movq(x, x); + code.movdqa(c, x); + code.pcmpgtb(c, y); + code.pand(x, c); + code.pandn(c, y); + code.por(x, c); } - - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - LowerPairedMax(result, a, b); - }); + ctx.reg_alloc.DefineValue(code, inst, x); } void EmitX64::EmitVectorPairedMaxLowerS16(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::SSE41)) { - EmitVectorPairedMinMaxLower16(code, ctx, inst, &Xbyak::CodeGenerator::pmaxsw); - return; + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); + // swap idxs 1 and 2 so that both registers contain even then odd-indexed pairs of elements + code.pshuflw(x, x, 0b11'01'10'00); + code.pshuflw(y, y, 0b11'01'10'00); + // move pairs of even/odd-indexed elements into one register each + // tmp = x[0, 2], y[0, 2], 0s... + code.movaps(tmp, y); + code.insertps(tmp, x, 0b01001100); + // x = x[1, 3], y[1, 3], 0s... + code.insertps(x, y, 0b00011100); + code.pmaxsw(x, tmp); + ctx.reg_alloc.DefineValue(code, inst, x); + } else { + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseScratchXmm(code, args[1]); + code.punpcklwd(tmp0, tmp1); + code.pshufd(tmp1, tmp0, 232); + code.pshuflw(tmp1, tmp1, 216); + code.pshufd(tmp0, tmp0, 231); + code.pshuflw(tmp0, tmp0, 114); + code.pmaxsw(tmp0, tmp1); + code.movq(tmp0, tmp0); + ctx.reg_alloc.DefineValue(code, inst, tmp0); } - - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - LowerPairedMax(result, a, b); - }); } void EmitX64::EmitVectorPairedMaxLowerS32(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::SSE41)) { - EmitVectorPairedMinMaxLower32(code, ctx, inst, &Xbyak::CodeGenerator::pmaxsd); - return; + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); + // tmp = x[1], y[1], 0, 0 + code.movaps(tmp, y); + code.insertps(tmp, x, 0b01001100); + // x = x[0], y[0], 0, 0 + code.insertps(x, y, 0b00011100); + code.pmaxsd(x, tmp); + ctx.reg_alloc.DefineValue(code, inst, x); + } else { + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + code.punpckldq(tmp0, tmp1); + code.pshufd(tmp1, tmp0, 238); + code.movdqa(tmp2, tmp0); + code.pcmpgtd(tmp2, tmp1); + code.pand(tmp0, tmp2); + code.pandn(tmp2, tmp1); + code.por(tmp2, tmp0); + code.movq(tmp0, tmp2); + ctx.reg_alloc.DefineValue(code, inst, tmp0); } - - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - LowerPairedMax(result, a, b); - }); } void EmitX64::EmitVectorPairedMaxLowerU8(EmitContext& ctx, IR::Inst* inst) { @@ -3031,63 +3168,143 @@ void EmitX64::EmitVectorPairedMaxLowerU8(EmitContext& ctx, IR::Inst* inst) { } void EmitX64::EmitVectorPairedMaxLowerU16(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::SSE41)) { - EmitVectorPairedMinMaxLower16(code, ctx, inst, &Xbyak::CodeGenerator::pmaxuw); - return; + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); + // swap idxs 1 and 2 so that both registers contain even then odd-indexed pairs of elements + code.pshuflw(x, x, 0b11'01'10'00); + code.pshuflw(y, y, 0b11'01'10'00); + // move pairs of even/odd-indexed elements into one register each + // tmp = x[0, 2], y[0, 2], 0s... + code.movaps(tmp, y); + code.insertps(tmp, x, 0b01001100); + // x = x[1, 3], y[1, 3], 0s... + code.insertps(x, y, 0b00011100); + code.pmaxuw(x, tmp); + ctx.reg_alloc.DefineValue(code, inst, x); + } else { + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseScratchXmm(code, args[1]); + code.punpcklwd(tmp0, tmp1); + code.pshufd(tmp1, tmp0, 232); + code.pshuflw(tmp1, tmp1, 216); + code.pshufd(tmp0, tmp0, 231); + code.pshuflw(tmp0, tmp0, 114); + code.psubusw(tmp0, tmp1); + code.paddw(tmp0, tmp1); + code.movq(tmp0, tmp0); + ctx.reg_alloc.DefineValue(code, inst, tmp0); } - - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - LowerPairedMax(result, a, b); - }); } void EmitX64::EmitVectorPairedMaxLowerU32(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::SSE41)) { - EmitVectorPairedMinMaxLower32(code, ctx, inst, &Xbyak::CodeGenerator::pmaxud); - return; + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); + // tmp = x[1], y[1], 0, 0 + code.movaps(tmp, y); + code.insertps(tmp, x, 0b01001100); + // x = x[0], y[0], 0, 0 + code.insertps(x, y, 0b00011100); + code.pmaxud(x, tmp); + ctx.reg_alloc.DefineValue(code, inst, x); + } else { + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp3 = ctx.reg_alloc.ScratchXmm(code); + code.punpckldq(tmp0, tmp1); + code.pshufd(tmp1, tmp0, 238); + code.movdqa(tmp2, code.Const(xword, 0x8000'00008000'0000, 0x8000'00008000'0000)); + code.movdqa(tmp3, tmp0); + code.pxor(tmp3, tmp2); + code.pxor(tmp2, tmp1); + code.pcmpgtd(tmp3, tmp2); + code.pand(tmp0, tmp3); + code.pandn(tmp3, tmp1); + code.por(tmp3, tmp0); + code.movq(tmp0, tmp3); + ctx.reg_alloc.DefineValue(code, inst, tmp0); } - - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - LowerPairedMax(result, a, b); - }); } void EmitX64::EmitVectorPairedMinLowerS8(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSE41)) { EmitVectorPairedMinMaxLower8(code, ctx, inst, &Xbyak::CodeGenerator::pminsb); - return; - } else if (code.HasHostFeature(HostFeature::SSSE3)) { - EmitVectorPairedMinMaxLower8(code, ctx, inst, [&](const auto& lhs, const auto& rhs) { - FallbackMinMaxS8(code, ctx, lhs, rhs, MinMaxOperation::Min); + } else { + EmitVectorPairedMinMaxLower8(code, ctx, inst, [&](const auto& a, const auto& b) { + auto const c = ctx.reg_alloc.ScratchXmm(code); + code.movdqa(c, b); + code.pcmpgtb(c, a); + code.pand(a, c); + code.pandn(c, b); + code.por(a, c); }); - return; } - - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - LowerPairedMin(result, a, b); - }); } void EmitX64::EmitVectorPairedMinLowerS16(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::SSE41)) { - EmitVectorPairedMinMaxLower16(code, ctx, inst, &Xbyak::CodeGenerator::pminsw); - return; + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); + // swap idxs 1 and 2 so that both registers contain even then odd-indexed pairs of elements + code.pshuflw(x, x, 0b11'01'10'00); + code.pshuflw(y, y, 0b11'01'10'00); + // move pairs of even/odd-indexed elements into one register each + // tmp = x[0, 2], y[0, 2], 0s... + code.movaps(tmp, y); + code.insertps(tmp, x, 0b01001100); + // x = x[1, 3], y[1, 3], 0s... + code.insertps(x, y, 0b00011100); + code.pminsw(x, tmp); + ctx.reg_alloc.DefineValue(code, inst, x); + } else { + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseScratchXmm(code, args[1]); + code.punpcklwd(tmp0, tmp1); + code.pshufd(tmp1, tmp0, 231); + code.pshuflw(tmp1, tmp1, 114); + code.pshufd(tmp0, tmp0, 232); + code.pshuflw(tmp0, tmp0, 216); + code.pminsw(tmp0, tmp1); + code.movq(tmp0, tmp0); + ctx.reg_alloc.DefineValue(code, inst, tmp0); } - - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - LowerPairedMin(result, a, b); - }); } void EmitX64::EmitVectorPairedMinLowerS32(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::SSE41)) { - EmitVectorPairedMinMaxLower32(code, ctx, inst, &Xbyak::CodeGenerator::pminsd); - return; + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); + // tmp = x[1], y[1], 0, 0 + code.movaps(tmp, y); + code.insertps(tmp, x, 0b01001100); + // x = x[0], y[0], 0, 0 + code.insertps(x, y, 0b00011100); + code.pminsd(x, tmp); + ctx.reg_alloc.DefineValue(code, inst, x); + } else { + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + code.punpckldq(tmp0, tmp1); + code.pshufd(tmp1, tmp0, 238); + code.movdqa(tmp2, tmp0); + code.pcmpgtd(tmp2, tmp1); + code.pand(tmp1, tmp2); + code.pandn(tmp2, tmp0); + code.por(tmp2, tmp1); + code.movq(tmp0, tmp2); + ctx.reg_alloc.DefineValue(code, inst, tmp0); } - - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - LowerPairedMin(result, a, b); - }); } void EmitX64::EmitVectorPairedMinLowerU8(EmitContext& ctx, IR::Inst* inst) { @@ -3102,50 +3319,91 @@ void EmitX64::EmitVectorPairedMinLowerU8(EmitContext& ctx, IR::Inst* inst) { } void EmitX64::EmitVectorPairedMinLowerU16(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::SSE41)) { - EmitVectorPairedMinMaxLower16(code, ctx, inst, &Xbyak::CodeGenerator::pminuw); - return; + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); + // swap idxs 1 and 2 so that both registers contain even then odd-indexed pairs of elements + code.pshuflw(x, x, 0b11'01'10'00); + code.pshuflw(y, y, 0b11'01'10'00); + // move pairs of even/odd-indexed elements into one register each + // tmp = x[0, 2], y[0, 2], 0s... + code.movaps(tmp, y); + code.insertps(tmp, x, 0b01001100); + // x = x[1, 3], y[1, 3], 0s... + code.insertps(x, y, 0b00011100); + code.pminuw(x, tmp); + ctx.reg_alloc.DefineValue(code, inst, x); + } else { + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + code.punpcklwd(tmp0, tmp1); + code.pshufd(tmp1, tmp0, 231); + code.pshuflw(tmp1, tmp1, 114); + code.pshufd(tmp0, tmp0, 232); + code.pshuflw(tmp0, tmp0, 216); + code.movdqa(tmp2, tmp1); + code.psubusw(tmp2, tmp0); + code.psubw(tmp1, tmp2); + code.movq(tmp0, tmp1); + ctx.reg_alloc.DefineValue(code, inst, tmp0); } - - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - LowerPairedMin(result, a, b); - }); } void EmitX64::EmitVectorPairedMinLowerU32(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::SSE41)) { - EmitVectorPairedMinMaxLower32(code, ctx, inst, &Xbyak::CodeGenerator::pminud); - return; + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); + // tmp = x[1], y[1], 0, 0 + code.movaps(tmp, y); + code.insertps(tmp, x, 0b01001100); + // x = x[0], y[0], 0, 0 + code.insertps(x, y, 0b00011100); + code.pminud(x, tmp); + ctx.reg_alloc.DefineValue(code, inst, x); + } else { + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp3 = ctx.reg_alloc.ScratchXmm(code); + code.punpckldq(tmp0, tmp1); + code.pshufd(tmp1, tmp0, 238); + code.movdqa(tmp2, code.Const(xword, 0x8000'00008000'0000, 0x8000'00008000'0000)); + code.movdqa(tmp3, tmp0); + code.pxor(tmp3, tmp2); + code.pxor(tmp2, tmp1); + code.pcmpgtd(tmp3, tmp2); + code.pand(tmp1, tmp3); + code.pandn(tmp3, tmp0); + code.por(tmp3, tmp1); + code.movq(tmp0, tmp3); + ctx.reg_alloc.DefineValue(code, inst, tmp0); } - - EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray& result, const VectorArray& a, const VectorArray& b) { - LowerPairedMin(result, a, b); - }); } template static D PolynomialMultiply(T lhs, T rhs) { constexpr size_t bit_size = mcl::bitsizeof; const std::bitset operand(lhs); - D res = 0; - for (size_t i = 0; i < bit_size; i++) { - if (operand[i]) { + for (size_t i = 0; i < bit_size; i++) + if (operand[i]) res ^= rhs << i; - } - } - return res; } void EmitX64::EmitVectorPolynomialMultiply8(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSE41)) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm alternate = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm mask = ctx.reg_alloc.ScratchXmm(code); + auto const xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); + auto const result = ctx.reg_alloc.ScratchXmm(code); + auto const alternate = ctx.reg_alloc.ScratchXmm(code); + auto const mask = ctx.reg_alloc.ScratchXmm(code); const Xbyak::Reg32 counter = ctx.reg_alloc.ScratchGpr(code).cvt32(); Xbyak::Label loop; @@ -3183,11 +3441,11 @@ void EmitX64::EmitVectorPolynomialMultiply8(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorPolynomialMultiplyLong8(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSE41)) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm xmm_b = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm alternate = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm mask = ctx.reg_alloc.ScratchXmm(code); + auto const xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const result = ctx.reg_alloc.ScratchXmm(code); + auto const alternate = ctx.reg_alloc.ScratchXmm(code); + auto const mask = ctx.reg_alloc.ScratchXmm(code); const Xbyak::Reg32 counter = ctx.reg_alloc.ScratchGpr(code).cvt32(); Xbyak::Label loop; @@ -3229,8 +3487,8 @@ void EmitX64::EmitVectorPolynomialMultiplyLong8(EmitContext& ctx, IR::Inst* inst void EmitX64::EmitVectorPolynomialMultiplyLong64(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::PCLMULQDQ)) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); + auto const xmm_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const xmm_b = ctx.reg_alloc.UseXmm(code, args[1]); code.pclmulqdq(xmm_a, xmm_b, 0x00); @@ -3260,7 +3518,7 @@ void EmitX64::EmitVectorPolynomialMultiplyLong64(EmitContext& ctx, IR::Inst* ins void EmitX64::EmitVectorPopulationCount(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::AVX512VL | HostFeature::AVX512BITALG)) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const data = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.vpopcntb(data, data); @@ -3271,10 +3529,10 @@ void EmitX64::EmitVectorPopulationCount(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSSE3)) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm low_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm high_a = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm tmp1 = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const low_a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const high_a = ctx.reg_alloc.ScratchXmm(code); + auto const tmp1 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); code.movdqa(high_a, low_a); code.psrlw(high_a, 4); @@ -3303,12 +3561,12 @@ void EmitX64::EmitVectorPopulationCount(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorReverseBits(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const data = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::GFNI)) { code.gf2p8affineqb(data, code.Const(xword, 0x8040201008040201, 0x8040201008040201), 0); } else { - const Xbyak::Xmm high_nibble_reg = ctx.reg_alloc.ScratchXmm(code); + auto const high_nibble_reg = ctx.reg_alloc.ScratchXmm(code); code.movdqa(high_nibble_reg, code.Const(xword, 0xF0F0F0F0F0F0F0F0, 0xF0F0F0F0F0F0F0F0)); code.pand(high_nibble_reg, data); code.pxor(data, high_nibble_reg); @@ -3316,7 +3574,7 @@ void EmitX64::EmitVectorReverseBits(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSSE3)) { // High lookup - const Xbyak::Xmm high_reversed_reg = ctx.reg_alloc.ScratchXmm(code); + auto const high_reversed_reg = ctx.reg_alloc.ScratchXmm(code); code.movdqa(high_reversed_reg, code.Const(xword, 0xE060A020C0408000, 0xF070B030D0509010)); code.pshufb(high_reversed_reg, data); @@ -3350,8 +3608,8 @@ void EmitX64::EmitVectorReverseBits(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorReverseElementsInHalfGroups8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const data = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.movdqa(tmp, data); code.psllw(tmp, 8); @@ -3363,13 +3621,13 @@ void EmitX64::EmitVectorReverseElementsInHalfGroups8(EmitContext& ctx, IR::Inst* void EmitX64::EmitVectorReverseElementsInWordGroups8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const data = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::AVX)) { code.vpshufb(data, data, code.Const(xword, 0x0405060700010203, 0x0c0d0e0f08090a0b)); } else if (code.HasHostFeature(HostFeature::SSSE3)) { code.pshufb(data, code.Const(xword, 0x0405060700010203, 0x0c0d0e0f08090a0b)); } else { - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.movdqa(tmp, data); code.psllw(tmp, 8); code.psrlw(data, 8); @@ -3382,7 +3640,7 @@ void EmitX64::EmitVectorReverseElementsInWordGroups8(EmitContext& ctx, IR::Inst* void EmitX64::EmitVectorReverseElementsInWordGroups16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const data = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.pshuflw(data, data, 0b10110001); code.pshufhw(data, data, 0b10110001); ctx.reg_alloc.DefineValue(code, inst, data); @@ -3390,13 +3648,13 @@ void EmitX64::EmitVectorReverseElementsInWordGroups16(EmitContext& ctx, IR::Inst void EmitX64::EmitVectorReverseElementsInLongGroups8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const data = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::AVX)) { code.vpshufb(data, data, code.Const(xword, 0x0001020304050607, 0x08090a0b0c0d0e0f)); } else if (code.HasHostFeature(HostFeature::SSSE3)) { code.pshufb(data, code.Const(xword, 0x0001020304050607, 0x08090a0b0c0d0e0f)); } else { - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.movdqa(tmp, data); code.psllw(tmp, 8); code.psrlw(data, 8); @@ -3410,7 +3668,7 @@ void EmitX64::EmitVectorReverseElementsInLongGroups8(EmitContext& ctx, IR::Inst* void EmitX64::EmitVectorReverseElementsInLongGroups16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const data = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.pshuflw(data, data, 0b00011011); code.pshufhw(data, data, 0b00011011); @@ -3421,7 +3679,7 @@ void EmitX64::EmitVectorReverseElementsInLongGroups16(EmitContext& ctx, IR::Inst void EmitX64::EmitVectorReverseElementsInLongGroups32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const data = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.pshuflw(data, data, 0b01001110); code.pshufhw(data, data, 0b01001110); @@ -3432,8 +3690,8 @@ void EmitX64::EmitVectorReverseElementsInLongGroups32(EmitContext& ctx, IR::Inst void EmitX64::EmitVectorReduceAdd8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm temp = xmm0; + auto const data = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const temp = xmm0; // Add upper elements to lower elements code.pshufd(temp, data, 0b01'00'11'10); @@ -3453,8 +3711,8 @@ void EmitX64::EmitVectorReduceAdd8(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorReduceAdd16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm temp = xmm0; + auto const data = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const temp = xmm0; if (code.HasHostFeature(HostFeature::SSSE3)) { code.pxor(temp, temp); @@ -3484,8 +3742,8 @@ void EmitX64::EmitVectorReduceAdd16(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorReduceAdd32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm temp = xmm0; + auto const data = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const temp = xmm0; // Add upper elements to lower elements(reversed) code.pshufd(temp, data, 0b00'01'10'11); @@ -3508,8 +3766,8 @@ void EmitX64::EmitVectorReduceAdd32(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorReduceAdd64(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm temp = xmm0; + auto const data = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const temp = xmm0; // Add upper elements to lower elements code.pshufd(temp, data, 0b01'00'11'10); @@ -3524,8 +3782,8 @@ void EmitX64::EmitVectorReduceAdd64(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorRotateWholeVectorRight(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm operand = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const operand = ctx.reg_alloc.UseXmm(code, args[0]); + auto const result = ctx.reg_alloc.ScratchXmm(code); const u8 shift_amount = args[1].GetImmediateU8(); ASSERT(shift_amount % 32 == 0); const u8 shuffle_imm = std::rotr(0b11100100, shift_amount / 32 * 2); @@ -3538,12 +3796,12 @@ void EmitX64::EmitVectorRotateWholeVectorRight(EmitContext& ctx, IR::Inst* inst) static void EmitVectorRoundingHalvingAddSigned(size_t esize, EmitContext& ctx, IR::Inst* inst, BlockOfCode& code) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseScratchXmm(code, args[1]); switch (esize) { case 8: { - const Xbyak::Xmm vec_128 = ctx.reg_alloc.ScratchXmm(code); + auto const vec_128 = ctx.reg_alloc.ScratchXmm(code); code.movdqa(vec_128, code.Const(xword, 0x8080808080808080, 0x8080808080808080)); code.paddb(a, vec_128); @@ -3553,7 +3811,7 @@ static void EmitVectorRoundingHalvingAddSigned(size_t esize, EmitContext& ctx, I break; } case 16: { - const Xbyak::Xmm vec_32768 = ctx.reg_alloc.ScratchXmm(code); + auto const vec_32768 = ctx.reg_alloc.ScratchXmm(code); code.movdqa(vec_32768, code.Const(xword, 0x8000800080008000, 0x8000800080008000)); code.paddw(a, vec_32768); @@ -3563,7 +3821,7 @@ static void EmitVectorRoundingHalvingAddSigned(size_t esize, EmitContext& ctx, I break; } case 32: { - const Xbyak::Xmm tmp1 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp1 = ctx.reg_alloc.ScratchXmm(code); code.movdqa(tmp1, a); code.por(a, b); @@ -3603,9 +3861,9 @@ static void EmitVectorRoundingHalvingAddUnsigned(size_t esize, EmitContext& ctx, case 32: { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm tmp1 = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp1 = ctx.reg_alloc.ScratchXmm(code); code.movdqa(tmp1, a); @@ -3669,18 +3927,18 @@ static void EmitUnsignedRoundingShiftLeft(BlockOfCode& code, EmitContext& ctx, I static_assert(esize == 32 || esize == 64); auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm b = ctx.reg_alloc.UseXmm(code, args[1]); + auto const a = ctx.reg_alloc.UseXmm(code, args[0]); + auto const b = ctx.reg_alloc.UseXmm(code, args[1]); // positive values of b are left shifts, while negative values are (positive) rounding right shifts // only the lowest byte of each element is read as the shift amount // conveniently, the behavior of bit shifts greater than element width is the same in NEON and SSE/AVX - filled with zeros - const Xbyak::Xmm shift_amount = ctx.reg_alloc.ScratchXmm(code); + auto const shift_amount = ctx.reg_alloc.ScratchXmm(code); code.vpabsb(shift_amount, b); code.vpand(shift_amount, shift_amount, code.BConst(xword, 0xFF)); // if b is positive, do a normal left shift - const Xbyak::Xmm left_shift = ctx.reg_alloc.ScratchXmm(code); + auto const left_shift = ctx.reg_alloc.ScratchXmm(code); ICODE(vpsllv)(left_shift, a, shift_amount); // if b is negative, compute the rounding right shift @@ -3691,7 +3949,7 @@ static void EmitUnsignedRoundingShiftLeft(BlockOfCode& code, EmitContext& ctx, I // tmp = (a >> (b - 1)) & 1 // res = (a >> b) + tmp // to add the value of the last bit to be shifted off to the result of the right shift - const Xbyak::Xmm right_shift = ctx.reg_alloc.ScratchXmm(code); + auto const right_shift = ctx.reg_alloc.ScratchXmm(code); code.vmovdqa(xmm0, code.BConst(xword, 1)); // find value of last bit to be shifted off @@ -3775,12 +4033,12 @@ void EmitX64::EmitVectorRoundingShiftLeftU64(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorSignExtend8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::SSE41)) { - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.pmovsxbw(a, a); ctx.reg_alloc.DefineValue(code, inst, a); } else { - const Xbyak::Xmm a = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseXmm(code, args[0]); + auto const result = ctx.reg_alloc.ScratchXmm(code); code.pxor(result, result); code.punpcklbw(result, a); code.psraw(result, 8); @@ -3791,12 +4049,12 @@ void EmitX64::EmitVectorSignExtend8(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorSignExtend16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::SSE41)) { - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.pmovsxwd(a, a); ctx.reg_alloc.DefineValue(code, inst, a); } else { - const Xbyak::Xmm a = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseXmm(code, args[0]); + auto const result = ctx.reg_alloc.ScratchXmm(code); code.pxor(result, result); code.punpcklwd(result, a); code.psrad(result, 16); @@ -3806,12 +4064,12 @@ void EmitX64::EmitVectorSignExtend16(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorSignExtend32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::SSE41)) { code.pmovsxdq(a, a); } else { - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); code.movaps(tmp, a); code.psrad(tmp, 31); @@ -3824,7 +4082,7 @@ void EmitX64::EmitVectorSignExtend32(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorSignExtend64(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const data = ctx.reg_alloc.UseScratchXmm(code, args[0]); const Xbyak::Reg64 gpr_tmp = ctx.reg_alloc.ScratchGpr(code); code.movq(gpr_tmp, data); @@ -3833,7 +4091,7 @@ void EmitX64::EmitVectorSignExtend64(EmitContext& ctx, IR::Inst* inst) { if (code.HasHostFeature(HostFeature::SSE41)) { code.pinsrq(data, gpr_tmp, 1); } else { - const Xbyak::Xmm xmm_tmp = ctx.reg_alloc.ScratchXmm(code); + auto const xmm_tmp = ctx.reg_alloc.ScratchXmm(code); code.movq(xmm_tmp, gpr_tmp); code.punpcklqdq(data, xmm_tmp); @@ -3844,9 +4102,9 @@ void EmitX64::EmitVectorSignExtend64(EmitContext& ctx, IR::Inst* inst) { static void EmitVectorSignedAbsoluteDifference(size_t esize, EmitContext& ctx, IR::Inst* inst, BlockOfCode& code) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); // only signed 16-bit min/max are available below SSE4.1 if (code.HasHostFeature(HostFeature::SSE41) || esize == 16) { @@ -3912,11 +4170,11 @@ void EmitX64::EmitVectorSignedMultiply16(EmitContext& ctx, IR::Inst* inst) { const auto lower_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetLowerFromOp); auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm x = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseXmm(code, args[1]); + auto const x = ctx.reg_alloc.UseXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseXmm(code, args[1]); if (upper_inst) { - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const result = ctx.reg_alloc.ScratchXmm(code); if (code.HasHostFeature(HostFeature::AVX)) { code.vpmulhw(result, x, y); } else { @@ -3928,7 +4186,7 @@ void EmitX64::EmitVectorSignedMultiply16(EmitContext& ctx, IR::Inst* inst) { } if (lower_inst) { - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const result = ctx.reg_alloc.ScratchXmm(code); if (code.HasHostFeature(HostFeature::AVX)) { code.vpmullw(result, x, y); } else { @@ -3946,9 +4204,9 @@ void EmitX64::EmitVectorSignedMultiply32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (lower_inst && !upper_inst && code.HasHostFeature(HostFeature::AVX)) { - const Xbyak::Xmm x = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const x = ctx.reg_alloc.UseXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseXmm(code, args[1]); + auto const result = ctx.reg_alloc.ScratchXmm(code); code.vpmulld(result, x, y); @@ -3957,16 +4215,16 @@ void EmitX64::EmitVectorSignedMultiply32(EmitContext& ctx, IR::Inst* inst) { } if (code.HasHostFeature(HostFeature::AVX)) { - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); if (lower_inst) { - const Xbyak::Xmm lower_result = ctx.reg_alloc.ScratchXmm(code); + auto const lower_result = ctx.reg_alloc.ScratchXmm(code); code.vpmulld(lower_result, x, y); ctx.reg_alloc.DefineValue(code, lower_inst, lower_result); } - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const result = ctx.reg_alloc.ScratchXmm(code); code.vpmuldq(result, x, y); code.vpsrlq(x, x, 32); @@ -3978,12 +4236,12 @@ void EmitX64::EmitVectorSignedMultiply32(EmitContext& ctx, IR::Inst* inst) { return; } - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm sign_correction = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm upper_result = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm lower_result = ctx.reg_alloc.ScratchXmm(code); + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); + auto const sign_correction = ctx.reg_alloc.ScratchXmm(code); + auto const upper_result = ctx.reg_alloc.ScratchXmm(code); + auto const lower_result = ctx.reg_alloc.ScratchXmm(code); // calculate sign correction code.movdqa(tmp, x); @@ -4026,7 +4284,7 @@ void EmitX64::EmitVectorSignedMultiply32(EmitContext& ctx, IR::Inst* inst) { static void EmitVectorSignedSaturatedAbs(size_t esize, BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const data = ctx.reg_alloc.UseScratchXmm(code, args[0]); const Xbyak::Reg32 bit = ctx.reg_alloc.ScratchGpr(code).cvt32(); // SSE absolute value functions return an unsigned result @@ -4038,21 +4296,34 @@ static void EmitVectorSignedSaturatedAbs(size_t esize, BlockOfCode& code, EmitCo // or shift in sign bits to create a mask of (msb == 1 ? -1 : 0), then add to the result vector switch (esize) { case 8: { - VectorAbs8(code, ctx, data); + if (code.HasHostFeature(HostFeature::SSSE3)) { + code.pabsb(data, data); + } else { + auto const temp = ctx.reg_alloc.ScratchXmm(code); + code.pxor(temp, temp); + code.psubb(temp, data); + code.pminub(data, temp); + } code.pmovmskb(bit, data); - code.pminub(data, code.BConst<8>(xword, 0x7F)); break; } case 16: { - VectorAbs16(code, ctx, data); + if (code.HasHostFeature(HostFeature::SSSE3)) { + code.pabsw(data, data); + } else { + auto const temp = ctx.reg_alloc.ScratchXmm(code); + code.pxor(temp, temp); + code.psubw(temp, data); + code.pmaxsw(data, temp); + } code.pmovmskb(bit, data); code.and_(bit, 0xAAAA); // toggle mask bits that aren't the msb of an int16 to 0 if (code.HasHostFeature(HostFeature::SSE41)) { code.pminuw(data, code.BConst<16>(xword, 0x7FFF)); } else { - const Xbyak::Xmm tmp = xmm0; + auto const tmp = xmm0; code.movdqa(tmp, data); code.psraw(data, 15); code.paddw(data, tmp); @@ -4060,13 +4331,21 @@ static void EmitVectorSignedSaturatedAbs(size_t esize, BlockOfCode& code, EmitCo break; } case 32: { - VectorAbs32(code, ctx, data); + if (code.HasHostFeature(HostFeature::SSSE3)) { + code.pabsd(data, data); + } else { + auto const temp = ctx.reg_alloc.ScratchXmm(code); + code.movdqa(temp, data); + code.psrad(temp, 31); + code.pxor(data, temp); + code.psubd(data, temp); + } code.movmskps(bit, data); if (code.HasHostFeature(HostFeature::SSE41)) { code.pminud(data, code.BConst<32>(xword, 0x7FFFFFFF)); } else { - const Xbyak::Xmm tmp = xmm0; + auto const tmp = xmm0; code.movdqa(tmp, data); code.psrad(data, 31); code.paddd(data, tmp); @@ -4074,10 +4353,18 @@ static void EmitVectorSignedSaturatedAbs(size_t esize, BlockOfCode& code, EmitCo break; } case 64: { - VectorAbs64(code, ctx, data); + if (code.HasHostFeature(HostFeature::AVX512_Ortho)) { + code.vpabsq(data, data); + } else { + auto const temp = ctx.reg_alloc.ScratchXmm(code); + code.pshufd(temp, data, 0b11110101); + code.psrad(temp, 31); + code.pxor(data, temp); + code.psubq(data, temp); + } code.movmskpd(bit, data); - const Xbyak::Xmm tmp = xmm0; + auto const tmp = xmm0; if (code.HasHostFeature(HostFeature::SSE42)) { // create a -1 mask if msb is set code.pxor(tmp, tmp); @@ -4119,13 +4406,13 @@ template static void EmitVectorSignedSaturatedAccumulateUnsigned(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm y = ctx.reg_alloc.UseXmm(code, args[1]); + auto const y = ctx.reg_alloc.UseXmm(code, args[1]); code.movdqa(xmm0, y); ctx.reg_alloc.Release(y); - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.ScratchXmm(code); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); switch (bit_width) { case 8: @@ -4182,7 +4469,7 @@ static void EmitVectorSignedSaturatedAccumulateUnsigned(BlockOfCode& code, EmitC switch (bit_width) { case 8: if (code.HasHostFeature(HostFeature::AVX)) { - const Xbyak::Xmm tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); code.pcmpeqb(tmp2, tmp2); code.pxor(tmp, tmp); code.vpblendvb(xmm0, tmp, tmp2, xmm0); @@ -4262,10 +4549,10 @@ void EmitX64::EmitVectorSignedSaturatedAccumulateUnsigned64(EmitContext& ctx, IR template static void EmitVectorSignedSaturatedDoublingMultiply16(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm x = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm upper_tmp = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm lower_tmp = ctx.reg_alloc.ScratchXmm(code); + auto const x = ctx.reg_alloc.UseXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseXmm(code, args[1]); + auto const upper_tmp = ctx.reg_alloc.ScratchXmm(code); + auto const lower_tmp = ctx.reg_alloc.ScratchXmm(code); if (code.HasHostFeature(HostFeature::AVX)) { code.vpmulhw(upper_tmp, x, y); @@ -4284,7 +4571,7 @@ static void EmitVectorSignedSaturatedDoublingMultiply16(BlockOfCode& code, EmitC ctx.reg_alloc.Release(x); ctx.reg_alloc.Release(y); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const result = ctx.reg_alloc.ScratchXmm(code); if (code.HasHostFeature(HostFeature::AVX)) { if constexpr (is_rounding) { @@ -4334,10 +4621,10 @@ void EmitVectorSignedSaturatedDoublingMultiply32(BlockOfCode& code, EmitContext& auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (code.HasHostFeature(HostFeature::AVX)) { - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm odds = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm even = ctx.reg_alloc.ScratchXmm(code); + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const odds = ctx.reg_alloc.ScratchXmm(code); + auto const even = ctx.reg_alloc.ScratchXmm(code); code.vpmuldq(odds, x, y); code.vpsrlq(x, x, 32); @@ -4350,7 +4637,7 @@ void EmitVectorSignedSaturatedDoublingMultiply32(BlockOfCode& code, EmitContext& code.vpaddq(odds, odds, odds); code.vpaddq(even, even, even); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const result = ctx.reg_alloc.ScratchXmm(code); if constexpr (is_rounding) { code.vmovdqa(result, code.Const(xword, 0x0000000080000000, 0x0000000080000000)); @@ -4361,7 +4648,7 @@ void EmitVectorSignedSaturatedDoublingMultiply32(BlockOfCode& code, EmitContext& code.vpsrlq(result, odds, 32); code.vblendps(result, result, even, 0b1010); - const Xbyak::Xmm mask = ctx.reg_alloc.ScratchXmm(code); + auto const mask = ctx.reg_alloc.ScratchXmm(code); const Xbyak::Reg32 bit = ctx.reg_alloc.ScratchGpr(code).cvt32(); code.vpcmpeqd(mask, result, code.Const(xword, 0x8000000080000000, 0x8000000080000000)); @@ -4376,11 +4663,11 @@ void EmitVectorSignedSaturatedDoublingMultiply32(BlockOfCode& code, EmitContext& return; } - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm sign_correction = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); + auto const sign_correction = ctx.reg_alloc.ScratchXmm(code); + auto const result = ctx.reg_alloc.ScratchXmm(code); // calculate sign correction code.movdqa(tmp, x); @@ -4439,8 +4726,8 @@ void EmitX64::EmitVectorSignedSaturatedDoublingMultiplyHighRounding32(EmitContex void EmitX64::EmitVectorSignedSaturatedDoublingMultiplyLong16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); code.punpcklwd(x, x); code.punpcklwd(y, y); @@ -4465,8 +4752,8 @@ void EmitX64::EmitVectorSignedSaturatedDoublingMultiplyLong16(EmitContext& ctx, void EmitX64::EmitVectorSignedSaturatedDoublingMultiplyLong32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); if (code.HasHostFeature(HostFeature::AVX)) { code.vpmovsxdq(x, x); @@ -4517,10 +4804,10 @@ void EmitX64::EmitVectorSignedSaturatedDoublingMultiplyLong32(EmitContext& ctx, static void EmitVectorSignedSaturatedNarrowToSigned(size_t original_esize, BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm src = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm dest = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm reconstructed = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm sign = ctx.reg_alloc.ScratchXmm(code); + auto const src = ctx.reg_alloc.UseXmm(code, args[0]); + auto const dest = ctx.reg_alloc.ScratchXmm(code); + auto const reconstructed = ctx.reg_alloc.ScratchXmm(code); + auto const sign = ctx.reg_alloc.ScratchXmm(code); code.movdqa(dest, src); code.pxor(xmm0, xmm0); @@ -4577,9 +4864,9 @@ void EmitX64::EmitVectorSignedSaturatedNarrowToSigned64(EmitContext& ctx, IR::In static void EmitVectorSignedSaturatedNarrowToUnsigned(size_t original_esize, BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm src = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm dest = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm reconstructed = ctx.reg_alloc.ScratchXmm(code); + auto const src = ctx.reg_alloc.UseXmm(code, args[0]); + auto const dest = ctx.reg_alloc.ScratchXmm(code); + auto const reconstructed = ctx.reg_alloc.ScratchXmm(code); code.movdqa(dest, src); code.pxor(xmm0, xmm0); @@ -4647,9 +4934,9 @@ void EmitX64::EmitVectorSignedSaturatedNarrowToUnsigned64(EmitContext& ctx, IR:: static void EmitVectorSignedSaturatedNeg(size_t esize, BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm data = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm zero = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); + auto const data = ctx.reg_alloc.UseXmm(code, args[0]); + auto const zero = ctx.reg_alloc.ScratchXmm(code); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); const Xbyak::Address mask = [esize, &code] { switch (esize) { case 8: @@ -4665,7 +4952,7 @@ static void EmitVectorSignedSaturatedNeg(size_t esize, BlockOfCode& code, EmitCo } }(); - const auto vector_equality = [esize, &code](const Xbyak::Xmm& x, const auto& y) { + const auto vector_equality = [esize, &code](auto const& x, const auto& y) { switch (esize) { case 8: code.pcmpeqb(x, y); @@ -4810,33 +5097,23 @@ void EmitX64::EmitVectorSignedSaturatedShiftLeft64(EmitContext& ctx, IR::Inst* i EmitTwoArgumentFallbackWithSaturation(code, ctx, inst, VectorSignedSaturatedShiftLeft); } -template> +template static bool VectorSignedSaturatedShiftLeftUnsigned(VectorArray& dst, const VectorArray& data, u8 shift_amount) { + using U = std::make_unsigned_t; static_assert(std::is_signed_v, "T must be signed."); - bool qc_flag = false; for (size_t i = 0; i < dst.size(); i++) { - const T element = data[i]; - const T shift = static_cast(shift_amount); - - if (element == 0) { - dst[i] = 0; - } else if (element < 0) { - dst[i] = 0; - qc_flag = true; - } else { - const U shifted = static_cast(element) << static_cast(shift); - const U shifted_test = shifted >> static_cast(shift); - - if (shifted_test != static_cast(element)) { - dst[i] = static_cast((std::numeric_limits::max)()); - qc_flag = true; - } else { - dst[i] = shifted; - } - } + auto const element = data[i]; + auto const shifted = U(element) << U(T(shift_amount)); + auto const shifted_test = shifted >> U(T(shift_amount)); + auto result = 0; + if (element > 0 && shifted_test != U(element)) + result = T((std::numeric_limits::max)()); + if (element > 0 && shifted_test == U(element)) + result = shifted; + qc_flag |= element < 0 || (element > 0 && shifted_test != U(element)); + dst[i] = result; } - return qc_flag; } @@ -4849,7 +5126,97 @@ void EmitX64::EmitVectorSignedSaturatedShiftLeftUnsigned16(EmitContext& ctx, IR: } void EmitX64::EmitVectorSignedSaturatedShiftLeftUnsigned32(EmitContext& ctx, IR::Inst* inst) { - EmitTwoArgumentFallbackWithSaturationAndImmediate(code, ctx, inst, VectorSignedSaturatedShiftLeftUnsigned); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + auto const imm8 = args[1].GetImmediateU8(); + if (code.HasHostFeature(HostFeature::AVX2)) { + auto const tmp_flag = ctx.reg_alloc.ScratchGpr(code); + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + if (imm8 == 0) { + auto const tmp1 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + code.vpshufd(tmp1, tmp0, 85); + code.vpshufd(tmp2, tmp0, 238); + code.vpor(tmp1, tmp1, tmp2); + code.vpshufd(tmp2, tmp0, 255); + code.vpor(tmp2, tmp2, tmp0); + code.vpor(tmp1, tmp1, tmp2); + code.vmovd(tmp_flag.cvt32(), tmp1); + code.shr(tmp_flag.cvt32(), 31); + code.vpxor(tmp1, tmp1, tmp1); + code.vpmaxsd(tmp0, tmp0, tmp1); + } else { + auto const tmp1 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp3 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp4 = ctx.reg_alloc.ScratchXmm(code); + auto const cmp_value = u32(1ULL << 31) >> (imm8 - 1); + code.vpshufd(tmp1, tmp0, 238); + code.vpor(tmp1, tmp1, tmp0); + code.vpshufd(tmp2, tmp1, 85); + code.vpor(tmp1, tmp1, tmp2); + code.vmovd(tmp_flag.cvt32(), tmp1); + code.cmp(tmp_flag.cvt32(), cmp_value); + code.vpslld(tmp1, tmp0, imm8); + code.vpbroadcastd(tmp2, code.Const(dword, cmp_value - 2)); + code.vpbroadcastd(tmp3, code.Const(dword, cmp_value - 1)); + code.vpcmpgtd(tmp3, tmp0, tmp3); + code.vpcmpeqd(tmp4, tmp4, tmp4); + code.vpaddd(tmp0, tmp0, tmp4); + code.vpminud(tmp2, tmp0, tmp2); + code.vpcmpeqd(tmp0, tmp0, tmp2); + code.vblendvps(tmp0, tmp3, tmp1, tmp0); + code.setae(tmp_flag.cvt8()); + } + code.or_(code.byte[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], tmp_flag.cvt8()); + ctx.reg_alloc.DefineValue(code, inst, tmp0); + } else { + auto const tmp_flag = ctx.reg_alloc.ScratchGpr(code); + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + if (imm8 == 0) { + auto const tmp1 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + code.pshufd(tmp1, tmp0, 85); + code.pshufd(tmp2, tmp0, 238); + code.por(tmp2, tmp1); + code.pshufd(tmp1, tmp0, 255); + code.por(tmp1, tmp0); + code.por(tmp1, tmp2); + code.movd(tmp_flag.cvt32(), tmp1); + code.shr(tmp_flag.cvt32(), 31); + code.pxor(tmp1, tmp1); + code.movdqa(tmp2, tmp0); + code.pcmpgtd(tmp2, tmp1); + code.pand(tmp0, tmp2); + } else { + auto const tmp1 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp3 = ctx.reg_alloc.ScratchXmm(code); + u64 const cmp_value = u64(1ULL << 31) >> (imm8 - 1); + u64 const cmp_one = cmp_value - 1; + u64 const cmp_add = (cmp_value - 2) + 0x80000000; + code.pshufd(tmp1, tmp0, 238); + code.por(tmp1, tmp0); + code.pshufd(tmp2, tmp1, 85); + code.por(tmp2, tmp1); + code.movd(tmp_flag.cvt32(), tmp2); + code.cmp(tmp_flag.cvt32(), cmp_value); + code.movdqa(tmp1, tmp0); + code.pslld(tmp1, imm8); + code.movdqa(tmp2, tmp0); + code.pcmpgtd(tmp2, code.Const(xword, cmp_one | (cmp_one << 32), cmp_one | (cmp_one << 32))); + code.pcmpeqd(tmp3, tmp3); + code.paddd(tmp0, tmp3); + code.pxor(tmp0, code.Const(xword, 0x80000000'80000000, 0x80000000'80000000)); + code.pcmpgtd(tmp0, code.Const(xword, cmp_add | (cmp_add << 32), cmp_add | (cmp_add << 32))); + code.pand(tmp2, tmp0); + code.pandn(tmp0, tmp1); + code.por(tmp0, tmp2); + code.setae(tmp_flag.cvt8()); + } + code.or_(code.byte[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_qc], tmp_flag.cvt8()); + ctx.reg_alloc.DefineValue(code, inst, tmp0); +// EmitTwoArgumentFallbackWithSaturationAndImmediate(code, ctx, inst, VectorSignedSaturatedShiftLeftUnsigned); + } } void EmitX64::EmitVectorSignedSaturatedShiftLeftUnsigned64(EmitContext& ctx, IR::Inst* inst) { @@ -4887,7 +5254,7 @@ void EmitX64::EmitVectorTableLookup64(EmitContext& ctx, IR::Inst* inst) { const bool is_defaults_zero = inst->GetArg(0).IsZero(); if (code.HasHostFeature(HostFeature::AVX512_Ortho | HostFeature::AVX512BW | HostFeature::AVX512VBMI)) { - const Xbyak::Xmm indicies = table_size <= 2 ? ctx.reg_alloc.UseXmm(code, args[2]) : ctx.reg_alloc.UseScratchXmm(code, args[2]); + auto const indicies = table_size <= 2 ? ctx.reg_alloc.UseXmm(code, args[2]) : ctx.reg_alloc.UseScratchXmm(code, args[2]); const u64 index_count = mcl::bit::replicate_element(static_cast(table_size * 8)); @@ -4895,43 +5262,43 @@ void EmitX64::EmitVectorTableLookup64(EmitContext& ctx, IR::Inst* inst) { switch (table_size) { case 1: { - const Xbyak::Xmm xmm_table0 = ctx.reg_alloc.UseXmm(code, table[0]); + auto const xmm_table0 = ctx.reg_alloc.UseXmm(code, table[0]); if (is_defaults_zero) { - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const result = ctx.reg_alloc.ScratchXmm(code); code.vpermb(result | k1 | T_z, indicies, xmm_table0); ctx.reg_alloc.DefineValue(code, inst, result); } else { - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.vpermb(result | k1, indicies, xmm_table0); ctx.reg_alloc.DefineValue(code, inst, result); } break; } case 2: { - const Xbyak::Xmm xmm_table0_lower = ctx.reg_alloc.UseXmm(code, table[0]); - const Xbyak::Xmm xmm_table0_upper = ctx.reg_alloc.UseXmm(code, table[1]); + auto const xmm_table0_lower = ctx.reg_alloc.UseXmm(code, table[0]); + auto const xmm_table0_upper = ctx.reg_alloc.UseXmm(code, table[1]); code.vpunpcklqdq(xmm0, xmm_table0_lower, xmm_table0_upper); if (is_defaults_zero) { - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const result = ctx.reg_alloc.ScratchXmm(code); code.vpermb(result | k1 | T_z, indicies, xmm0); ctx.reg_alloc.DefineValue(code, inst, result); } else { - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.vpermb(result | k1, indicies, xmm0); ctx.reg_alloc.DefineValue(code, inst, result); } break; } case 3: { - const Xbyak::Xmm xmm_table0_lower = ctx.reg_alloc.UseXmm(code, table[0]); - const Xbyak::Xmm xmm_table0_upper = ctx.reg_alloc.UseXmm(code, table[1]); - const Xbyak::Xmm xmm_table1 = ctx.reg_alloc.UseXmm(code, table[2]); + auto const xmm_table0_lower = ctx.reg_alloc.UseXmm(code, table[0]); + auto const xmm_table0_upper = ctx.reg_alloc.UseXmm(code, table[1]); + auto const xmm_table1 = ctx.reg_alloc.UseXmm(code, table[2]); code.vpunpcklqdq(xmm0, xmm_table0_lower, xmm_table0_upper); if (is_defaults_zero) { code.vpermi2b(indicies | k1 | T_z, xmm0, xmm_table1); ctx.reg_alloc.DefineValue(code, inst, indicies); } else { - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.vpermi2b(indicies, xmm0, xmm_table1); code.vmovdqu8(result | k1, indicies); ctx.reg_alloc.DefineValue(code, inst, result); @@ -4939,17 +5306,17 @@ void EmitX64::EmitVectorTableLookup64(EmitContext& ctx, IR::Inst* inst) { break; } case 4: { - const Xbyak::Xmm xmm_table0_lower = ctx.reg_alloc.UseXmm(code, table[0]); - const Xbyak::Xmm xmm_table0_upper = ctx.reg_alloc.UseXmm(code, table[1]); - const Xbyak::Xmm xmm_table1 = ctx.reg_alloc.UseScratchXmm(code, table[2]); - const Xbyak::Xmm xmm_table1_upper = ctx.reg_alloc.UseXmm(code, table[3]); + auto const xmm_table0_lower = ctx.reg_alloc.UseXmm(code, table[0]); + auto const xmm_table0_upper = ctx.reg_alloc.UseXmm(code, table[1]); + auto const xmm_table1 = ctx.reg_alloc.UseScratchXmm(code, table[2]); + auto const xmm_table1_upper = ctx.reg_alloc.UseXmm(code, table[3]); code.vpunpcklqdq(xmm0, xmm_table0_lower, xmm_table0_upper); code.vpunpcklqdq(xmm_table1, xmm_table1, xmm_table1_upper); if (is_defaults_zero) { code.vpermi2b(indicies | k1 | T_z, xmm0, xmm_table1); ctx.reg_alloc.DefineValue(code, inst, indicies); } else { - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.vpermi2b(indicies, xmm0, xmm_table1); code.vmovdqu8(result | k1, indicies); ctx.reg_alloc.DefineValue(code, inst, result); @@ -4972,9 +5339,9 @@ void EmitX64::EmitVectorTableLookup64(EmitContext& ctx, IR::Inst* inst) { }; if (code.HasHostFeature(HostFeature::SSSE3) && is_defaults_zero && table_size == 1) { - const Xbyak::Xmm indicies = ctx.reg_alloc.UseScratchXmm(code, args[2]); - const Xbyak::Xmm xmm_table0 = ctx.reg_alloc.UseXmm(code, table[0]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const indicies = ctx.reg_alloc.UseScratchXmm(code, args[2]); + auto const xmm_table0 = ctx.reg_alloc.UseXmm(code, table[0]); + auto const result = ctx.reg_alloc.ScratchXmm(code); code.xorps(result, result); code.movsd(result, xmm_table0); @@ -4986,9 +5353,9 @@ void EmitX64::EmitVectorTableLookup64(EmitContext& ctx, IR::Inst* inst) { } if (code.HasHostFeature(HostFeature::SSSE3) && is_defaults_zero && table_size == 2) { - const Xbyak::Xmm indicies = ctx.reg_alloc.UseScratchXmm(code, args[2]); - const Xbyak::Xmm xmm_table0 = ctx.reg_alloc.UseScratchXmm(code, table[0]); - const Xbyak::Xmm xmm_table0_upper = ctx.reg_alloc.UseXmm(code, table[1]); + auto const indicies = ctx.reg_alloc.UseScratchXmm(code, args[2]); + auto const xmm_table0 = ctx.reg_alloc.UseScratchXmm(code, table[0]); + auto const xmm_table0_upper = ctx.reg_alloc.UseXmm(code, table[1]); code.punpcklqdq(xmm_table0, xmm_table0_upper); code.paddusb(indicies, code.Const(xword, 0x7070707070707070, 0xFFFFFFFFFFFFFFFF)); @@ -4999,12 +5366,12 @@ void EmitX64::EmitVectorTableLookup64(EmitContext& ctx, IR::Inst* inst) { } if (code.HasHostFeature(HostFeature::SSE41) && table_size <= 2) { - const Xbyak::Xmm indicies = ctx.reg_alloc.UseXmm(code, args[2]); - const Xbyak::Xmm defaults = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm xmm_table0 = ctx.reg_alloc.UseScratchXmm(code, table[0]); + auto const indicies = ctx.reg_alloc.UseXmm(code, args[2]); + auto const defaults = ctx.reg_alloc.UseXmm(code, args[0]); + auto const xmm_table0 = ctx.reg_alloc.UseScratchXmm(code, table[0]); if (table_size == 2) { - const Xbyak::Xmm xmm_table0_upper = ctx.reg_alloc.UseXmm(code, table[1]); + auto const xmm_table0_upper = ctx.reg_alloc.UseXmm(code, table[1]); code.punpcklqdq(xmm_table0, xmm_table0_upper); ctx.reg_alloc.Release(xmm_table0_upper); } @@ -5023,12 +5390,12 @@ void EmitX64::EmitVectorTableLookup64(EmitContext& ctx, IR::Inst* inst) { } if (code.HasHostFeature(HostFeature::SSE41) && is_defaults_zero) { - const Xbyak::Xmm indicies = ctx.reg_alloc.UseScratchXmm(code, args[2]); - const Xbyak::Xmm xmm_table0 = ctx.reg_alloc.UseScratchXmm(code, table[0]); - const Xbyak::Xmm xmm_table1 = ctx.reg_alloc.UseScratchXmm(code, table[2]); + auto const indicies = ctx.reg_alloc.UseScratchXmm(code, args[2]); + auto const xmm_table0 = ctx.reg_alloc.UseScratchXmm(code, table[0]); + auto const xmm_table1 = ctx.reg_alloc.UseScratchXmm(code, table[2]); { - const Xbyak::Xmm xmm_table0_upper = ctx.reg_alloc.UseXmm(code, table[1]); + auto const xmm_table0_upper = ctx.reg_alloc.UseXmm(code, table[1]); code.punpcklqdq(xmm_table0, xmm_table0_upper); ctx.reg_alloc.Release(xmm_table0_upper); } @@ -5037,7 +5404,7 @@ void EmitX64::EmitVectorTableLookup64(EmitContext& ctx, IR::Inst* inst) { code.punpcklqdq(xmm_table1, xmm0); } else { ASSERT(table_size == 4); - const Xbyak::Xmm xmm_table1_upper = ctx.reg_alloc.UseXmm(code, table[3]); + auto const xmm_table1_upper = ctx.reg_alloc.UseXmm(code, table[3]); code.punpcklqdq(xmm_table1, xmm_table1_upper); ctx.reg_alloc.Release(xmm_table1_upper); } @@ -5058,18 +5425,18 @@ void EmitX64::EmitVectorTableLookup64(EmitContext& ctx, IR::Inst* inst) { } if (code.HasHostFeature(HostFeature::SSE41)) { - const Xbyak::Xmm indicies = ctx.reg_alloc.UseScratchXmm(code, args[2]); - const Xbyak::Xmm defaults = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm xmm_table0 = ctx.reg_alloc.UseScratchXmm(code, table[0]); - const Xbyak::Xmm xmm_table1 = ctx.reg_alloc.UseScratchXmm(code, table[2]); + auto const indicies = ctx.reg_alloc.UseScratchXmm(code, args[2]); + auto const defaults = ctx.reg_alloc.UseXmm(code, args[0]); + auto const xmm_table0 = ctx.reg_alloc.UseScratchXmm(code, table[0]); + auto const xmm_table1 = ctx.reg_alloc.UseScratchXmm(code, table[2]); { - const Xbyak::Xmm xmm_table0_upper = ctx.reg_alloc.UseXmm(code, table[1]); + auto const xmm_table0_upper = ctx.reg_alloc.UseXmm(code, table[1]); code.punpcklqdq(xmm_table0, xmm_table0_upper); ctx.reg_alloc.Release(xmm_table0_upper); } if (table_size == 4) { - const Xbyak::Xmm xmm_table1_upper = ctx.reg_alloc.UseXmm(code, table[3]); + auto const xmm_table1_upper = ctx.reg_alloc.UseXmm(code, table[3]); code.punpcklqdq(xmm_table1, xmm_table1_upper); ctx.reg_alloc.Release(xmm_table1_upper); } @@ -5098,37 +5465,31 @@ void EmitX64::EmitVectorTableLookup64(EmitContext& ctx, IR::Inst* inst) { const u32 stack_space = static_cast(6 * 8); ctx.reg_alloc.AllocStackSpace(code, stack_space + ABI_SHADOW_SPACE); for (size_t i = 0; i < table_size; ++i) { - const Xbyak::Xmm table_value = ctx.reg_alloc.UseXmm(code, table[i]); + auto const table_value = ctx.reg_alloc.UseXmm(code, table[i]); code.movq(qword[rsp + ABI_SHADOW_SPACE + i * 8], table_value); ctx.reg_alloc.Release(table_value); } - const Xbyak::Xmm defaults = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm indicies = ctx.reg_alloc.UseXmm(code, args[2]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const defaults = ctx.reg_alloc.UseXmm(code, args[0]); + auto const indicies = ctx.reg_alloc.UseXmm(code, args[2]); + auto const result = ctx.reg_alloc.ScratchXmm(code); ctx.reg_alloc.EndOfAllocScope(); ctx.reg_alloc.HostCall(code, nullptr); - code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE]); code.lea(code.ABI_PARAM2, ptr[rsp + ABI_SHADOW_SPACE + 4 * 8]); code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE + 5 * 8]); code.mov(code.ABI_PARAM4.cvt32(), table_size); code.movq(qword[code.ABI_PARAM2], defaults); code.movq(qword[code.ABI_PARAM3], indicies); - - code.CallLambda( - [](const HalfVectorArray* table, HalfVectorArray& result, const HalfVectorArray& indicies, size_t table_size) { - for (size_t i = 0; i < result.size(); ++i) { - const size_t index = indicies[i] / table[0].size(); - const size_t elem = indicies[i] % table[0].size(); - if (index < table_size) { - result[i] = table[index][elem]; - } - } - }); - + code.CallLambda([](const HalfVectorArray* table, HalfVectorArray& result, const HalfVectorArray& indicies, size_t table_size) { + for (size_t i = 0; i < result.size(); ++i) { + const size_t index = indicies[i] / table[0].size(); + const size_t elem = indicies[i] % table[0].size(); + if (index < table_size) + result[i] = table[index][elem]; + } + }); code.movq(result, qword[rsp + ABI_SHADOW_SPACE + 4 * 8]); ctx.reg_alloc.ReleaseStackSpace(code, stack_space + ABI_SHADOW_SPACE); - ctx.reg_alloc.DefineValue(code, inst, result); } @@ -5142,14 +5503,14 @@ void EmitX64::EmitVectorTableLookup128(EmitContext& ctx, IR::Inst* inst) { const bool is_defaults_zero = !inst->GetArg(0).IsImmediate() && inst->GetArg(0).GetInst()->GetOpcode() == IR::Opcode::ZeroVector; if (code.HasHostFeature(HostFeature::AVX512_Ortho | HostFeature::AVX512BW | HostFeature::AVX512VBMI) && table_size == 4) { - const Xbyak::Xmm indicies = ctx.reg_alloc.UseScratchXmm(code, args[2]); + auto const indicies = ctx.reg_alloc.UseScratchXmm(code, args[2]); code.vpcmpub(k1, indicies, code.BConst<8>(xword, 2 * 16), CmpInt::LessThan); code.vpcmpub(k2, indicies, code.BConst<8>(xword, 4 * 16), CmpInt::LessThan); // Handle vector-table 0,1 - const Xbyak::Xmm xmm_table0 = ctx.reg_alloc.UseXmm(code, table[0]); - const Xbyak::Xmm xmm_table1 = ctx.reg_alloc.UseXmm(code, table[1]); + auto const xmm_table0 = ctx.reg_alloc.UseXmm(code, table[0]); + auto const xmm_table1 = ctx.reg_alloc.UseXmm(code, table[1]); code.vpermi2b(indicies | k1, xmm_table0, xmm_table1); @@ -5157,8 +5518,8 @@ void EmitX64::EmitVectorTableLookup128(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.Release(xmm_table1); // Handle vector-table 2,3 - const Xbyak::Xmm xmm_table2 = ctx.reg_alloc.UseXmm(code, table[2]); - const Xbyak::Xmm xmm_table3 = ctx.reg_alloc.UseXmm(code, table[3]); + auto const xmm_table2 = ctx.reg_alloc.UseXmm(code, table[2]); + auto const xmm_table3 = ctx.reg_alloc.UseXmm(code, table[3]); code.kandnw(k1, k1, k2); code.vpermi2b(indicies | k1, xmm_table2, xmm_table3); @@ -5167,19 +5528,19 @@ void EmitX64::EmitVectorTableLookup128(EmitContext& ctx, IR::Inst* inst) { code.vmovdqu8(indicies | k2 | T_z, indicies); ctx.reg_alloc.DefineValue(code, inst, indicies); } else { - const Xbyak::Xmm defaults = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const defaults = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.vmovdqu8(defaults | k2, indicies); ctx.reg_alloc.DefineValue(code, inst, defaults); } } else if (code.HasHostFeature(HostFeature::AVX512_Ortho | HostFeature::AVX512BW | HostFeature::AVX512VBMI) && table_size == 3) { - const Xbyak::Xmm indicies = ctx.reg_alloc.UseScratchXmm(code, args[2]); + auto const indicies = ctx.reg_alloc.UseScratchXmm(code, args[2]); code.vpcmpub(k1, indicies, code.BConst<8>(xword, 2 * 16), CmpInt::LessThan); code.vpcmpub(k2, indicies, code.BConst<8>(xword, 3 * 16), CmpInt::LessThan); // Handle vector-table 0,1 - const Xbyak::Xmm xmm_table0 = ctx.reg_alloc.UseXmm(code, table[0]); - const Xbyak::Xmm xmm_table1 = ctx.reg_alloc.UseXmm(code, table[1]); + auto const xmm_table0 = ctx.reg_alloc.UseXmm(code, table[0]); + auto const xmm_table1 = ctx.reg_alloc.UseXmm(code, table[1]); code.vpermi2b(indicies | k1, xmm_table0, xmm_table1); @@ -5187,7 +5548,7 @@ void EmitX64::EmitVectorTableLookup128(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.Release(xmm_table1); // Handle vector-table 2 - const Xbyak::Xmm xmm_table2 = ctx.reg_alloc.UseXmm(code, table[2]); + auto const xmm_table2 = ctx.reg_alloc.UseXmm(code, table[2]); code.kandnw(k1, k1, k2); code.vpermb(indicies | k1, indicies, xmm_table2); @@ -5196,14 +5557,14 @@ void EmitX64::EmitVectorTableLookup128(EmitContext& ctx, IR::Inst* inst) { code.vmovdqu8(indicies | k2 | T_z, indicies); ctx.reg_alloc.DefineValue(code, inst, indicies); } else { - const Xbyak::Xmm defaults = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const defaults = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.vmovdqu8(defaults | k2, indicies); ctx.reg_alloc.DefineValue(code, inst, defaults); } } else if (code.HasHostFeature(HostFeature::AVX512_Ortho | HostFeature::AVX512BW | HostFeature::AVX512VBMI) && table_size == 2) { - const Xbyak::Xmm indicies = ctx.reg_alloc.UseScratchXmm(code, args[2]); - const Xbyak::Xmm xmm_table0 = ctx.reg_alloc.UseXmm(code, table[0]); - const Xbyak::Xmm xmm_table1 = ctx.reg_alloc.UseXmm(code, table[1]); + auto const indicies = ctx.reg_alloc.UseScratchXmm(code, args[2]); + auto const xmm_table0 = ctx.reg_alloc.UseXmm(code, table[0]); + auto const xmm_table1 = ctx.reg_alloc.UseXmm(code, table[1]); code.vpcmpub(k1, indicies, code.BConst<8>(xword, 2 * 16), CmpInt::LessThan); @@ -5211,36 +5572,36 @@ void EmitX64::EmitVectorTableLookup128(EmitContext& ctx, IR::Inst* inst) { code.vpermi2b(indicies | k1 | T_z, xmm_table0, xmm_table1); ctx.reg_alloc.DefineValue(code, inst, indicies); } else { - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.vpermi2b(indicies, xmm_table0, xmm_table1); code.vmovdqu8(result | k1, indicies); ctx.reg_alloc.DefineValue(code, inst, result); } } else if (code.HasHostFeature(HostFeature::AVX512_Ortho | HostFeature::AVX512BW | HostFeature::AVX512VBMI) && table_size == 1) { - const Xbyak::Xmm indicies = ctx.reg_alloc.UseXmm(code, args[2]); - const Xbyak::Xmm xmm_table0 = ctx.reg_alloc.UseXmm(code, table[0]); + auto const indicies = ctx.reg_alloc.UseXmm(code, args[2]); + auto const xmm_table0 = ctx.reg_alloc.UseXmm(code, table[0]); code.vpcmpub(k1, indicies, code.BConst<8>(xword, 1 * 16), CmpInt::LessThan); if (is_defaults_zero) { - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const result = ctx.reg_alloc.ScratchXmm(code); code.vpermb(result | k1 | T_z, indicies, xmm_table0); ctx.reg_alloc.DefineValue(code, inst, result); } else { - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.vpermb(result | k1, indicies, xmm_table0); ctx.reg_alloc.DefineValue(code, inst, result); } } else if (code.HasHostFeature(HostFeature::SSSE3) && is_defaults_zero && table_size == 1) { - const Xbyak::Xmm indicies = ctx.reg_alloc.UseScratchXmm(code, args[2]); - const Xbyak::Xmm xmm_table0 = ctx.reg_alloc.UseScratchXmm(code, table[0]); + auto const indicies = ctx.reg_alloc.UseScratchXmm(code, args[2]); + auto const xmm_table0 = ctx.reg_alloc.UseScratchXmm(code, table[0]); code.paddusb(indicies, code.Const(xword, 0x7070707070707070, 0x7070707070707070)); code.pshufb(xmm_table0, indicies); ctx.reg_alloc.DefineValue(code, inst, xmm_table0); } else if (code.HasHostFeature(HostFeature::SSE41) && table_size == 1) { - const Xbyak::Xmm indicies = ctx.reg_alloc.UseXmm(code, args[2]); - const Xbyak::Xmm defaults = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm xmm_table0 = ctx.reg_alloc.UseScratchXmm(code, table[0]); + auto const indicies = ctx.reg_alloc.UseXmm(code, args[2]); + auto const defaults = ctx.reg_alloc.UseXmm(code, args[0]); + auto const xmm_table0 = ctx.reg_alloc.UseScratchXmm(code, table[0]); if (code.HasHostFeature(HostFeature::AVX)) { code.vpaddusb(xmm0, indicies, code.Const(xword, 0x7070707070707070, 0x7070707070707070)); @@ -5253,9 +5614,9 @@ void EmitX64::EmitVectorTableLookup128(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.DefineValue(code, inst, xmm_table0); } else if (code.HasHostFeature(HostFeature::SSE41) && is_defaults_zero && table_size == 2) { - const Xbyak::Xmm indicies = ctx.reg_alloc.UseScratchXmm(code, args[2]); - const Xbyak::Xmm xmm_table0 = ctx.reg_alloc.UseScratchXmm(code, table[0]); - const Xbyak::Xmm xmm_table1 = ctx.reg_alloc.UseScratchXmm(code, table[1]); + auto const indicies = ctx.reg_alloc.UseScratchXmm(code, args[2]); + auto const xmm_table0 = ctx.reg_alloc.UseScratchXmm(code, table[0]); + auto const xmm_table1 = ctx.reg_alloc.UseScratchXmm(code, table[1]); if (code.HasHostFeature(HostFeature::AVX)) { code.vpaddusb(xmm0, indicies, code.Const(xword, 0x7070707070707070, 0x7070707070707070)); @@ -5271,14 +5632,14 @@ void EmitX64::EmitVectorTableLookup128(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.DefineValue(code, inst, xmm_table0); return; } else if (code.HasHostFeature(HostFeature::AVX512_Ortho | HostFeature::AVX512BW)) { - const Xbyak::Xmm indicies = ctx.reg_alloc.UseXmm(code, args[2]); - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm masked = ctx.reg_alloc.ScratchXmm(code); + auto const indicies = ctx.reg_alloc.UseXmm(code, args[2]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const masked = ctx.reg_alloc.ScratchXmm(code); code.vpandd(masked, indicies, code.Const(xword_b, 0xF0F0F0F0F0F0F0F0, 0xF0F0F0F0F0F0F0F0)); for (size_t i = 0; i < table_size; ++i) { - const Xbyak::Xmm xmm_table = ctx.reg_alloc.UseScratchXmm(code, table[i]); + auto const xmm_table = ctx.reg_alloc.UseScratchXmm(code, table[i]); const Xbyak::Opmask table_mask = k1; const u64 table_index = mcl::bit::replicate_element(i * 16); @@ -5295,15 +5656,15 @@ void EmitX64::EmitVectorTableLookup128(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.DefineValue(code, inst, result); } else if (code.HasHostFeature(HostFeature::SSE41)) { - const Xbyak::Xmm indicies = ctx.reg_alloc.UseXmm(code, args[2]); - const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm masked = ctx.reg_alloc.ScratchXmm(code); + auto const indicies = ctx.reg_alloc.UseXmm(code, args[2]); + auto const result = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const masked = ctx.reg_alloc.ScratchXmm(code); code.movaps(masked, code.Const(xword, 0xF0F0F0F0F0F0F0F0, 0xF0F0F0F0F0F0F0F0)); code.pand(masked, indicies); for (size_t i = 0; i < table_size; ++i) { - const Xbyak::Xmm xmm_table = ctx.reg_alloc.UseScratchXmm(code, table[i]); + auto const xmm_table = ctx.reg_alloc.UseScratchXmm(code, table[i]); const u64 table_index = mcl::bit::replicate_element(i * 16); @@ -5327,13 +5688,13 @@ void EmitX64::EmitVectorTableLookup128(EmitContext& ctx, IR::Inst* inst) { const u32 stack_space = static_cast((table_size + 2) * 16); ctx.reg_alloc.AllocStackSpace(code, stack_space + ABI_SHADOW_SPACE); for (size_t i = 0; i < table_size; ++i) { - const Xbyak::Xmm table_value = ctx.reg_alloc.UseXmm(code, table[i]); + auto const table_value = ctx.reg_alloc.UseXmm(code, table[i]); code.movaps(xword[rsp + ABI_SHADOW_SPACE + i * 16], table_value); ctx.reg_alloc.Release(table_value); } - const Xbyak::Xmm defaults = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm indicies = ctx.reg_alloc.UseXmm(code, args[2]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const defaults = ctx.reg_alloc.UseXmm(code, args[0]); + auto const indicies = ctx.reg_alloc.UseXmm(code, args[2]); + auto const result = ctx.reg_alloc.ScratchXmm(code); ctx.reg_alloc.EndOfAllocScope(); ctx.reg_alloc.HostCall(code, nullptr); code.lea(code.ABI_PARAM1, ptr[rsp + ABI_SHADOW_SPACE]); @@ -5360,8 +5721,8 @@ void EmitX64::EmitVectorTableLookup128(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorTranspose8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm lower = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm upper = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const lower = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const upper = ctx.reg_alloc.UseScratchXmm(code, args[1]); const bool part = args[2].GetImmediateU1(); if (!part) { @@ -5379,8 +5740,8 @@ void EmitX64::EmitVectorTranspose8(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorTranspose16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm lower = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm upper = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const lower = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const upper = ctx.reg_alloc.UseScratchXmm(code, args[1]); const bool part = args[2].GetImmediateU1(); if (!part) { @@ -5398,8 +5759,8 @@ void EmitX64::EmitVectorTranspose16(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorTranspose32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm lower = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm upper = ctx.reg_alloc.UseXmm(code, args[1]); + auto const lower = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const upper = ctx.reg_alloc.UseXmm(code, args[1]); const bool part = args[2].GetImmediateU1(); code.shufps(lower, upper, !part ? 0b10001000 : 0b11011101); @@ -5411,8 +5772,8 @@ void EmitX64::EmitVectorTranspose32(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorTranspose64(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm lower = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm upper = ctx.reg_alloc.UseXmm(code, args[1]); + auto const lower = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const upper = ctx.reg_alloc.UseXmm(code, args[1]); const bool part = args[2].GetImmediateU1(); code.shufpd(lower, upper, !part ? 0b00 : 0b11); @@ -5420,89 +5781,87 @@ void EmitX64::EmitVectorTranspose64(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.DefineValue(code, inst, lower); } -static void EmitVectorUnsignedAbsoluteDifference(size_t esize, EmitContext& ctx, IR::Inst* inst, BlockOfCode& code) { + +void EmitX64::EmitVectorUnsignedAbsoluteDifference8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - - const Xbyak::Xmm temp = ctx.reg_alloc.ScratchXmm(code); - - switch (esize) { - case 8: { - const Xbyak::Xmm x = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(code, args[1]); - + if (code.HasHostFeature(HostFeature::AVX)) { + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + code.vpminub(tmp2, tmp0, tmp1); + code.vpmaxub(tmp0, tmp0, tmp1); + code.vpsubb(tmp0, tmp0, tmp2); + ctx.reg_alloc.DefineValue(code, inst, tmp0); + } else { + auto const temp = ctx.reg_alloc.ScratchXmm(code); + auto const x = ctx.reg_alloc.UseXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); code.movdqa(temp, x); code.psubusb(temp, y); code.psubusb(y, x); code.por(temp, y); - break; + ctx.reg_alloc.DefineValue(code, inst, temp); } - case 16: { - const Xbyak::Xmm x = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(code, args[1]); +} +void EmitX64::EmitVectorUnsignedAbsoluteDifference16(EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + if (code.HasHostFeature(HostFeature::AVX)) { + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + code.vpminuw(tmp2, tmp0, tmp1); + code.vpmaxuw(tmp0, tmp0, tmp1); + code.vpsubw(tmp0, tmp0, tmp2); + ctx.reg_alloc.DefineValue(code, inst, tmp0); + } else { + auto const temp = ctx.reg_alloc.ScratchXmm(code); + auto const x = ctx.reg_alloc.UseXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); code.movdqa(temp, x); code.psubusw(temp, y); code.psubusw(y, x); code.por(temp, y); - break; + ctx.reg_alloc.DefineValue(code, inst, temp); } - case 32: - // See https://stackoverflow.com/questions/3380785/compute-the-absolute-difference-between-unsigned-integers-using-sse/3527267#3527267 - if (code.HasHostFeature(HostFeature::SSE41)) { - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseXmm(code, args[1]); - - code.movdqa(temp, x); - code.pminud(x, y); - code.pmaxud(temp, y); - code.psubd(temp, x); - } else { - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(code, args[1]); - if (ctx.HasOptimization(OptimizationFlag::CodeSpeed)) { - // About 45 bytes - const Xbyak::Xmm temp_x = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm temp_y = ctx.reg_alloc.ScratchXmm(code); - code.pcmpeqd(temp, temp); - code.pslld(temp, 31); - code.movdqa(temp_x, x); - code.movdqa(temp_y, y); - code.paddd(temp_x, x); - code.paddd(temp_y, y); - code.pcmpgtd(temp_y, temp_x); - code.psubd(x, y); - code.pandn(temp, temp_y); - code.pxor(x, y); - code.psubd(x, y); - } else { - // Smaller code size - about 36 bytes - code.movdqa(temp, code.Const(xword, 0x8000000080000000, 0x8000000080000000)); - code.pxor(x, temp); - code.pxor(y, temp); - code.movdqa(temp, x); - code.psubd(temp, y); - code.pcmpgtd(y, x); - code.psrld(y, 1); - code.pxor(temp, y); - code.psubd(temp, y); - } - } - break; - } - - ctx.reg_alloc.DefineValue(code, inst, temp); -} - -void EmitX64::EmitVectorUnsignedAbsoluteDifference8(EmitContext& ctx, IR::Inst* inst) { - EmitVectorUnsignedAbsoluteDifference(8, ctx, inst, code); -} - -void EmitX64::EmitVectorUnsignedAbsoluteDifference16(EmitContext& ctx, IR::Inst* inst) { - EmitVectorUnsignedAbsoluteDifference(16, ctx, inst, code); } void EmitX64::EmitVectorUnsignedAbsoluteDifference32(EmitContext& ctx, IR::Inst* inst) { - EmitVectorUnsignedAbsoluteDifference(32, ctx, inst, code); + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + if (code.HasHostFeature(HostFeature::AVX)) { + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + code.vpminud(tmp2, tmp0, tmp1); + code.vpmaxud(tmp0, tmp0, tmp1); + code.vpsubd(tmp0, tmp0, tmp2); + ctx.reg_alloc.DefineValue(code, inst, tmp0); + } else if (code.HasHostFeature(HostFeature::SSE41)) { + // See https://stackoverflow.com/questions/3380785/compute-the-absolute-difference-between-unsigned-integers-using-sse/3527267#3527267 + auto const temp = ctx.reg_alloc.ScratchXmm(code); + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseXmm(code, args[1]); + code.movdqa(temp, x); + code.pminud(x, y); + code.pmaxud(temp, y); + code.psubd(temp, x); + ctx.reg_alloc.DefineValue(code, inst, temp); + } else { + auto const tmp0 = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const tmp1 = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp2 = ctx.reg_alloc.ScratchXmm(code); + auto const tmp3 = ctx.reg_alloc.ScratchXmm(code); + code.movdqa(tmp2, code.Const(xword, 0x8000'00008000'0000, 0x8000'00008000'0000)); + code.movdqa(tmp3, tmp1); + code.pxor(tmp3, tmp2); + code.pxor(tmp2, tmp0); + code.pcmpgtd(tmp2, tmp3); + code.psubd(tmp0, tmp1); + code.pxor(tmp0, tmp2); + code.psubd(tmp2, tmp0); + //code.movdqa(tmp0, tmp2); + ctx.reg_alloc.DefineValue(code, inst, tmp2); + } } void EmitX64::EmitVectorUnsignedMultiply16(EmitContext& ctx, IR::Inst* inst) { @@ -5510,11 +5869,11 @@ void EmitX64::EmitVectorUnsignedMultiply16(EmitContext& ctx, IR::Inst* inst) { const auto lower_inst = inst->GetAssociatedPseudoOperation(IR::Opcode::GetLowerFromOp); auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm x = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseXmm(code, args[1]); + auto const x = ctx.reg_alloc.UseXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseXmm(code, args[1]); if (upper_inst) { - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const result = ctx.reg_alloc.ScratchXmm(code); if (code.HasHostFeature(HostFeature::AVX)) { code.vpmulhuw(result, x, y); } else { @@ -5526,7 +5885,7 @@ void EmitX64::EmitVectorUnsignedMultiply16(EmitContext& ctx, IR::Inst* inst) { } if (lower_inst) { - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const result = ctx.reg_alloc.ScratchXmm(code); if (code.HasHostFeature(HostFeature::AVX)) { code.vpmullw(result, x, y); } else { @@ -5544,24 +5903,24 @@ void EmitX64::EmitVectorUnsignedMultiply32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (lower_inst && !upper_inst && code.HasHostFeature(HostFeature::AVX)) { - const Xbyak::Xmm x = ctx.reg_alloc.UseXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseXmm(code, args[1]); - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const x = ctx.reg_alloc.UseXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseXmm(code, args[1]); + auto const result = ctx.reg_alloc.ScratchXmm(code); code.vpmulld(result, x, y); ctx.reg_alloc.DefineValue(code, lower_inst, result); } else if (code.HasHostFeature(HostFeature::AVX)) { - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); if (lower_inst) { - const Xbyak::Xmm lower_result = ctx.reg_alloc.ScratchXmm(code); + auto const lower_result = ctx.reg_alloc.ScratchXmm(code); code.vpmulld(lower_result, x, y); ctx.reg_alloc.DefineValue(code, lower_inst, lower_result); } - const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm(code); + auto const result = ctx.reg_alloc.ScratchXmm(code); code.vpmuludq(result, x, y); code.vpsrlq(x, x, 32); @@ -5571,11 +5930,11 @@ void EmitX64::EmitVectorUnsignedMultiply32(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.DefineValue(code, upper_inst, result); } else { - const Xbyak::Xmm x = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm y = ctx.reg_alloc.UseScratchXmm(code, args[1]); - const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm(code); - const Xbyak::Xmm upper_result = upper_inst ? ctx.reg_alloc.ScratchXmm(code) : Xbyak::Xmm{-1}; - const Xbyak::Xmm lower_result = lower_inst ? ctx.reg_alloc.ScratchXmm(code) : Xbyak::Xmm{-1}; + auto const x = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const y = ctx.reg_alloc.UseScratchXmm(code, args[1]); + auto const tmp = ctx.reg_alloc.ScratchXmm(code); + auto const upper_result = upper_inst ? ctx.reg_alloc.ScratchXmm(code) : Xbyak::Xmm{-1}; + auto const lower_result = lower_inst ? ctx.reg_alloc.ScratchXmm(code) : Xbyak::Xmm{-1}; // calculate unsigned multiply code.movdqa(tmp, x); @@ -5792,11 +6151,11 @@ void EmitX64::EmitVectorUnsignedSaturatedShiftLeft64(EmitContext& ctx, IR::Inst* void EmitX64::EmitVectorZeroExtend8(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::SSE41)) { code.pmovzxbw(a, a); } else { - const Xbyak::Xmm zeros = ctx.reg_alloc.ScratchXmm(code); + auto const zeros = ctx.reg_alloc.ScratchXmm(code); code.pxor(zeros, zeros); code.punpcklbw(a, zeros); } @@ -5805,11 +6164,11 @@ void EmitX64::EmitVectorZeroExtend8(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorZeroExtend16(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::SSE41)) { code.pmovzxwd(a, a); } else { - const Xbyak::Xmm zeros = ctx.reg_alloc.ScratchXmm(code); + auto const zeros = ctx.reg_alloc.ScratchXmm(code); code.pxor(zeros, zeros); code.punpcklwd(a, zeros); } @@ -5818,11 +6177,11 @@ void EmitX64::EmitVectorZeroExtend16(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorZeroExtend32(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); if (code.HasHostFeature(HostFeature::SSE41)) { code.pmovzxdq(a, a); } else { - const Xbyak::Xmm zeros = ctx.reg_alloc.ScratchXmm(code); + auto const zeros = ctx.reg_alloc.ScratchXmm(code); code.pxor(zeros, zeros); code.punpckldq(a, zeros); } @@ -5831,8 +6190,8 @@ void EmitX64::EmitVectorZeroExtend32(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorZeroExtend64(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); - const Xbyak::Xmm zeros = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const zeros = ctx.reg_alloc.ScratchXmm(code); code.pxor(zeros, zeros); code.punpcklqdq(a, zeros); ctx.reg_alloc.DefineValue(code, inst, a); @@ -5840,7 +6199,7 @@ void EmitX64::EmitVectorZeroExtend64(EmitContext& ctx, IR::Inst* inst) { void EmitX64::EmitVectorZeroUpper(EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); - const Xbyak::Xmm a = ctx.reg_alloc.UseScratchXmm(code, args[0]); + auto const a = ctx.reg_alloc.UseScratchXmm(code, args[0]); code.movq(a, a); // TODO: !IsLastUse @@ -5848,7 +6207,7 @@ void EmitX64::EmitVectorZeroUpper(EmitContext& ctx, IR::Inst* inst) { } void EmitX64::EmitZeroVector(EmitContext& ctx, IR::Inst* inst) { - const Xbyak::Xmm a = ctx.reg_alloc.ScratchXmm(code); + auto const a = ctx.reg_alloc.ScratchXmm(code); code.pxor(a, a); ctx.reg_alloc.DefineValue(code, inst, a); } diff --git a/src/dynarmic/tests/A64/a64.cpp b/src/dynarmic/tests/A64/a64.cpp index 4d4484e53e..e85986ea5a 100644 --- a/src/dynarmic/tests/A64/a64.cpp +++ b/src/dynarmic/tests/A64/a64.cpp @@ -415,6 +415,105 @@ TEST_CASE("A64: URSHL", "[a64]") { CHECK(jit.GetVector(9) == Vector{0x0000000000000002, 0x12db8b8280e0ba}); } +TEST_CASE("A64: SQSHLU", "[a64]") { + A64TestEnv env; + A64::UserConfig jit_user_config{}; + jit_user_config.callbacks = &env; + A64::Jit jit{jit_user_config}; + + oaknut::VectorCodeGenerator code{env.code_mem, nullptr}; + code.SQSHLU(V8.B16(), V0.B16(), 1); + code.SQSHLU(V9.H8(), V1.H8(), 2); + code.SQSHLU(V10.S4(), V2.S4(), 28); + code.SQSHLU(V11.D2(), V3.D2(), 4); + code.SQSHLU(V12.S4(), V0.S4(), 1); + code.SQSHLU(V13.S4(), V1.S4(), 3); + code.SQSHLU(V14.S4(), V2.S4(), 0); + code.SQSHLU(V15.S4(), V3.S4(), 0); + + jit.SetVector(0, Vector{0xffffffff'18ba6a6a, 0x7fffffff'943b954f}); + jit.SetVector(1, Vector{0x0000000b'0000000f, 0xffffffff'ffffffff}); + jit.SetVector(2, Vector{0x00000001'000000ff, 0x00000010'0000007f}); + jit.SetVector(3, Vector{0xffffffffffffffff, 0x96dc5c140705cd04}); + + env.ticks_left = env.code_mem.size(); + CheckedRun([&]() { jit.Run(); }); + + CHECK(jit.GetVector(8) == Vector{0x3000d4d4, 0xfe0000000076009e}); + CHECK(jit.GetVector(9) == Vector{0x2c0000003c, 0}); + CHECK(jit.GetVector(10) == Vector{0x10000000'ffffffff, 0xffffffff'ffffffff}); + CHECK(jit.GetVector(11) == Vector{0, 0}); + CHECK(jit.GetVector(12) == Vector{0x3174d4d4, 0xfffffffe00000000}); + CHECK(jit.GetVector(13) == Vector{0x5800000078, 0}); + CHECK(jit.GetVector(14) == Vector{0x1000000ff, 0x100000007f}); + CHECK(jit.GetVector(15) == Vector{0, 0x705cd04}); +} + +TEST_CASE("A64: SMIN", "[a64]") { + A64TestEnv env; + A64::UserConfig jit_user_config{}; + jit_user_config.callbacks = &env; + A64::Jit jit{jit_user_config}; + + oaknut::VectorCodeGenerator code{env.code_mem, nullptr}; + code.SMIN(V8.B16(), V0.B16(), V3.B16()); + code.SMIN(V9.H8(), V1.H8(), V2.H8()); + code.SMIN(V10.S4(), V2.S4(), V3.S4()); + code.SMIN(V11.S4(), V3.S4(), V3.S4()); + code.SMIN(V12.S4(), V0.S4(), V3.S4()); + code.SMIN(V13.S4(), V1.S4(), V2.S4()); + code.SMIN(V14.S4(), V2.S4(), V1.S4()); + code.SMIN(V15.S4(), V3.S4(), V0.S4()); + + jit.SetPC(0); + jit.SetVector(0, Vector{0xffffffff'18ba6a6a, 0x7fffffff'943b954f}); + jit.SetVector(1, Vector{0x0000000b'0000000f, 0xffffffff'ffffffff}); + jit.SetVector(2, Vector{0x00000001'000000ff, 0x00000010'0000007f}); + jit.SetVector(3, Vector{0xffffffff'ffffffff, 0x96dc5c14'0705cd04}); + + env.ticks_left = 4; + CheckedRun([&]() { jit.Run(); }); + + REQUIRE(jit.GetVector(8) == Vector{0xffffffffffbaffff, 0x96dcffff94059504}); + REQUIRE(jit.GetVector(9) == Vector{0x10000000f, 0xffffffffffffffff}); + REQUIRE(jit.GetVector(10) == Vector{0xffffffffffffffff, 0x96dc5c140000007f}); +} + +TEST_CASE("A64: SMINP", "[a64]") { + A64TestEnv env; + A64::UserConfig jit_user_config{}; + jit_user_config.callbacks = &env; + A64::Jit jit{jit_user_config}; + + oaknut::VectorCodeGenerator code{env.code_mem, nullptr}; + code.SMINP(V8.B16(), V0.B16(), V3.B16()); + code.SMINP(V9.H8(), V1.H8(), V2.H8()); + code.SMINP(V10.S4(), V2.S4(), V1.S4()); + code.SMINP(V11.S4(), V3.S4(), V3.S4()); + code.SMINP(V12.S4(), V0.S4(), V3.S4()); + code.SMINP(V13.S4(), V1.S4(), V2.S4()); + code.SMINP(V14.S4(), V2.S4(), V1.S4()); + code.SMINP(V15.S4(), V3.S4(), V0.S4()); + + jit.SetPC(0); + jit.SetVector(0, Vector{0xffffffff'18ba6a6a, 0x7fffffff'943b954f}); + jit.SetVector(1, Vector{0x0000000b'0000000f, 0xffffffff'ffffffff}); + jit.SetVector(2, Vector{0x00000001'000000ff, 0x00000010'0000007f}); + jit.SetVector(3, Vector{0xffffffff'ffffffff, 0x96dc5c14'0705cd04}); + + env.ticks_left = 4; + CheckedRun([&]() { jit.Run(); }); + + REQUIRE(jit.GetVector(8) == Vector{0xffff9495ffffba6a, 0x961405cdffffffff}); + REQUIRE(jit.GetVector(9) == Vector{0xffffffff00000000, 0}); + REQUIRE(jit.GetVector(10) == Vector{0x1000000001, 0xffffffff0000000b}); + REQUIRE(jit.GetVector(11) == Vector{0x96dc5c14ffffffff, 0x96dc5c14ffffffff}); + REQUIRE(jit.GetVector(12) == Vector{0x943b954fffffffff, 0x96dc5c14ffffffff}); + REQUIRE(jit.GetVector(13) == Vector{0xffffffff0000000b, 0x1000000001}); + REQUIRE(jit.GetVector(14) == Vector{0x1000000001, 0xffffffff0000000b}); + REQUIRE(jit.GetVector(15) == Vector{0x96dc5c14ffffffff, 0x943b954fffffffff}); +} + TEST_CASE("A64: XTN", "[a64]") { A64TestEnv env; A64::UserConfig jit_user_config{}; From 9b19d17c9c7804ff1c8351cbd3830658dd4fc993 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Feb 2026 03:42:19 +0000 Subject: [PATCH 02/54] sudachi ios stuff --- src/ios/Eden/AppUI-Bridging-Header.h | 11 + src/ios/Eden/AppUI.swift | 108 ++++ .../AppUIGameInformation.h | 26 + .../AppUIGameInformation.mm | 434 +++++++++++++ src/ios/Eden/Wrapper/AppUIObjC.h | 92 +++ src/ios/Eden/Wrapper/AppUIObjC.mm | 258 ++++++++ src/ios/Eden/Wrapper/Config/Config.h | 568 ++++++++++++++++++ src/ios/Eden/Wrapper/Config/Config.mm | 330 ++++++++++ .../DirectoryManager/DirectoryManager.h | 10 + .../DirectoryManager/DirectoryManager.mm | 16 + .../EmulationSession/EmulationSession.h | 98 +++ .../EmulationSession/EmulationSession.mm | 528 ++++++++++++++++ .../Wrapper/EmulationWindow/EmulationWindow.h | 80 +++ .../EmulationWindow/EmulationWindow.mm | 85 +++ 14 files changed, 2644 insertions(+) create mode 100644 src/ios/Eden/AppUI-Bridging-Header.h create mode 100644 src/ios/Eden/AppUI.swift create mode 100644 src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.h create mode 100644 src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.mm create mode 100644 src/ios/Eden/Wrapper/AppUIObjC.h create mode 100644 src/ios/Eden/Wrapper/AppUIObjC.mm create mode 100644 src/ios/Eden/Wrapper/Config/Config.h create mode 100644 src/ios/Eden/Wrapper/Config/Config.mm create mode 100644 src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.h create mode 100644 src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.mm create mode 100644 src/ios/Eden/Wrapper/EmulationSession/EmulationSession.h create mode 100644 src/ios/Eden/Wrapper/EmulationSession/EmulationSession.mm create mode 100644 src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.h create mode 100644 src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.mm diff --git a/src/ios/Eden/AppUI-Bridging-Header.h b/src/ios/Eden/AppUI-Bridging-Header.h new file mode 100644 index 0000000000..a75f43550d --- /dev/null +++ b/src/ios/Eden/AppUI-Bridging-Header.h @@ -0,0 +1,11 @@ +// +// AppUI-Bridging-Header.h - Sudachi +// Created by Jarrod Norwell on 4/3/2024. +// + +#ifndef AppUI_Bridging_Header_h +#define AppUI_Bridging_Header_h + +#import "Wrapper/AppUIObjC.h" + +#endif /* AppUI_Bridging_Header_h */ diff --git a/src/ios/Eden/AppUI.swift b/src/ios/Eden/AppUI.swift new file mode 100644 index 0000000000..b8f79528b7 --- /dev/null +++ b/src/ios/Eden/AppUI.swift @@ -0,0 +1,108 @@ +// +// AppUI.swift - Sudachi +// Created by Jarrod Norwell on 4/3/2024. +// + +import Foundation +import QuartzCore.CAMetalLayer + +public struct AppUI { + + public static let shared = AppUI() + + fileprivate let appUIObjC = AppUIObjC.shared() + + public func configure(layer: CAMetalLayer, with size: CGSize) { + appUIObjC.configure(layer: layer, with: size) + } + + public func information(for url: URL) -> AppUIInformation { + appUIObjC.gameInformation.information(for: url) + } + + public func insert(game url: URL) { + appUIObjC.insert(game: url) + } + + public func insert(games urls: [URL]) { + appUIObjC.insert(games: urls) + } + + public func bootOS() { + appUIObjC.bootOS() + } + + public func pause() { + appUIObjC.pause() + } + + public func play() { + appUIObjC.play() + } + + public func ispaused() -> Bool { + return appUIObjC.ispaused() + } + + public func FirstFrameShowed() -> Bool { + return appUIObjC.hasfirstfame() + } + + public func canGetFullPath() -> Bool { + return appUIObjC.canGetFullPath() + } + + + public func exit() { + appUIObjC.quit() + } + + public func step() { + appUIObjC.step() + } + + public func orientationChanged(orientation: UIInterfaceOrientation, with layer: CAMetalLayer, size: CGSize) { + appUIObjC.orientationChanged(orientation: orientation, with: layer, size: size) + } + + public func touchBegan(at point: CGPoint, for index: UInt) { + appUIObjC.touchBegan(at: point, for: index) + } + + public func touchEnded(for index: UInt) { + appUIObjC.touchEnded(for: index) + } + + public func touchMoved(at point: CGPoint, for index: UInt) { + appUIObjC.touchMoved(at: point, for: index) + } + + public func gyroMoved(x: Float, y: Float, z: Float, accelX: Float, accelY: Float, accelZ: Float, controllerId: Int32, deltaTimestamp: Int32) { + // Calling the Objective-C function with both gyroscope and accelerometer data + appUIObjC.virtualControllerGyro(controllerId, + deltaTimestamp: deltaTimestamp, + gyroX: x, + gyroY: y, + gyroZ: z, + accelX: accelX, + accelY: accelY, + accelZ: accelZ) + } + + + public func thumbstickMoved(analog: VirtualControllerAnalogType, x: Float, y: Float, controllerid: Int) { + appUIObjC.thumbstickMoved(analog, x: CGFloat(x), y: CGFloat(y), controllerId: Int32(controllerid)) + } + + public func virtualControllerButtonDown(button: VirtualControllerButtonType, controllerid: Int) { + appUIObjC.virtualControllerButtonDown(button, controllerId: Int32(controllerid)) + } + + public func virtualControllerButtonUp(button: VirtualControllerButtonType, controllerid: Int) { + appUIObjC.virtualControllerButtonUp(button, controllerId: Int32(controllerid)) + } + + public func settingsSaved() { + appUIObjC.settingsChanged() + } +} diff --git a/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.h b/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.h new file mode 100644 index 0000000000..5040775ad0 --- /dev/null +++ b/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.h @@ -0,0 +1,26 @@ +// +// AppUIGameInformation.h - Sudachi +// Created by Jarrod Norwell on 1/20/24. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface AppUIInformation : NSObject +@property (nonatomic, strong) NSString *developer; +@property (nonatomic, strong) NSData *iconData; +@property (nonatomic) BOOL isHomebrew; +@property (nonatomic) uint64_t programID; +@property (nonatomic, strong) NSString *title, *version; + +-(AppUIInformation *) initWithDeveloper:(NSString *)developer iconData:(NSData *)iconData isHomebrew:(BOOL)isHomebrew programID:(uint64_t)programID title:(NSString *)title version:(NSString *)version; +@end + +@interface AppUIGameInformation : NSObject ++(AppUIGameInformation *) sharedInstance NS_SWIFT_NAME(shared()); + +-(AppUIInformation *) informationForGame:(NSURL *)url NS_SWIFT_NAME(information(for:)); +@end + +NS_ASSUME_NONNULL_END diff --git a/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.mm b/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.mm new file mode 100644 index 0000000000..00c894d078 --- /dev/null +++ b/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.mm @@ -0,0 +1,434 @@ +// +// AppUIGameInformation.mm - Sudachi +// Created by Jarrod Norwell on 1/20/24. +// + +#import "AppUIGameInformation.h" +#import "../DirectoryManager/DirectoryManager.h" +#import "../EmulationSession/EmulationSession.h" + +#include "common/fs/fs.h" +#include "common/fs/path_util.h" +#include "core/core.h" +#include "core/file_sys/fs_filesystem.h" +#include "core/file_sys/patch_manager.h" +#include "core/loader/loader.h" +#include "core/loader/nro.h" +#include "frontend_common/yuzu_config.h" + +struct GameMetadata { + std::string title; + u64 programId; + std::string developer; + std::string version; + std::vector icon; + bool isHomebrew; +}; + + +class SdlConfig final : public YuzuConfig { +public: + explicit SdlConfig(std::optional config_path); + ~SdlConfig() override; + + void ReloadAllValues() override; + void SaveAllValues() override; + +protected: + void ReadSdlValues(); + void ReadSdlPlayerValues(std::size_t player_index); + void ReadSdlControlValues(); + void ReadHidbusValues() override; + void ReadDebugControlValues() override; + void ReadPathValues() override {} + void ReadShortcutValues() override {} + void ReadUIValues() override {} + void ReadUIGamelistValues() override {} + void ReadUILayoutValues() override {} + void ReadMultiplayerValues() override {} + + void SaveSdlValues(); + void SaveSdlPlayerValues(std::size_t player_index); + void SaveSdlControlValues(); + void SaveHidbusValues() override; + void SaveDebugControlValues() override; + void SavePathValues() override {} + void SaveShortcutValues() override {} + void SaveUIValues() override {} + void SaveUIGamelistValues() override {} + void SaveUILayoutValues() override {} + void SaveMultiplayerValues() override {} + + std::vector& FindRelevantList(YuzuSettings::Category category) override; + +public: + static const std::array default_buttons; + static const std::array default_motions; + static const std::array, YuzuSettings::NativeAnalog::NumAnalogs> default_analogs; + static const std::array default_stick_mod; + static const std::array default_ringcon_analogs; +}; + + +#define SDL_MAIN_HANDLED +#include + +#include "common/logging/log.h" +#include "input_common/main.h" + +const std::array SdlConfig::default_buttons = { + SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_T, + SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H, SDL_SCANCODE_Q, SDL_SCANCODE_W, + SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_B, +}; + +const std::array SdlConfig::default_motions = { + SDL_SCANCODE_7, + SDL_SCANCODE_8, +}; + +const std::array, YuzuSettings::NativeAnalog::NumAnalogs> SdlConfig::default_analogs{ + { + { + SDL_SCANCODE_UP, + SDL_SCANCODE_DOWN, + SDL_SCANCODE_LEFT, + SDL_SCANCODE_RIGHT, + }, + { + SDL_SCANCODE_I, + SDL_SCANCODE_K, + SDL_SCANCODE_J, + SDL_SCANCODE_L, + }, + }}; + +const std::array SdlConfig::default_stick_mod = { + SDL_SCANCODE_D, + 0, +}; + +const std::array SdlConfig::default_ringcon_analogs{{ + 0, + 0, +}}; + +SdlConfig::SdlConfig(const std::optional config_path) { + Initialize(config_path); + ReadSdlValues(); + SaveSdlValues(); +} + +SdlConfig::~SdlConfig() { + if (global) { + SdlConfig::SaveAllValues(); + } +} + +void SdlConfig::ReloadAllValues() { + Reload(); + ReadSdlValues(); + SaveSdlValues(); +} + +void SdlConfig::SaveAllValues() { + SaveValues(); + SaveSdlValues(); +} + +void SdlConfig::ReadSdlValues() { + ReadSdlControlValues(); +} + +void SdlConfig::ReadSdlControlValues() { + BeginGroup(YuzuSettings::TranslateCategory(YuzuSettings::Category::Controls)); + + YuzuSettings::values.players.SetGlobal(!IsCustomConfig()); + for (std::size_t p = 0; p < YuzuSettings::values.players.GetValue().size(); ++p) { + ReadSdlPlayerValues(p); + } + if (IsCustomConfig()) { + EndGroup(); + return; + } + ReadDebugControlValues(); + ReadHidbusValues(); + + EndGroup(); +} + +void SdlConfig::ReadSdlPlayerValues(const std::size_t player_index) { + std::string player_prefix; + if (type != ConfigType::InputProfile) { + player_prefix.append("player_").append(ToString(player_index)).append("_"); + } + + auto& player = YuzuSettings::values.players.GetValue()[player_index]; + if (IsCustomConfig()) { + const auto profile_name = + ReadStringSetting(std::string(player_prefix).append("profile_name")); + if (profile_name.empty()) { + // Use the global input config + player = YuzuSettings::values.players.GetValue(true)[player_index]; + player.profile_name = ""; + return; + } + } + + for (int i = 0; i < YuzuSettings::NativeButton::NumButtons; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); + auto& player_buttons = player.buttons[i]; + + player_buttons = ReadStringSetting( + std::string(player_prefix).append(YuzuSettings::NativeButton::mapping[i]), default_param); + if (player_buttons.empty()) { + player_buttons = default_param; + } + } + + for (int i = 0; i < YuzuSettings::NativeAnalog::NumAnalogs; ++i) { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], + default_analogs[i][3], default_stick_mod[i], 0.5f); + auto& player_analogs = player.analogs[i]; + + player_analogs = ReadStringSetting( + std::string(player_prefix).append(YuzuSettings::NativeAnalog::mapping[i]), default_param); + if (player_analogs.empty()) { + player_analogs = default_param; + } + } + + for (int i = 0; i < YuzuSettings::NativeMotion::NumMotions; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); + auto& player_motions = player.motions[i]; + + player_motions = ReadStringSetting( + std::string(player_prefix).append(YuzuSettings::NativeMotion::mapping[i]), default_param); + if (player_motions.empty()) { + player_motions = default_param; + } + } +} + +void SdlConfig::ReadDebugControlValues() { + for (int i = 0; i < YuzuSettings::NativeButton::NumButtons; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); + auto& debug_pad_buttons = YuzuSettings::values.debug_pad_buttons[i]; + debug_pad_buttons = ReadStringSetting( + std::string("debug_pad_").append(YuzuSettings::NativeButton::mapping[i]), default_param); + if (debug_pad_buttons.empty()) { + debug_pad_buttons = default_param; + } + } + for (int i = 0; i < YuzuSettings::NativeAnalog::NumAnalogs; ++i) { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], + default_analogs[i][3], default_stick_mod[i], 0.5f); + auto& debug_pad_analogs = YuzuSettings::values.debug_pad_analogs[i]; + debug_pad_analogs = ReadStringSetting( + std::string("debug_pad_").append(YuzuSettings::NativeAnalog::mapping[i]), default_param); + if (debug_pad_analogs.empty()) { + debug_pad_analogs = default_param; + } + } +} + +void SdlConfig::ReadHidbusValues() { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); + auto& ringcon_analogs = YuzuSettings::values.ringcon_analogs; + + ringcon_analogs = ReadStringSetting(std::string("ring_controller"), default_param); + if (ringcon_analogs.empty()) { + ringcon_analogs = default_param; + } +} + +void SdlConfig::SaveSdlValues() { + LOG_DEBUG(Config, "Saving SDL configuration values"); + SaveSdlControlValues(); + + WriteToIni(); +} + +void SdlConfig::SaveSdlControlValues() { + BeginGroup(YuzuSettings::TranslateCategory(YuzuSettings::Category::Controls)); + + YuzuSettings::values.players.SetGlobal(!IsCustomConfig()); + for (std::size_t p = 0; p < YuzuSettings::values.players.GetValue().size(); ++p) { + SaveSdlPlayerValues(p); + } + if (IsCustomConfig()) { + EndGroup(); + return; + } + SaveDebugControlValues(); + SaveHidbusValues(); + + EndGroup(); +} + +void SdlConfig::SaveSdlPlayerValues(const std::size_t player_index) { + std::string player_prefix; + if (type != ConfigType::InputProfile) { + player_prefix = std::string("player_").append(ToString(player_index)).append("_"); + } + + const auto& player = YuzuSettings::values.players.GetValue()[player_index]; + if (IsCustomConfig() && player.profile_name.empty()) { + // No custom profile selected + return; + } + + for (int i = 0; i < YuzuSettings::NativeButton::NumButtons; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); + WriteStringSetting(std::string(player_prefix).append(YuzuSettings::NativeButton::mapping[i]), + player.buttons[i], std::make_optional(default_param)); + } + for (int i = 0; i < YuzuSettings::NativeAnalog::NumAnalogs; ++i) { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], + default_analogs[i][3], default_stick_mod[i], 0.5f); + WriteStringSetting(std::string(player_prefix).append(YuzuSettings::NativeAnalog::mapping[i]), + player.analogs[i], std::make_optional(default_param)); + } + for (int i = 0; i < YuzuSettings::NativeMotion::NumMotions; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); + WriteStringSetting(std::string(player_prefix).append(YuzuSettings::NativeMotion::mapping[i]), + player.motions[i], std::make_optional(default_param)); + } +} + +void SdlConfig::SaveDebugControlValues() { + for (int i = 0; i < YuzuSettings::NativeButton::NumButtons; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); + WriteStringSetting(std::string("debug_pad_").append(YuzuSettings::NativeButton::mapping[i]), + YuzuSettings::values.debug_pad_buttons[i], + std::make_optional(default_param)); + } + for (int i = 0; i < YuzuSettings::NativeAnalog::NumAnalogs; ++i) { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], + default_analogs[i][3], default_stick_mod[i], 0.5f); + WriteStringSetting(std::string("debug_pad_").append(YuzuSettings::NativeAnalog::mapping[i]), + YuzuSettings::values.debug_pad_analogs[i], + std::make_optional(default_param)); + } +} + +void SdlConfig::SaveHidbusValues() { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); + WriteStringSetting(std::string("ring_controller"), YuzuSettings::values.ringcon_analogs, + std::make_optional(default_param)); +} + +std::vector& SdlConfig::FindRelevantList(YuzuSettings::Category category) { + return YuzuSettings::values.linkage.by_category[category]; +} + + + + + + + +std::unordered_map m_game_metadata_cache; + +GameMetadata CacheGameMetadata(const std::string& path) { + const auto file = + Core::GetGameFileFromPath(EmulationSession::GetInstance().System().GetFilesystem(), path); + auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0); + + GameMetadata entry; + loader->ReadTitle(entry.title); + loader->ReadProgramId(entry.programId); + loader->ReadIcon(entry.icon); + + const FileSys::PatchManager pm{ + entry.programId, EmulationSession::GetInstance().System().GetFileSystemController(), + EmulationSession::GetInstance().System().GetContentProvider()}; + const auto control = pm.GetControlMetadata(); + + if (control.first != nullptr) { + entry.developer = control.first->GetDeveloperName(); + entry.version = control.first->GetVersionString(); + } else { + FileSys::NACP nacp; + if (loader->ReadControlData(nacp) == Loader::ResultStatus::Success) { + entry.developer = nacp.GetDeveloperName(); + } else { + entry.developer = ""; + } + + entry.version = "1.0.0"; + } + + if (loader->GetFileType() == Loader::FileType::NRO) { + auto loader_nro = reinterpret_cast(loader.get()); + entry.isHomebrew = loader_nro->IsHomebrew(); + } else { + entry.isHomebrew = false; + } + + m_game_metadata_cache[path] = entry; + + return entry; +} + +GameMetadata GameMetadata(const std::string& path, bool reload = false) { + if (!EmulationSession::GetInstance().IsInitialized()) { + Common::FS::SetAppDirectory(DirectoryManager::AppUIDirectory()); + + EmulationSession::GetInstance().System().Initialize(); + EmulationSession::GetInstance().InitializeSystem(false); + } + + if (reload) { + return CacheGameMetadata(path); + } + + if (auto search = m_game_metadata_cache.find(path); search != m_game_metadata_cache.end()) { + return search->second; + } + + return CacheGameMetadata(path); +} + + +@implementation AppUIInformation +-(AppUIInformation *) initWithDeveloper:(NSString *)developer iconData:(NSData *)iconData isHomebrew:(BOOL)isHomebrew programID:(uint64_t)programID + title:(NSString *)title version:(NSString *)version { + if (self = [super init]) { + self.developer = developer; + self.iconData = iconData; + self.isHomebrew = isHomebrew; + self.programID = programID; + self.title = title; + self.version = version; + } return self; +} +@end + +@implementation AppUIGameInformation ++(AppUIGameInformation *) sharedInstance { + static AppUIGameInformation *sharedInstance = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + return sharedInstance; +} + + +-(AppUIInformation *) informationForGame:(NSURL *)url { + auto gameMetadata = GameMetadata([url.path UTF8String]); + + return [[AppUIInformation alloc] initWithDeveloper:[NSString stringWithCString:gameMetadata.developer.c_str() encoding:NSUTF8StringEncoding] + iconData:[NSData dataWithBytes:gameMetadata.icon.data() length:gameMetadata.icon.size()] + isHomebrew:gameMetadata.isHomebrew programID:gameMetadata.programId + title:[NSString stringWithCString:gameMetadata.title.c_str() encoding:NSUTF8StringEncoding] + version:[NSString stringWithCString:gameMetadata.version.c_str() encoding:NSUTF8StringEncoding]]; +} +@end diff --git a/src/ios/Eden/Wrapper/AppUIObjC.h b/src/ios/Eden/Wrapper/AppUIObjC.h new file mode 100644 index 0000000000..d3594d74d1 --- /dev/null +++ b/src/ios/Eden/Wrapper/AppUIObjC.h @@ -0,0 +1,92 @@ +// +// AppUIObjC.h - Sudachi +// Created by Jarrod Norwell on 1/8/24. +// + +#import +#import + +#import "AppUIGameInformation/AppUIGameInformation.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSUInteger, VirtualControllerAnalogType) { + VirtualControllerAnalogTypeLeft = 0, + VirtualControllerAnalogTypeRight = 1 +}; + +typedef NS_ENUM(NSUInteger, VirtualControllerButtonType) { + VirtualControllerButtonTypeA = 0, + VirtualControllerButtonTypeB = 1, + VirtualControllerButtonTypeX = 2, + VirtualControllerButtonTypeY = 3, + VirtualControllerButtonTypeL = 4, + VirtualControllerButtonTypeR = 5, + VirtualControllerButtonTypeTriggerL = 6, + VirtualControllerButtonTypeTriggerR = 7, + VirtualControllerButtonTypeTriggerZL = 8, + VirtualControllerButtonTypeTriggerZR = 9, + VirtualControllerButtonTypePlus = 10, + VirtualControllerButtonTypeMinus = 11, + VirtualControllerButtonTypeDirectionalPadLeft = 12, + VirtualControllerButtonTypeDirectionalPadUp = 13, + VirtualControllerButtonTypeDirectionalPadRight = 14, + VirtualControllerButtonTypeDirectionalPadDown = 15, + VirtualControllerButtonTypeSL = 16, + VirtualControllerButtonTypeSR = 17, + VirtualControllerButtonTypeHome = 18, + VirtualControllerButtonTypeCapture = 19 +}; + +@interface AppUIObjC : NSObject { + CAMetalLayer *_layer; + CGSize _size; +} + +@property (nonatomic, strong) AppUIGameInformation *gameInformation; + ++(AppUIObjC *) sharedInstance NS_SWIFT_NAME(shared()); +-(void) configureLayer:(CAMetalLayer *)layer withSize:(CGSize)size NS_SWIFT_NAME(configure(layer:with:)); +-(void) bootOS; +-(void) pause; +-(void) play; +-(BOOL) ispaused; +-(BOOL) canGetFullPath; +-(void) quit; +-(void) insertGame:(NSURL *)url NS_SWIFT_NAME(insert(game:)); +-(void) insertGames:(NSArray *)games NS_SWIFT_NAME(insert(games:)); +-(void) step; +-(BOOL) hasfirstfame; + +-(void) touchBeganAtPoint:(CGPoint)point index:(NSUInteger)index NS_SWIFT_NAME(touchBegan(at:for:)); +-(void) touchEndedForIndex:(NSUInteger)index; +-(void) touchMovedAtPoint:(CGPoint)point index:(NSUInteger)index NS_SWIFT_NAME(touchMoved(at:for:)); + +-(void) thumbstickMoved:(VirtualControllerAnalogType)analog + x:(CGFloat)x + y:(CGFloat)y + controllerId:(int)controllerId; + +-(void) virtualControllerGyro:(int)controllerId + deltaTimestamp:(int)delta_timestamp + gyroX:(float)gyro_x + gyroY:(float)gyro_y + gyroZ:(float)gyro_z + accelX:(float)accel_x + accelY:(float)accel_y + accelZ:(float)accel_z; + +-(void) virtualControllerButtonDown:(VirtualControllerButtonType)button + controllerId:(int)controllerId; + +-(void) virtualControllerButtonUp:(VirtualControllerButtonType)button + controllerId:(int)controllerId; + + +-(void) orientationChanged:(UIInterfaceOrientation)orientation with:(CAMetalLayer *)layer size:(CGSize)size NS_SWIFT_NAME(orientationChanged(orientation:with:size:)); + +-(void) settingsChanged; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/ios/Eden/Wrapper/AppUIObjC.mm b/src/ios/Eden/Wrapper/AppUIObjC.mm new file mode 100644 index 0000000000..065ce6d046 --- /dev/null +++ b/src/ios/Eden/Wrapper/AppUIObjC.mm @@ -0,0 +1,258 @@ +// +// AppUIObjC.mm - Sudachi +// Created by Jarrod Norwell on 1/8/24. +// + +#import "AppUIObjC.h" + +#import "Config/Config.h" +#import "EmulationSession/EmulationSession.h" +#import "DirectoryManager/DirectoryManager.h" + +#include "common/fs/fs.h" +#include "common/fs/path_util.h" +#include "common/settings.h" +#include "common/fs/fs.h" +#include "core/file_sys/patch_manager.h" +#include "core/file_sys/savedata_factory.h" +#include "core/loader/nro.h" +#include "frontend_common/content_manager.h" +#include "common/settings_enums.h" +#include "network/announce_multiplayer_session.h" +#include "common/announce_multiplayer_room.h" +#include "network/network.h" + +#include "common/detached_tasks.h" +#include "common/dynamic_library.h" +#include "common/fs/path_util.h" +#include "common/logging/backend.h" +#include "common/logging/log.h" +#include "common/microprofile.h" +#include "common/scm_rev.h" +#include "common/scope_exit.h" +#include "common/settings.h" +#include "common/string_util.h" +#include "core/core.h" +#include "core/cpu_manager.h" +#include "core/crypto/key_manager.h" +#include "core/file_sys/card_image.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/fs_filesystem.h" +#include "core/file_sys/submission_package.h" +#include "core/file_sys/vfs/vfs.h" +#include "core/file_sys/vfs/vfs_real.h" +#include "core/frontend/applets/cabinet.h" +#include "core/frontend/applets/controller.h" +#include "core/frontend/applets/error.h" +#include "core/frontend/applets/general.h" +#include "core/frontend/applets/mii_edit.h" +#include "core/frontend/applets/profile_select.h" +#include "core/frontend/applets/software_keyboard.h" +#include "core/frontend/applets/web_browser.h" +#include "core/hle/service/am/applet_manager.h" +#include "core/hle/service/am/frontend/applets.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/loader/loader.h" +#include "frontend_common/yuzu_config.h" +#include "hid_core/frontend/emulated_controller.h" +#include "hid_core/hid_core.h" +#include "hid_core/hid_types.h" +#include "video_core/renderer_base.h" +#include "video_core/renderer_vulkan/renderer_vulkan.h" +#include "video_core/vulkan_common/vulkan_instance.h" +#include "video_core/vulkan_common/vulkan_surface.h" + + +#import + +@implementation AppUIObjC +-(AppUIObjC *) init { + if (self = [super init]) { + _gameInformation = [AppUIGameInformation sharedInstance]; + + + Common::FS::SetAppDirectory(DirectoryManager::AppUIDirectory()); + Config{"config", Config::ConfigType::GlobalConfig}; + + EmulationSession::GetInstance().System().Initialize(); + EmulationSession::GetInstance().InitializeSystem(false); + EmulationSession::GetInstance().InitializeGpuDriver(); + + + YuzuSettings::values.dump_shaders.SetValue(true); + YuzuSettings::values.use_asynchronous_shaders.SetValue(true); + // YuzuSettings::values.astc_recompression.SetValue(YuzuSettings::AstcRecompression::Bc3); + YuzuSettings::values.shader_backend.SetValue(YuzuSettings::ShaderBackend::SpirV); + // YuzuSettings::values.resolution_setup.SetValue(YuzuSettings::ResolutionSetup::Res1X); + // YuzuSettings::values.scaling_filter.SetValue(YuzuSettings::ScalingFilter::Bilinear); + } return self; +} + + ++(AppUIObjC *) sharedInstance { + static AppUIObjC *sharedInstance = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + return sharedInstance; +} + +- (BOOL)ispaused { + return EmulationSession::GetInstance().IsPaused(); +} + +-(void) pause { + EmulationSession::GetInstance().System().Pause(); + EmulationSession::GetInstance().HaltEmulation(); + EmulationSession::GetInstance().PauseEmulation(); +} + +-(void) play { + + EmulationSession::GetInstance().System().Run(); + EmulationSession::GetInstance().RunEmulation(); + EmulationSession::GetInstance().UnPauseEmulation(); +} + +-(BOOL)hasfirstfame { + @try { + auto* window = &EmulationSession::GetInstance().Window(); + if (window && window->HasFirstFrame()) { + return YES; + } + } + @catch (NSException *exception) { + NSLog(@"Exception occurred: %@", exception); + // Handle the exception, maybe return a default value + return NO; + } + return NO; +} + +- (BOOL)canGetFullPath { + @try { + Core::System& system = EmulationSession::GetInstance().System(); + auto bis_system = system.GetFileSystemController().GetSystemNANDContents(); + + if (bis_system == nullptr) { + return NO; + } + + constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); + auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); + + if (qlaunch_applet_nca == nullptr) { + return NO; + } + + const auto filename = qlaunch_applet_nca->GetFullPath(); + + // If GetFullPath() is successful + return YES; + } @catch (NSException *exception) { + // Handle the exception if needed + return NO; + } +} + +-(void) quit { + EmulationSession::GetInstance().ShutdownEmulation(); +} + +-(void) configureLayer:(CAMetalLayer *)layer withSize:(CGSize)size { + _layer = layer; + _size = size; + EmulationSession::GetInstance().SetNativeWindow((__bridge CA::MetalLayer*)layer, size); +} + +-(void) bootOS { + EmulationSession::GetInstance().BootOS(); +} + +-(void) insertGame:(NSURL *)url { + EmulationSession::GetInstance().InitializeEmulation([url.path UTF8String], [_gameInformation informationForGame:url].programID, true); +} + +-(void) insertGames:(NSArray *)games { + for (NSURL *url in games) { + EmulationSession::GetInstance().ConfigureFilesystemProvider([url.path UTF8String]); + } +} + +-(void) step { + void(EmulationSession::GetInstance().System().Run()); +} + +-(void) touchBeganAtPoint:(CGPoint)point index:(NSUInteger)index { + float h_ratio, w_ratio; + h_ratio = EmulationSession::GetInstance().Window().GetFramebufferLayout().height / (_size.height * [[UIScreen mainScreen] nativeScale]); + w_ratio = EmulationSession::GetInstance().Window().GetFramebufferLayout().width / (_size.width * [[UIScreen mainScreen] nativeScale]); + + EmulationSession::GetInstance().Window().OnTouchPressed([[NSNumber numberWithUnsignedInteger:index] intValue], + (point.x) * [[UIScreen mainScreen] nativeScale] * w_ratio, + ((point.y) * [[UIScreen mainScreen] nativeScale] * h_ratio)); +} + +-(void) touchEndedForIndex:(NSUInteger)index { + EmulationSession::GetInstance().Window().OnTouchReleased([[NSNumber numberWithUnsignedInteger:index] intValue]); +} + +-(void) touchMovedAtPoint:(CGPoint)point index:(NSUInteger)index { + float h_ratio, w_ratio; + h_ratio = EmulationSession::GetInstance().Window().GetFramebufferLayout().height / (_size.height * [[UIScreen mainScreen] nativeScale]); + w_ratio = EmulationSession::GetInstance().Window().GetFramebufferLayout().width / (_size.width * [[UIScreen mainScreen] nativeScale]); + + EmulationSession::GetInstance().Window().OnTouchMoved([[NSNumber numberWithUnsignedInteger:index] intValue], + (point.x) * [[UIScreen mainScreen] nativeScale] * w_ratio, + ((point.y) * [[UIScreen mainScreen] nativeScale] * h_ratio)); +} + +-(void) thumbstickMoved:(VirtualControllerAnalogType)analog + x:(CGFloat)x + y:(CGFloat)y + controllerId:(int)controllerId { + EmulationSession::GetInstance().OnGamepadConnectEvent(controllerId); + EmulationSession::GetInstance().Window().OnGamepadJoystickEvent(controllerId, [[NSNumber numberWithUnsignedInteger:analog] intValue], CGFloat(x), CGFloat(y)); +} + +-(void) virtualControllerButtonDown:(VirtualControllerButtonType)button + controllerId:(int)controllerId { + EmulationSession::GetInstance().OnGamepadConnectEvent(controllerId); + EmulationSession::GetInstance().Window().OnGamepadButtonEvent(controllerId, [[NSNumber numberWithUnsignedInteger:button] intValue], true); +} + +-(void) virtualControllerGyro:(int)controllerId + deltaTimestamp:(int)delta_timestamp + gyroX:(float)gyro_x + gyroY:(float)gyro_y + gyroZ:(float)gyro_z + accelX:(float)accel_x + accelY:(float)accel_y + accelZ:(float)accel_z +{ + EmulationSession::GetInstance().OnGamepadConnectEvent(controllerId); + EmulationSession::GetInstance().Window().OnGamepadMotionEvent(controllerId, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z); +} + + +-(void) virtualControllerButtonUp:(VirtualControllerButtonType)button + controllerId:(int)controllerId { + EmulationSession::GetInstance().OnGamepadConnectEvent(controllerId); + EmulationSession::GetInstance().Window().OnGamepadButtonEvent(controllerId, [[NSNumber numberWithUnsignedInteger:button] intValue], false); +} + + +-(void) orientationChanged:(UIInterfaceOrientation)orientation with:(CAMetalLayer *)layer size:(CGSize)size { + _layer = layer; + _size = size; + EmulationSession::GetInstance().Window().OnSurfaceChanged((__bridge CA::MetalLayer*)layer, size); +} + +-(void) settingsChanged { + Config{"config", Config::ConfigType::GlobalConfig}; +} + + + +@end diff --git a/src/ios/Eden/Wrapper/Config/Config.h b/src/ios/Eden/Wrapper/Config/Config.h new file mode 100644 index 0000000000..5e29db42cf --- /dev/null +++ b/src/ios/Eden/Wrapper/Config/Config.h @@ -0,0 +1,568 @@ +// +// Config.h +// AppUI +// +// Created by Jarrod Norwell on 13/3/2024. +// + +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +namespace DefaultINI { + +const char* android_config_file = R"( + +[ControlsP0] +# The input devices and parameters for each Switch native input +# The config section determines the player number where the config will be applied on. For example "ControlsP0", "ControlsP1", ... +# It should be in the format of "engine:[engine_name],[param1]:[value1],[param2]:[value2]..." +# Escape characters $0 (for ':'), $1 (for ',') and $2 (for '$') can be used in values + +# Indicates if this player should be connected at boot +connected= + +# for button input, the following devices are available: +# - "keyboard" (default) for keyboard input. Required parameters: +# - "code": the code of the key to bind +# - "sdl" for joystick input using SDL. Required parameters: +# - "guid": SDL identification GUID of the joystick +# - "port": the index of the joystick to bind +# - "button"(optional): the index of the button to bind +# - "hat"(optional): the index of the hat to bind as direction buttons +# - "axis"(optional): the index of the axis to bind +# - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", "down", "left" or "right" +# - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is +# triggered if the axis value crosses +# - "direction"(only used for axis): "+" means the button is triggered when the axis value +# is greater than the threshold; "-" means the button is triggered when the axis value +# is smaller than the threshold +button_a= +button_b= +button_x= +button_y= +button_lstick= +button_rstick= +button_l= +button_r= +button_zl= +button_zr= +button_plus= +button_minus= +button_dleft= +button_dup= +button_dright= +button_ddown= +button_lstick_left= +button_lstick_up= +button_lstick_right= +button_lstick_down= +button_sl= +button_sr= +button_home= +button_screenshot= + +# for analog input, the following devices are available: +# - "analog_from_button" (default) for emulating analog input from direction buttons. Required parameters: +# - "up", "down", "left", "right": sub-devices for each direction. +# Should be in the format as a button input devices using escape characters, for example, "engine$0keyboard$1code$00" +# - "modifier": sub-devices as a modifier. +# - "modifier_scale": a float number representing the applied modifier scale to the analog input. +# Must be in range of 0.0-1.0. Defaults to 0.5 +# - "sdl" for joystick input using SDL. Required parameters: +# - "guid": SDL identification GUID of the joystick +# - "port": the index of the joystick to bind +# - "axis_x": the index of the axis to bind as x-axis (default to 0) +# - "axis_y": the index of the axis to bind as y-axis (default to 1) +lstick= +rstick= + +# for motion input, the following devices are available: +# - "keyboard" (default) for emulating random motion input from buttons. Required parameters: +# - "code": the code of the key to bind +# - "sdl" for motion input using SDL. Required parameters: +# - "guid": SDL identification GUID of the joystick +# - "port": the index of the joystick to bind +# - "motion": the index of the motion sensor to bind +# - "cemuhookudp" for motion input using Cemu Hook protocol. Required parameters: +# - "guid": the IP address of the cemu hook server encoded to a hex string. for example 192.168.0.1 = "c0a80001" +# - "port": the port of the cemu hook server +# - "pad": the index of the joystick +# - "motion": the index of the motion sensor of the joystick to bind +motionleft= +motionright= + +[ControlsGeneral] +# To use the debug_pad, prepend debug_pad_ before each button setting above. +# i.e. debug_pad_button_a= + +# Enable debug pad inputs to the guest +# 0 (default): Disabled, 1: Enabled +debug_pad_enabled = + +# Whether to enable or disable vibration +# 0: Disabled, 1 (default): Enabled +vibration_enabled = + +# Whether to enable or disable accurate vibrations +# 0 (default): Disabled, 1: Enabled +enable_accurate_vibrations = + +# Enables controller motion inputs +# 0: Disabled, 1 (default): Enabled +motion_enabled = + +# Defines the udp device's touch screen coordinate system for cemuhookudp devices +# - "min_x", "min_y", "max_x", "max_y" +touch_device= + +# for mapping buttons to touch inputs. +#touch_from_button_map=1 +#touch_from_button_maps_0_name=default +#touch_from_button_maps_0_count=2 +#touch_from_button_maps_0_bind_0=foo +#touch_from_button_maps_0_bind_1=bar +# etc. + +# List of Cemuhook UDP servers, delimited by ','. +# Default: 127.0.0.1:26760 +# Example: 127.0.0.1:26760,123.4.5.67:26761 +udp_input_servers = + +# Enable controlling an axis via a mouse input. +# 0 (default): Off, 1: On +mouse_panning = + +# Set mouse sensitivity. +# Default: 1.0 +mouse_panning_sensitivity = + +# Emulate an analog control stick from keyboard inputs. +# 0 (default): Disabled, 1: Enabled +emulate_analog_keyboard = + +# Enable mouse inputs to the guest +# 0 (default): Disabled, 1: Enabled +mouse_enabled = + +# Enable keyboard inputs to the guest +# 0 (default): Disabled, 1: Enabled +keyboard_enabled = + +[Core] +# Whether to use multi-core for CPU emulation +# 0: Disabled, 1 (default): Enabled +use_multi_core = + +# Enable unsafe extended guest system memory layout (8GB DRAM) +# 0 (default): Disabled, 1: Enabled +use_unsafe_extended_memory_layout = + +[Cpu] +# Adjusts various optimizations. +# Auto-select mode enables choice unsafe optimizations. +# Accurate enables only safe optimizations. +# Unsafe allows any unsafe optimizations. +# 0 (default): Auto-select, 1: Accurate, 2: Enable unsafe optimizations +cpu_accuracy = + +# Allow disabling safe optimizations. +# 0 (default): Disabled, 1: Enabled +cpu_debug_mode = + +# Enable inline page tables optimization (faster guest memory access) +# 0: Disabled, 1 (default): Enabled +cpuopt_page_tables = + +# Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps) +# 0: Disabled, 1 (default): Enabled +cpuopt_block_linking = + +# Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns) +# 0: Disabled, 1 (default): Enabled +cpuopt_return_stack_buffer = + +# Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture) +# 0: Disabled, 1 (default): Enabled +cpuopt_fast_dispatcher = + +# Enable context elimination CPU Optimization (reduce host memory use for guest context) +# 0: Disabled, 1 (default): Enabled +cpuopt_context_elimination = + +# Enable constant propagation CPU optimization (basic IR optimization) +# 0: Disabled, 1 (default): Enabled +cpuopt_const_prop = + +# Enable miscellaneous CPU optimizations (basic IR optimization) +# 0: Disabled, 1 (default): Enabled +cpuopt_misc_ir = + +# Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access) +# 0: Disabled, 1 (default): Enabled +cpuopt_reduce_misalign_checks = + +# Enable Host MMU Emulation (faster guest memory access) +# 0: Disabled, 1 (default): Enabled +cpuopt_fastmem = + +# Enable Host MMU Emulation for exclusive memory instructions (faster guest memory access) +# 0: Disabled, 1 (default): Enabled +cpuopt_fastmem_exclusives = + +# Enable fallback on failure of fastmem of exclusive memory instructions (faster guest memory access) +# 0: Disabled, 1 (default): Enabled +cpuopt_recompile_exclusives = + +# Enable optimization to ignore invalid memory accesses (faster guest memory access) +# 0: Disabled, 1 (default): Enabled +cpuopt_ignore_memory_aborts = + +# Enable unfuse FMA (improve performance on CPUs without FMA) +# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. +# 0: Disabled, 1 (default): Enabled +cpuopt_unsafe_unfuse_fma = + +# Enable faster FRSQRTE and FRECPE +# Only enabled if cpu_accuracy is set to Unsafe. +# 0: Disabled, 1 (default): Enabled +cpuopt_unsafe_reduce_fp_error = + +# Enable faster ASIMD instructions (32 bits only) +# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. +# 0: Disabled, 1 (default): Enabled +cpuopt_unsafe_ignore_standard_fpcr = + +# Enable inaccurate NaN handling +# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. +# 0: Disabled, 1 (default): Enabled +cpuopt_unsafe_inaccurate_nan = + +# Disable address space checks (64 bits only) +# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. +# 0: Disabled, 1 (default): Enabled +cpuopt_unsafe_fastmem_check = + +# Enable faster exclusive instructions +# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. +# 0: Disabled, 1 (default): Enabled +cpuopt_unsafe_ignore_global_monitor = + +[Renderer] +# Which backend API to use. +# 0: OpenGL (unsupported), 1 (default): Vulkan, 2: Null +backend = + +# Whether to enable asynchronous presentation (Vulkan only) +# 0: Off, 1 (default): On +async_presentation = + +# Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied). +# 0 (default): Disabled, 1: Enabled +force_max_clock = + +# Enable graphics API debugging mode. +# 0 (default): Disabled, 1: Enabled +debug = + +# Enable shader feedback. +# 0 (default): Disabled, 1: Enabled +renderer_shader_feedback = + +# Enable Nsight Aftermath crash dumps +# 0 (default): Disabled, 1: Enabled +nsight_aftermath = + +# Disable shader loop safety checks, executing the shader without loop logic changes +# 0 (default): Disabled, 1: Enabled +disable_shader_loop_safety_checks = + +# Which Vulkan physical device to use (defaults to 0) +vulkan_device = + +# 0: 0.5x (360p/540p) [EXPERIMENTAL] +# 1: 0.75x (540p/810p) [EXPERIMENTAL] +# 2 (default): 1x (720p/1080p) +# 3: 2x (1440p/2160p) +# 4: 3x (2160p/3240p) +# 5: 4x (2880p/4320p) +# 6: 5x (3600p/5400p) +# 7: 6x (4320p/6480p) +resolution_setup = + +# Pixel filter to use when up- or down-sampling rendered frames. +# 0: Nearest Neighbor +# 1 (default): Bilinear +# 2: Bicubic +# 3: Gaussian +# 4: ScaleForce +# 5: AMD FidelityFX™️ Super Resolution [Vulkan Only] +scaling_filter = + +# Anti-Aliasing (AA) +# 0 (default): None, 1: FXAA +anti_aliasing = + +# Whether to use fullscreen or borderless window mode +# 0 (Windows default): Borderless window, 1 (All other default): Exclusive fullscreen +fullscreen_mode = + +# Aspect ratio +# 0: Default (16:9), 1: Force 4:3, 2: Force 21:9, 3: Force 16:10, 4: Stretch to Window +aspect_ratio = + +# Anisotropic filtering +# 0: Default, 1: 2x, 2: 4x, 3: 8x, 4: 16x +max_anisotropy = + +# Whether to enable VSync or not. +# OpenGL: Values other than 0 enable VSync +# Vulkan: FIFO is selected if the requested mode is not supported by the driver. +# FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. +# FIFO Relaxed is similar to FIFO but allows tearing as it recovers from a slow down. +# Mailbox can have lower latency than FIFO and does not tear but may drop frames. +# Immediate (no synchronization) just presents whatever is available and can exhibit tearing. +# 0: Immediate (Off), 1 (Default): Mailbox (On), 2: FIFO, 3: FIFO Relaxed +use_vsync = + +# Selects the OpenGL shader backend. NV_gpu_program5 is required for GLASM. If NV_gpu_program5 is +# not available and GLASM is selected, GLSL will be used. +# 0: GLSL, 1 (default): GLASM, 2: SPIR-V +shader_backend = + +# Whether to allow asynchronous shader building. +# 0 (default): Off, 1: On +use_asynchronous_shaders = + +# Uses reactive flushing instead of predictive flushing. Allowing a more accurate syncing of memory. +# 0 (default): Off, 1: On +use_reactive_flushing = + +# NVDEC emulation. +# 0: Disabled, 1: CPU Decoding, 2 (default): GPU Decoding +nvdec_emulation = + +# Accelerate ASTC texture decoding. +# 0 (default): Off, 1: On +accelerate_astc = + +# Turns on the speed limiter, which will limit the emulation speed to the desired speed limit value +# 0: Off, 1: On (default) +use_speed_limit = + +# Limits the speed of the game to run no faster than this value as a percentage of target speed +# 1 - 9999: Speed limit as a percentage of target game speed. 100 (default) +speed_limit = + +# Whether to use disk based shader cache +# 0: Off, 1 (default): On +use_disk_shader_cache = + +# Which gpu accuracy level to use +# 0 (default): Normal, 1: High, 2: Extreme (Very slow) +gpu_accuracy = + +# Whether to use asynchronous GPU emulation +# 0 : Off (slow), 1 (default): On (fast) +use_asynchronous_gpu_emulation = + +# Inform the guest that GPU operations completed more quickly than they did. +# 0: Off, 1 (default): On +use_fast_gpu_time = + +# Force unmodified buffers to be flushed, which can cost performance. +# 0: Off (default), 1: On +use_pessimistic_flushes = + +# Whether to use garbage collection or not for GPU caches. +# 0 (default): Off, 1: On +use_caches_gc = + +# The clear color for the renderer. What shows up on the sides of the bottom screen. +# Must be in range of 0-255. Defaults to 0 for all. +bg_red = +bg_blue = +bg_green = + +[Audio] +# Which audio output engine to use. +# auto (default): Auto-select +# cubeb: Cubeb audio engine (if available) +# sdl2: SDL2 audio engine (if available) +# null: No audio output +output_engine = + +# Which audio device to use. +# auto (default): Auto-select +output_device = + +# Output volume. +# 100 (default): 100%, 0; mute +volume = + +[Data Storage] +# Whether to create a virtual SD card. +# 1: Yes, 0 (default): No +use_virtual_sd = + +# Whether or not to enable gamecard emulation +# 1: Yes, 0 (default): No +gamecard_inserted = + +# Whether or not the gamecard should be emulated as the current game +# If 'gamecard_inserted' is 0 this setting is irrelevant +# 1: Yes, 0 (default): No +gamecard_current_game = + +# Path to an XCI file to use as the gamecard +# If 'gamecard_inserted' is 0 this setting is irrelevant +# If 'gamecard_current_game' is 1 this setting is irrelevant +gamecard_path = + +[System] +# Whether the system is docked +# 1: Yes, 0 (default): No +use_docked_mode = + +# Sets the seed for the RNG generator built into the switch +# rng_seed will be ignored and randomly generated if rng_seed_enabled is false +rng_seed_enabled = +rng_seed = + +# Sets the current time (in seconds since 12:00 AM Jan 1, 1970) that will be used by the time service +# This will auto-increment, with the time set being the time the game is started +# This override will only occur if custom_rtc_enabled is true, otherwise the current time is used +custom_rtc_enabled = +custom_rtc = + +# Sets the systems language index +# 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese, +# 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French, +# 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese, 17: Brazilian Portuguese +language_index = + +# The system region that yuzu will use during emulation +# -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan +region_index = + +# The system time zone that yuzu will use during emulation +# 0: Auto-select (default), 1: Default (system archive value), Others: Index for specified time zone +time_zone_index = + +# Sets the sound output mode. +# 0: Mono, 1 (default): Stereo, 2: Surround +sound_index = + +[Miscellaneous] +# A filter which removes logs below a certain logging level. +# Examples: *:Debug Kernel.SVC:Trace Service.*:Critical +log_filter = *:Trace + +# Use developer keys +# 0 (default): Disabled, 1: Enabled +use_dev_keys = + +[Debugging] +# Record frame time data, can be found in the log directory. Boolean value +record_frame_times = +# Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them +dump_exefs=false +# Determines whether or not yuzu will dump all NSOs it attempts to load while loading them +dump_nso=false +# Determines whether or not yuzu will save the filesystem access log. +enable_fs_access_log=false +# Enables verbose reporting services +reporting_services = +# Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode +# false: Retail/Normal Mode (default), true: Kiosk Mode +quest_flag = +# Determines whether debug asserts should be enabled, which will throw an exception on asserts. +# false: Disabled (default), true: Enabled +use_debug_asserts = +# Determines whether unimplemented HLE service calls should be automatically stubbed. +# false: Disabled (default), true: Enabled +use_auto_stub = +# Enables/Disables the macro JIT compiler +disable_macro_jit=false +# Determines whether to enable the GDB stub and wait for the debugger to attach before running. +# false: Disabled (default), true: Enabled +use_gdbstub=false +# The port to use for the GDB server, if it is enabled. +gdbstub_port=6543 + +[WebService] +# Whether or not to enable telemetry +# 0: No, 1 (default): Yes +enable_telemetry = +# URL for Web API +web_api_url = +# Username and token for yuzu Web Service +# See https://profile.yuzu-emu.org/ for more info +yuzu_username = +yuzu_token = + +[Network] +# Name of the network interface device to use with yuzu LAN play. +# e.g. On *nix: 'enp7s0', 'wlp6s0u1u3u3', 'lo' +# e.g. On Windows: 'Ethernet', 'Wi-Fi' +network_interface = + +[AddOns] +# Used to disable add-ons +# List of title IDs of games that will have add-ons disabled (separated by '|'): +title_ids = +# For each title ID, have a key/value pair called `disabled_` equal to the names of the add-ons to disable (sep. by '|') +# e.x. disabled_0100000000010000 = Update|DLC <- disables Updates and + on Super Mario Odyssey +)"; +} // namespace DefaultINI + + +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include + +#include "common/settings.h" + +class INIReader; + +class Config { + bool LoadINI(const std::string& default_contents = "", bool retry = true); + +public: + enum class ConfigType { + GlobalConfig, + PerGameConfig, + InputProfile, + }; + + explicit Config(const std::string& config_name = "config", + ConfigType config_type = ConfigType::GlobalConfig); + ~Config(); + + void Initialize(const std::string& config_name); + +private: + /** + * Applies a value read from the config to a Setting. + * + * @param group The name of the INI group + * @param setting The yuzu setting to modify + */ + template + void ReadSetting(const std::string& group, YuzuSettings::Setting& setting); + + void ReadValues(); + + const ConfigType type; + std::unique_ptr config; + std::string config_loc; + const bool global; +}; diff --git a/src/ios/Eden/Wrapper/Config/Config.mm b/src/ios/Eden/Wrapper/Config/Config.mm new file mode 100644 index 0000000000..3460ee08de --- /dev/null +++ b/src/ios/Eden/Wrapper/Config/Config.mm @@ -0,0 +1,330 @@ +// +// Config.m - Sudachi +// Created by Jarrod Norwell on 13/3/2024. +// + +#import "Config.h" + +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include + +#include +#include "common/fs/file.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" +#include "common/logging/log.h" +#include "common/settings.h" +#include "common/settings_enums.h" +#include "core/hle/service/acc/profile_manager.h" +#include "input_common/main.h" + +namespace FS = Common::FS; + +Config::Config(const std::string& config_name, ConfigType config_type) + : type(config_type), global{config_type == ConfigType::GlobalConfig} { + Initialize(config_name); +} + +Config::~Config() = default; + +bool Config::LoadINI(const std::string& default_contents, bool retry) { + void(FS::CreateParentDir(config_loc)); + config = std::make_unique(FS::PathToUTF8String(config_loc)); + const auto config_loc_str = FS::PathToUTF8String(config_loc); + if (config->ParseError() < 0) { + if (retry) { + LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...", + config_loc_str); + + void(FS::CreateParentDir(config_loc)); + void(FS::WriteStringToFile(config_loc, FS::FileType::TextFile, default_contents)); + + config = std::make_unique(config_loc_str); + + return LoadINI(default_contents, false); + } + LOG_ERROR(Config, "Failed."); + return false; + } + LOG_INFO(Config, "Successfully loaded {}", config_loc_str); + return true; +} + +template <> +void Config::ReadSetting(const std::string& group, YuzuSettings::Setting& setting) { + std::string setting_value = config->Get(group, setting.GetLabel(), setting.GetDefault()); + if (setting_value.empty()) { + setting_value = setting.GetDefault(); + } + setting = std::move(setting_value); +} + +template <> +void Config::ReadSetting(const std::string& group, YuzuSettings::Setting& setting) { + setting = config->GetBoolean(group, setting.GetLabel(), setting.GetDefault()); +} + +template +void Config::ReadSetting(const std::string& group, YuzuSettings::Setting& setting) { + setting = static_cast( + config->GetInteger(group, setting.GetLabel(), static_cast(setting.GetDefault()))); +} + +void Config::ReadValues() { + ReadSetting("ControlsGeneral", YuzuSettings::values.mouse_enabled); + ReadSetting("ControlsGeneral", YuzuSettings::values.touch_device); + ReadSetting("ControlsGeneral", YuzuSettings::values.keyboard_enabled); + ReadSetting("ControlsGeneral", YuzuSettings::values.debug_pad_enabled); + ReadSetting("ControlsGeneral", YuzuSettings::values.vibration_enabled); + ReadSetting("ControlsGeneral", YuzuSettings::values.enable_accurate_vibrations); + ReadSetting("ControlsGeneral", YuzuSettings::values.motion_enabled); + YuzuSettings::values.touchscreen.enabled = + config->GetBoolean("ControlsGeneral", "touch_enabled", true); + YuzuSettings::values.touchscreen.rotation_angle = + config->GetInteger("ControlsGeneral", "touch_angle", 0); + YuzuSettings::values.touchscreen.diameter_x = + config->GetInteger("ControlsGeneral", "touch_diameter_x", 15); + YuzuSettings::values.touchscreen.diameter_y = + config->GetInteger("ControlsGeneral", "touch_diameter_y", 15); + + int num_touch_from_button_maps = + config->GetInteger("ControlsGeneral", "touch_from_button_map", 0); + if (num_touch_from_button_maps > 0) { + for (int i = 0; i < num_touch_from_button_maps; ++i) { + YuzuSettings::TouchFromButtonMap map; + map.name = config->Get("ControlsGeneral", + std::string("touch_from_button_maps_") + std::to_string(i) + + std::string("_name"), + "default"); + const int num_touch_maps = config->GetInteger( + "ControlsGeneral", + std::string("touch_from_button_maps_") + std::to_string(i) + std::string("_count"), + 0); + map.buttons.reserve(num_touch_maps); + + for (int j = 0; j < num_touch_maps; ++j) { + std::string touch_mapping = + config->Get("ControlsGeneral", + std::string("touch_from_button_maps_") + std::to_string(i) + + std::string("_bind_") + std::to_string(j), + ""); + map.buttons.emplace_back(std::move(touch_mapping)); + } + + YuzuSettings::values.touch_from_button_maps.emplace_back(std::move(map)); + } + } else { + YuzuSettings::values.touch_from_button_maps.emplace_back( + YuzuSettings::TouchFromButtonMap{"default", {}}); + num_touch_from_button_maps = 1; + } + YuzuSettings::values.touch_from_button_map_index = std::clamp( + YuzuSettings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); + + ReadSetting("ControlsGeneral", YuzuSettings::values.udp_input_servers); + + // Data Storage + ReadSetting("Data Storage", YuzuSettings::values.use_virtual_sd); + FS::SetYuzuPath(FS::YuzuPath::NANDDir, + config->Get("Data Storage", "nand_directory", + FS::GetYuzuPathString(FS::YuzuPath::NANDDir))); + FS::SetYuzuPath(FS::YuzuPath::SDMCDir, + config->Get("Data Storage", "sdmc_directory", + FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))); + FS::SetYuzuPath(FS::YuzuPath::LoadDir, + config->Get("Data Storage", "load_directory", + FS::GetYuzuPathString(FS::YuzuPath::LoadDir))); + FS::SetYuzuPath(FS::YuzuPath::DumpDir, + config->Get("Data Storage", "dump_directory", + FS::GetYuzuPathString(FS::YuzuPath::DumpDir))); + ReadSetting("Data Storage", YuzuSettings::values.gamecard_inserted); + ReadSetting("Data Storage", YuzuSettings::values.gamecard_current_game); + ReadSetting("Data Storage", YuzuSettings::values.gamecard_path); + + // System + ReadSetting("System", YuzuSettings::values.current_user); + YuzuSettings::values.current_user = std::clamp(YuzuSettings::values.current_user.GetValue(), 0, + Service::Account::MAX_USERS - 1); + + // Enable docked mode by default on iOS + YuzuSettings::values.use_docked_mode.SetValue(config->GetBoolean("System", "use_docked_mode", false) + ? YuzuSettings::ConsoleMode::Docked + : YuzuSettings::ConsoleMode::Handheld); + + const auto rng_seed_enabled = config->GetBoolean("System", "rng_seed_enabled", false); + if (rng_seed_enabled) { + YuzuSettings::values.rng_seed.SetValue(config->GetInteger("System", "rng_seed", 0)); + } else { + YuzuSettings::values.rng_seed.SetValue(0); + } + YuzuSettings::values.rng_seed_enabled.SetValue(rng_seed_enabled); + + const auto custom_rtc_enabled = config->GetBoolean("System", "custom_rtc_enabled", false); + if (custom_rtc_enabled) { + YuzuSettings::values.custom_rtc = config->GetInteger("System", "custom_rtc", 0); + } else { + YuzuSettings::values.custom_rtc = 0; + } + YuzuSettings::values.custom_rtc_enabled = custom_rtc_enabled; + + ReadSetting("System", YuzuSettings::values.language_index); + ReadSetting("System", YuzuSettings::values.region_index); + ReadSetting("System", YuzuSettings::values.time_zone_index); + ReadSetting("System", YuzuSettings::values.sound_index); + + // Core + ReadSetting("Core", YuzuSettings::values.use_multi_core); + ReadSetting("Core", YuzuSettings::values.memory_layout_mode); + + // Cpu + ReadSetting("Cpu", YuzuSettings::values.cpu_accuracy); + ReadSetting("Cpu", YuzuSettings::values.cpu_debug_mode); + ReadSetting("Cpu", YuzuSettings::values.cpuopt_page_tables); + ReadSetting("Cpu", YuzuSettings::values.cpuopt_block_linking); + ReadSetting("Cpu", YuzuSettings::values.cpuopt_return_stack_buffer); + ReadSetting("Cpu", YuzuSettings::values.cpuopt_fast_dispatcher); + ReadSetting("Cpu", YuzuSettings::values.cpuopt_context_elimination); + ReadSetting("Cpu", YuzuSettings::values.cpuopt_const_prop); + ReadSetting("Cpu", YuzuSettings::values.cpuopt_misc_ir); + ReadSetting("Cpu", YuzuSettings::values.cpuopt_reduce_misalign_checks); + ReadSetting("Cpu", YuzuSettings::values.cpuopt_fastmem); + ReadSetting("Cpu", YuzuSettings::values.cpuopt_fastmem_exclusives); + ReadSetting("Cpu", YuzuSettings::values.cpuopt_recompile_exclusives); + ReadSetting("Cpu", YuzuSettings::values.cpuopt_ignore_memory_aborts); + ReadSetting("Cpu", YuzuSettings::values.cpuopt_unsafe_unfuse_fma); + ReadSetting("Cpu", YuzuSettings::values.cpuopt_unsafe_reduce_fp_error); + ReadSetting("Cpu", YuzuSettings::values.cpuopt_unsafe_ignore_standard_fpcr); + ReadSetting("Cpu", YuzuSettings::values.cpuopt_unsafe_inaccurate_nan); + ReadSetting("Cpu", YuzuSettings::values.cpuopt_unsafe_fastmem_check); + ReadSetting("Cpu", YuzuSettings::values.cpuopt_unsafe_ignore_global_monitor); + + // Renderer + ReadSetting("Renderer", YuzuSettings::values.renderer_backend); + ReadSetting("Renderer", YuzuSettings::values.renderer_debug); + ReadSetting("Renderer", YuzuSettings::values.renderer_shader_feedback); + ReadSetting("Renderer", YuzuSettings::values.enable_nsight_aftermath); + ReadSetting("Renderer", YuzuSettings::values.disable_shader_loop_safety_checks); + ReadSetting("Renderer", YuzuSettings::values.vulkan_device); + + ReadSetting("Renderer", YuzuSettings::values.resolution_setup); + ReadSetting("Renderer", YuzuSettings::values.scaling_filter); + ReadSetting("Renderer", YuzuSettings::values.fsr_sharpening_slider); + ReadSetting("Renderer", YuzuSettings::values.anti_aliasing); + ReadSetting("Renderer", YuzuSettings::values.fullscreen_mode); + ReadSetting("Renderer", YuzuSettings::values.aspect_ratio); + ReadSetting("Renderer", YuzuSettings::values.max_anisotropy); + ReadSetting("Renderer", YuzuSettings::values.use_speed_limit); + ReadSetting("Renderer", YuzuSettings::values.speed_limit); + ReadSetting("Renderer", YuzuSettings::values.use_disk_shader_cache); + ReadSetting("Renderer", YuzuSettings::values.use_asynchronous_gpu_emulation); + ReadSetting("Renderer", YuzuSettings::values.vsync_mode); + ReadSetting("Renderer", YuzuSettings::values.shader_backend); + ReadSetting("Renderer", YuzuSettings::values.use_asynchronous_shaders); + ReadSetting("Renderer", YuzuSettings::values.nvdec_emulation); + ReadSetting("Renderer", YuzuSettings::values.use_fast_gpu_time); + ReadSetting("Renderer", YuzuSettings::values.use_vulkan_driver_pipeline_cache); + + ReadSetting("Renderer", YuzuSettings::values.bg_red); + ReadSetting("Renderer", YuzuSettings::values.bg_green); + ReadSetting("Renderer", YuzuSettings::values.bg_blue); + + // Use GPU accuracy normal by default on Android + YuzuSettings::values.gpu_accuracy = static_cast(config->GetInteger( + "Renderer", "gpu_accuracy", static_cast(YuzuSettings::GpuAccuracy::Normal))); + + // Use GPU default anisotropic filtering on Android + YuzuSettings::values.max_anisotropy = + static_cast(config->GetInteger("Renderer", "max_anisotropy", 1)); + + // Disable ASTC compute by default on iOS + YuzuSettings::values.accelerate_astc.SetValue( + config->GetBoolean("Renderer", "accelerate_astc", false) ? YuzuSettings::AstcDecodeMode::Gpu + : YuzuSettings::AstcDecodeMode::Cpu); + + // Enable asynchronous presentation by default on Android + YuzuSettings::values.async_presentation = + config->GetBoolean("Renderer", "async_presentation", true); + + // Disable force_max_clock by default on Android + YuzuSettings::values.renderer_force_max_clock = + config->GetBoolean("Renderer", "force_max_clock", false); + + // Disable use_reactive_flushing by default on Android + YuzuSettings::values.use_reactive_flushing = + config->GetBoolean("Renderer", "use_reactive_flushing", false); + + // Audio + ReadSetting("Audio", YuzuSettings::values.sink_id); + ReadSetting("Audio", YuzuSettings::values.audio_output_device_id); + ReadSetting("Audio", YuzuSettings::values.volume); + + // Miscellaneous + // log_filter has a different default here than from common + YuzuSettings::values.log_filter = "*:Info"; + ReadSetting("Miscellaneous", YuzuSettings::values.use_dev_keys); + + // Debugging + YuzuSettings::values.record_frame_times = + config->GetBoolean("Debugging", "record_frame_times", false); + ReadSetting("Debugging", YuzuSettings::values.dump_exefs); + ReadSetting("Debugging", YuzuSettings::values.dump_nso); + ReadSetting("Debugging", YuzuSettings::values.enable_fs_access_log); + ReadSetting("Debugging", YuzuSettings::values.reporting_services); + ReadSetting("Debugging", YuzuSettings::values.quest_flag); + ReadSetting("Debugging", YuzuSettings::values.use_debug_asserts); + ReadSetting("Debugging", YuzuSettings::values.use_auto_stub); + ReadSetting("Debugging", YuzuSettings::values.disable_macro_jit); + ReadSetting("Debugging", YuzuSettings::values.disable_macro_hle); + ReadSetting("Debugging", YuzuSettings::values.use_gdbstub); + ReadSetting("Debugging", YuzuSettings::values.gdbstub_port); + + const auto title_list = config->Get("AddOns", "title_ids", ""); + std::stringstream ss(title_list); + std::string line; + while (std::getline(ss, line, '|')) { + const auto title_id = std::strtoul(line.c_str(), nullptr, 16); + const auto disabled_list = config->Get("AddOns", "disabled_" + line, ""); + + std::stringstream inner_ss(disabled_list); + std::string inner_line; + std::vector out; + while (std::getline(inner_ss, inner_line, '|')) { + out.push_back(inner_line); + } + + YuzuSettings::values.disabled_addons.insert_or_assign(title_id, out); + } + + // Web Service + ReadSetting("WebService", YuzuSettings::values.enable_telemetry); + ReadSetting("WebService", YuzuSettings::values.web_api_url); + ReadSetting("WebService", YuzuSettings::values.yuzu_username); + ReadSetting("WebService", YuzuSettings::values.yuzu_token); + + // Network + ReadSetting("Network", YuzuSettings::values.network_interface); +} + +void Config::Initialize(const std::string& config_name) { + const auto fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir); + const auto config_file = fmt::format("{}.ini", config_name); + + switch (type) { + case ConfigType::GlobalConfig: + config_loc = FS::PathToUTF8String(fs_config_loc / config_file); + break; + case ConfigType::PerGameConfig: + config_loc = FS::PathToUTF8String(fs_config_loc / "custom" / FS::ToU8String(config_file)); + break; + case ConfigType::InputProfile: + config_loc = FS::PathToUTF8String(fs_config_loc / "input" / config_file); + LoadINI(DefaultINI::android_config_file); + return; + } + LoadINI(DefaultINI::android_config_file); + ReadValues(); +} diff --git a/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.h b/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.h new file mode 100644 index 0000000000..3965b6c2bb --- /dev/null +++ b/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.h @@ -0,0 +1,10 @@ +// +// DirectoryManager.h - Sudachi +// Created by Jarrod Norwell on 1/18/24. +// + +#pragma once + +namespace DirectoryManager { +const char* AppUIDirectory(void); +} diff --git a/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.mm b/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.mm new file mode 100644 index 0000000000..428244fea1 --- /dev/null +++ b/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.mm @@ -0,0 +1,16 @@ +// +// DirectoryManager.mm - Sudachi +// Created by Jarrod Norwell on 1/18/24. +// + +#import + +#import "DirectoryManager.h" + +NSURL *DocumentsDirectory() { + return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject]; +} + +const char* DirectoryManager::AppUIDirectory(void) { + return [[DocumentsDirectory() path] UTF8String]; +} diff --git a/src/ios/Eden/Wrapper/EmulationSession/EmulationSession.h b/src/ios/Eden/Wrapper/EmulationSession/EmulationSession.h new file mode 100644 index 0000000000..291d414b37 --- /dev/null +++ b/src/ios/Eden/Wrapper/EmulationSession/EmulationSession.h @@ -0,0 +1,98 @@ +// +// EmulationSession.h - Sudachi +// Created by Jarrod Norwell on 1/20/24. +// + +#pragma once + +#import + +#import +#import "../EmulationWindow/EmulationWindow.h" + +#include "common/detached_tasks.h" +#include "core/core.h" +#include "core/file_sys/registered_cache.h" +#include "core/hle/service/acc/profile_manager.h" +#include "core/perf_stats.h" +#include "frontend_common/content_manager.h" +#include "video_core/rasterizer_interface.h" + +class EmulationSession final { +public: + explicit EmulationSession(); + ~EmulationSession() = default; + + static EmulationSession& GetInstance(); + const Core::System& System() const; + Core::System& System(); + FileSys::ManualContentProvider* GetContentProvider(); + InputCommon::InputSubsystem& GetInputSubsystem(); + + const EmulationWindow& Window() const; + EmulationWindow& Window(); + CA::MetalLayer* NativeWindow() const; + void SetNativeWindow(CA::MetalLayer* native_window, CGSize size); + void SurfaceChanged(); + + void InitializeGpuDriver(); + + bool IsRunning() const; + bool IsPaused() const; + void PauseEmulation(); + void UnPauseEmulation(); + void HaltEmulation(); + void RunEmulation(); + void ShutdownEmulation(); + + const Core::PerfStatsResults& PerfStats(); + void ConfigureFilesystemProvider(const std::string& filepath); + void InitializeSystem(bool reload); + void SetAppletId(int applet_id); + Core::SystemResultStatus InitializeEmulation(const std::string& filepath, + const std::size_t program_index, + const bool frontend_initiated); + Core::SystemResultStatus BootOS(); + + static void OnEmulationStarted(); + static u64 GetProgramId(std::string programId); + bool IsInitialized() { return is_initialized; }; + + bool IsHandheldOnly(); + void SetDeviceType([[maybe_unused]] int index, int type); + void OnGamepadConnectEvent([[maybe_unused]] int index); + void OnGamepadDisconnectEvent([[maybe_unused]] int index); +private: + static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max); + static void OnEmulationStopped(Core::SystemResultStatus result); + static void ChangeProgram(std::size_t program_index); + +private: + // Window management + std::unique_ptr m_window; + CA::MetalLayer* m_native_window{}; + + // Core emulation + Core::System m_system; + InputCommon::InputSubsystem m_input_subsystem; + Common::DetachedTasks m_detached_tasks; + Core::PerfStatsResults m_perf_stats{}; + std::shared_ptr m_vfs; + Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized}; + std::atomic m_is_running = false; + std::atomic m_is_paused = false; + std::unique_ptr m_manual_provider; + int m_applet_id{1}; + + // GPU driver parameters + std::shared_ptr m_vulkan_library; + + // Synchronization + std::condition_variable_any m_cv; + mutable std::mutex m_mutex; + bool is_initialized = false; + CGSize m_size; + + // Program index for next boot + std::atomic m_next_program_index = -1; +}; diff --git a/src/ios/Eden/Wrapper/EmulationSession/EmulationSession.mm b/src/ios/Eden/Wrapper/EmulationSession/EmulationSession.mm new file mode 100644 index 0000000000..18793ca9fe --- /dev/null +++ b/src/ios/Eden/Wrapper/EmulationSession/EmulationSession.mm @@ -0,0 +1,528 @@ +// +// EmulationSession.m - Sudachi +// Created by Jarrod Norwell on 1/20/24. +// + +#import "EmulationSession.h" + +#include + +#include +#include +#include +#include +#include + +#include "common/fs/fs.h" +#include "core/file_sys/patch_manager.h" +#include "core/file_sys/savedata_factory.h" +#include "core/loader/nro.h" +#include "frontend_common/content_manager.h" + +#include "common/detached_tasks.h" +#include "common/dynamic_library.h" +#include "common/fs/path_util.h" +#include "common/logging/backend.h" +#include "common/logging/log.h" +#include "common/microprofile.h" +#include "common/scm_rev.h" +#include "common/scope_exit.h" +#include "common/settings.h" +#include "common/string_util.h" +#include "core/core.h" +#include "core/cpu_manager.h" +#include "core/crypto/key_manager.h" +#include "core/file_sys/card_image.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/fs_filesystem.h" +#include "core/file_sys/submission_package.h" +#include "core/file_sys/vfs/vfs.h" +#include "core/file_sys/vfs/vfs_real.h" +#include "core/frontend/applets/cabinet.h" +#include "core/frontend/applets/controller.h" +#include "core/frontend/applets/error.h" +#include "core/frontend/applets/general.h" +#include "core/frontend/applets/mii_edit.h" +#include "core/frontend/applets/profile_select.h" +#include "core/frontend/applets/software_keyboard.h" +#include "core/frontend/applets/web_browser.h" +#include "core/hle/service/am/applet_manager.h" +#include "core/hle/service/am/frontend/applets.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/loader/loader.h" +#include "frontend_common/yuzu_config.h" +#include "hid_core/frontend/emulated_controller.h" +#include "hid_core/hid_core.h" +#include "hid_core/hid_types.h" +#include "video_core/renderer_base.h" +#include "video_core/renderer_vulkan/renderer_vulkan.h" +#include "video_core/vulkan_common/vulkan_instance.h" +#include "video_core/vulkan_common/vulkan_surface.h" + +#define jconst [[maybe_unused]] const auto +#define jauto [[maybe_unused]] auto + +static EmulationSession s_instance; + +EmulationSession::EmulationSession() { + m_vfs = std::make_shared(); +} + +EmulationSession& EmulationSession::GetInstance() { + return s_instance; +} + +const Core::System& EmulationSession::System() const { + return m_system; +} + +Core::System& EmulationSession::System() { + return m_system; +} + +FileSys::ManualContentProvider* EmulationSession::GetContentProvider() { + return m_manual_provider.get(); +} + +InputCommon::InputSubsystem& EmulationSession::GetInputSubsystem() { + return m_input_subsystem; +} + +const EmulationWindow& EmulationSession::Window() const { + return *m_window; +} + +EmulationWindow& EmulationSession::Window() { + return *m_window; +} + +CA::MetalLayer* EmulationSession::NativeWindow() const { + return m_native_window; +} + +void EmulationSession::SetNativeWindow(CA::MetalLayer* native_window, CGSize size) { + m_native_window = native_window; + m_size = size; +} + +void EmulationSession::InitializeGpuDriver() { + m_vulkan_library = std::make_shared(dlopen("@executable_path/Frameworks/MoltenVK", RTLD_NOW)); +} + +bool EmulationSession::IsRunning() const { + return m_is_running; +} + +bool EmulationSession::IsPaused() const { + return m_is_running && m_is_paused; +} + +const Core::PerfStatsResults& EmulationSession::PerfStats() { + m_perf_stats = m_system.GetAndResetPerfStats(); + return m_perf_stats; +} + +void EmulationSession::SurfaceChanged() { + if (!IsRunning()) { + return; + } + m_window->OnSurfaceChanged(m_native_window, m_size); +} + +void EmulationSession::ConfigureFilesystemProvider(const std::string& filepath) { + const auto file = m_system.GetFilesystem()->OpenFile(filepath, FileSys::OpenMode::Read); + if (!file) { + return; + } + + auto loader = Loader::GetLoader(m_system, file); + if (!loader) { + return; + } + + const auto file_type = loader->GetFileType(); + if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) { + return; + } + + u64 program_id = 0; + const auto res2 = loader->ReadProgramId(program_id); + if (res2 == Loader::ResultStatus::Success && file_type == Loader::FileType::NCA) { + m_manual_provider->AddEntry(FileSys::TitleType::Application, + FileSys::GetCRTypeFromNCAType(FileSys::NCA{file}.GetType()), + program_id, file); + } else if (res2 == Loader::ResultStatus::Success && + (file_type == Loader::FileType::XCI || file_type == Loader::FileType::NSP)) { + const auto nsp = file_type == Loader::FileType::NSP + ? std::make_shared(file) + : FileSys::XCI{file}.GetSecurePartitionNSP(); + for (const auto& title : nsp->GetNCAs()) { + for (const auto& entry : title.second) { + m_manual_provider->AddEntry(entry.first.first, entry.first.second, title.first, + entry.second->GetBaseFile()); + } + } + } +} + +void EmulationSession::InitializeSystem(bool reload) { + if (!reload) { + SDL_SetMainReady(); + + // Initialize logging system + Common::Log::Initialize(); + Common::Log::SetColorConsoleBackendEnabled(true); + Common::Log::Start(); + } + + // Initialize filesystem. + m_system.SetFilesystem(m_vfs); + m_system.GetUserChannel().clear(); + m_manual_provider = std::make_unique(); + m_system.SetContentProvider(std::make_unique()); + m_system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual, + m_manual_provider.get()); + m_system.GetFileSystemController().CreateFactories(*m_vfs); + + is_initialized = true; +} + +void EmulationSession::SetAppletId(int applet_id) { + m_applet_id = applet_id; + m_system.GetFrontendAppletHolder().SetCurrentAppletId( + static_cast(m_applet_id)); +} + +Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string& filepath, + const std::size_t program_index, + const bool frontend_initiated) { + std::scoped_lock lock(m_mutex); + + // Create the render window. + m_window = std::make_unique(&m_input_subsystem, m_native_window, m_size, m_vulkan_library); + + // Initialize system. + m_system.SetShuttingDown(false); + m_system.ApplySettings(); + YuzuSettings::LogSettings(); + m_system.HIDCore().ReloadInputDevices(); + m_system.SetFrontendAppletSet({ + nullptr, // Amiibo Settings + nullptr, // Controller Selector + nullptr, // Error Display + nullptr, // Mii Editor + nullptr, // Parental Controls + nullptr, // Photo Viewer + nullptr, // Profile Selector + nullptr, // std::move(android_keyboard), // Software Keyboard + nullptr, // Web Browser + }); + + // Initialize filesystem. + ConfigureFilesystemProvider(filepath); + + // Load the ROM. + Service::AM::FrontendAppletParameters params{ + .applet_id = static_cast(m_applet_id), + .launch_type = frontend_initiated ? Service::AM::LaunchType::FrontendInitiated + : Service::AM::LaunchType::ApplicationInitiated, + .program_index = static_cast(program_index), + }; + m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath, params); + if (m_load_result != Core::SystemResultStatus::Success) { + return m_load_result; + } + + // Complete initialization. + m_system.GPU().Start(); + m_system.GetCpuManager().OnGpuReady(); + m_system.RegisterExitCallback([&] { HaltEmulation(); }); + + if (YuzuSettings::values.use_disk_shader_cache.GetValue()) { + m_system.Renderer().ReadRasterizer()->LoadDiskResources( + m_system.GetApplicationProcessProgramID(), std::stop_token{}, + [](VideoCore::LoadCallbackStage, size_t value, size_t total) {}); + } + + // Register an ExecuteProgram callback such that Core can execute a sub-program + m_system.RegisterExecuteProgramCallback([&](std::size_t program_index_) { + m_next_program_index = program_index_; + EmulationSession::GetInstance().HaltEmulation(); + ChangeProgram(m_next_program_index); + }); + + OnEmulationStarted(); + return Core::SystemResultStatus::Success; +} + + +Core::SystemResultStatus EmulationSession::BootOS() { + std::scoped_lock lock(m_mutex); + + // Create the render window. + m_window = std::make_unique(&m_input_subsystem, m_native_window, m_size, m_vulkan_library); + + // Initialize system. + m_system.SetShuttingDown(false); + m_system.ApplySettings(); + YuzuSettings::LogSettings(); + m_system.HIDCore().ReloadInputDevices(); + m_system.SetFrontendAppletSet({ + nullptr, // Amiibo Settings + nullptr, // Controller Selector + nullptr, // Error Display + nullptr, // Mii Editor + nullptr, // Parental Controls + nullptr, // Photo Viewer + nullptr, // Profile Selector + nullptr, // std::move(android_keyboard), // Software Keyboard + nullptr, // Web Browser + }); + + constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); + auto bis_system = m_system.GetFileSystemController().GetSystemNANDContents(); + + auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program); + + m_system.GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::QLaunch); + + const auto filename = qlaunch_applet_nca->GetFullPath(); + + auto params = Service::AM::FrontendAppletParameters { + .program_id = QLaunchId, + .applet_id = Service::AM::AppletId::QLaunch, + .applet_type = Service::AM::AppletType::LibraryApplet + }; + + m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filename, params); + + if (m_load_result != Core::SystemResultStatus::Success) { + return m_load_result; + } + + // Complete initialization. + m_system.GPU().Start(); + m_system.GetCpuManager().OnGpuReady(); + m_system.RegisterExitCallback([&] { HaltEmulation(); }); + + if (YuzuSettings::values.use_disk_shader_cache.GetValue()) { + m_system.Renderer().ReadRasterizer()->LoadDiskResources( + m_system.GetApplicationProcessProgramID(), std::stop_token{}, + [](VideoCore::LoadCallbackStage, size_t value, size_t total) {}); + } + + // Register an ExecuteProgram callback such that Core can execute a sub-program + m_system.RegisterExecuteProgramCallback([&](std::size_t program_index_) { + m_next_program_index = program_index_; + EmulationSession::GetInstance().HaltEmulation(); + }); + + OnEmulationStarted(); + return Core::SystemResultStatus::Success; +} + +void EmulationSession::ShutdownEmulation() { + std::scoped_lock lock(m_mutex); + + if (m_next_program_index != -1) { + ChangeProgram(m_next_program_index); + m_next_program_index = -1; + } + + m_is_running = false; + + // Unload user input. + m_system.HIDCore().UnloadInputDevices(); + + // Enable all controllers + m_system.HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); + + // Shutdown the main emulated process + if (m_load_result == Core::SystemResultStatus::Success) { + m_system.DetachDebugger(); + m_system.ShutdownMainProcess(); + m_detached_tasks.WaitForAllTasks(); + m_load_result = Core::SystemResultStatus::ErrorNotInitialized; + m_window.reset(); + OnEmulationStopped(Core::SystemResultStatus::Success); + return; + } + + // Tear down the render window. + m_window.reset(); +} + +void EmulationSession::PauseEmulation() { + std::scoped_lock lock(m_mutex); + m_system.Pause(); + m_is_paused = true; +} + +void EmulationSession::UnPauseEmulation() { + std::scoped_lock lock(m_mutex); + m_system.Run(); + m_is_paused = false; +} + +void EmulationSession::HaltEmulation() { + std::scoped_lock lock(m_mutex); + m_is_running = false; + m_cv.notify_one(); +} + +void EmulationSession::RunEmulation() { + { + std::scoped_lock lock(m_mutex); + m_is_running = true; + } + + // Load the disk shader cache. + if (YuzuSettings::values.use_disk_shader_cache.GetValue()) { + LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); + m_system.Renderer().ReadRasterizer()->LoadDiskResources( + m_system.GetApplicationProcessProgramID(), std::stop_token{}, LoadDiskCacheProgress); + LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0); + } + + void(m_system.Run()); + + if (m_system.DebuggerEnabled()) { + m_system.InitializeDebugger(); + } + + while (true) { + { + [[maybe_unused]] std::unique_lock lock(m_mutex); + if (m_cv.wait_for(lock, std::chrono::milliseconds(800), + [&]() { return !m_is_running; })) { + // Emulation halted. + break; + } + } + } + + // Reset current applet ID. + m_applet_id = static_cast(Service::AM::AppletId::Application); +} + +void EmulationSession::LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, + int max) { + +} + +void EmulationSession::OnEmulationStarted() { + +} + +void EmulationSession::OnEmulationStopped(Core::SystemResultStatus result) { + +} + +void EmulationSession::ChangeProgram(std::size_t program_index) { + LOG_INFO(Frontend, "Trying To Switch Program"); + // Halt current emulation session + EmulationSession::GetInstance().HaltEmulation(); + // Save the current state if necessary + + // Shutdown the current emulation session cleanly + // Update the program index + EmulationSession::GetInstance().m_next_program_index = program_index; + + // Initialize the new program + // Start the new emulation session + EmulationSession::GetInstance().RunEmulation(); +} + +u64 EmulationSession::GetProgramId(std::string programId) { + try { + return std::stoull(programId); + } catch (...) { + return 0; + } +} + +static Core::SystemResultStatus RunEmulation(const std::string& filepath, + const size_t program_index, + const bool frontend_initiated) { + MicroProfileOnThreadCreate("EmuThread"); + SCOPE_EXIT { + MicroProfileShutdown(); + }; + + LOG_INFO(Frontend, "starting"); + + if (filepath.empty()) { + LOG_CRITICAL(Frontend, "failed to load: filepath empty!"); + return Core::SystemResultStatus::ErrorLoader; + } + + SCOPE_EXIT { + EmulationSession::GetInstance().ShutdownEmulation(); + }; + + jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index, + frontend_initiated); + if (result != Core::SystemResultStatus::Success) { + return result; + } + + EmulationSession::GetInstance().RunEmulation(); + + return Core::SystemResultStatus::Success; +} + + + +bool EmulationSession::IsHandheldOnly() { + jconst npad_style_set = m_system.HIDCore().GetSupportedStyleTag(); + + if (npad_style_set.fullkey == 1) { + return false; + } + + if (npad_style_set.handheld == 0) { + return false; + } + + return !YuzuSettings::IsDockedMode(); +} + +void EmulationSession::SetDeviceType([[maybe_unused]] int index, int type) { + jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); + controller->SetNpadStyleIndex(static_cast(type)); +} + +void EmulationSession::OnGamepadConnectEvent([[maybe_unused]] int index) { + jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); + + // Ensure that player1 is configured correctly and handheld disconnected + if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) { + jauto handheld = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + + if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) { + handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey); + controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey); + handheld->Disconnect(); + } + } + + // Ensure that handheld is configured correctly and player 1 disconnected + if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) { + jauto player1 = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + + if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) { + player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); + controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); + player1->Disconnect(); + } + } + + if (!controller->IsConnected()) { + controller->Connect(); + } +} + +void EmulationSession::OnGamepadDisconnectEvent([[maybe_unused]] int index) { + jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); + controller->Disconnect(); +} diff --git a/src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.h b/src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.h new file mode 100644 index 0000000000..d099c88c55 --- /dev/null +++ b/src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.h @@ -0,0 +1,80 @@ +// +// EmulationWindow.h - Sudachi +// Created by Jarrod Norwell on 1/18/24. +// + +#pragma once + +#import +#import +#import + +#include +#include + +#include "core/frontend/emu_window.h" +#include "core/frontend/graphics_context.h" +#include "input_common/main.h" + +class GraphicsContext_Apple final : public Core::Frontend::GraphicsContext { +public: + explicit GraphicsContext_Apple(std::shared_ptr driver_library) + : m_driver_library{driver_library} {} + + ~GraphicsContext_Apple() = default; + + std::shared_ptr GetDriverLibrary() override { + return m_driver_library; + } + +private: + std::shared_ptr m_driver_library; +}; + +NS_ASSUME_NONNULL_BEGIN + +class EmulationWindow final : public Core::Frontend::EmuWindow { +public: + EmulationWindow(InputCommon::InputSubsystem* input_subsystem, CA::MetalLayer* surface, CGSize size, + std::shared_ptr driver_library); + + ~EmulationWindow() = default; + + void OnSurfaceChanged(CA::MetalLayer* surface, CGSize size); + void OrientationChanged(UIInterfaceOrientation orientation); + void OnFrameDisplayed() override; + + void OnTouchPressed(int id, float x, float y); + void OnTouchMoved(int id, float x, float y); + void OnTouchReleased(int id); + + void OnGamepadButtonEvent(int player_index, int button_id, bool pressed); + void OnGamepadJoystickEvent(int player_index, int stick_id, float x, float y); + void OnGamepadMotionEvent(int player_index, u64 delta_timestamp, float gyro_x, float gyro_y, float gyro_z, float accel_x, float accel_y, float accel_z); + + std::unique_ptr CreateSharedContext() const override { + return {std::make_unique(m_driver_library)}; + } + + + bool HasFirstFrame() const { + return m_first_frame; + } + + bool IsShown() const override { + return true; + }; + +private: + float m_window_width{}; + float m_window_height{}; + CGSize m_size; + bool is_portrait = true; + + InputCommon::InputSubsystem* m_input_subsystem{}; + std::shared_ptr m_driver_library; + + bool m_first_frame = false; +}; + +NS_ASSUME_NONNULL_END diff --git a/src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.mm b/src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.mm new file mode 100644 index 0000000000..a0e388e751 --- /dev/null +++ b/src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.mm @@ -0,0 +1,85 @@ +// +// EmulationWindow.mm - Sudachi +// Created by Jarrod Norwell on 1/18/24. +// + +#import "EmulationWindow.h" +#import "../EmulationSession/EmulationSession.h" + +#include + +#include "common/logging/log.h" +#include "input_common/drivers/touch_screen.h" +#include "input_common/drivers/virtual_amiibo.h" +#include "input_common/drivers/virtual_gamepad.h" +#include "input_common/main.h" + +void EmulationWindow::OnSurfaceChanged(CA::MetalLayer* surface, CGSize size) { + m_size = size; + + m_window_width = size.width; + m_window_height = size.height; + + // Ensures that we emulate with the correct aspect ratio. + // UpdateCurrentFramebufferLayout(m_window_width, m_window_height); + + window_info.render_surface = reinterpret_cast(surface); + window_info.render_surface_scale = [[UIScreen mainScreen] nativeScale]; +} + +void EmulationWindow::OrientationChanged(UIInterfaceOrientation orientation) { + is_portrait = orientation == UIInterfaceOrientationPortrait; +} + +void EmulationWindow::OnTouchPressed(int id, float x, float y) { + const auto [touch_x, touch_y] = MapToTouchScreen(x, y); + EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchPressed(touch_x, + touch_y, id); +} + +void EmulationWindow::OnTouchMoved(int id, float x, float y) { + const auto [touch_x, touch_y] = MapToTouchScreen(x, y); + EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchMoved(touch_x, + touch_y, id); +} + +void EmulationWindow::OnTouchReleased(int id) { + EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchReleased(id); +} + +void EmulationWindow::OnGamepadButtonEvent(int player_index, int button_id, bool pressed) { + m_input_subsystem->GetVirtualGamepad()->SetButtonState(player_index, button_id, pressed); +} + +void EmulationWindow::OnGamepadJoystickEvent(int player_index, int stick_id, float x, float y) { + m_input_subsystem->GetVirtualGamepad()->SetStickPosition(player_index, stick_id, x, y); +} + +void EmulationWindow::OnGamepadMotionEvent(int player_index, u64 delta_timestamp, float gyro_x, + float gyro_y, float gyro_z, float accel_x, + float accel_y, float accel_z) { + m_input_subsystem->GetVirtualGamepad()->SetMotionState(player_index, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z); +} + +void EmulationWindow::OnFrameDisplayed() { + if (!m_first_frame) { + m_first_frame = true; + } +} + +EmulationWindow::EmulationWindow(InputCommon::InputSubsystem* input_subsystem, CA::MetalLayer* surface, CGSize size, + std::shared_ptr driver_library) +: m_input_subsystem{input_subsystem}, m_size{size}, m_driver_library{driver_library} { + LOG_INFO(Frontend, "initializing"); + + if (!surface) { + LOG_CRITICAL(Frontend, "surface is nullptr"); + return; + } + + OnSurfaceChanged(surface, m_size); + window_info.render_surface_scale = [[UIScreen mainScreen] nativeScale]; + window_info.type = Core::Frontend::WindowSystemType::Cocoa; + + m_input_subsystem->Initialize(); +} From 1252f7203e5d74e2f90d55b41860164c21682ad5 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Feb 2026 03:53:04 +0000 Subject: [PATCH 03/54] modernize #1 --- src/ios/Eden/AppUI.swift | 10 +- .../AppUIGameInformation.mm | 90 +-- src/ios/Eden/Wrapper/Config/Config.h | 575 +----------------- src/ios/Eden/Wrapper/Config/Config.mm | 330 +--------- .../DirectoryManager/DirectoryManager.mm | 1 - 5 files changed, 65 insertions(+), 941 deletions(-) diff --git a/src/ios/Eden/AppUI.swift b/src/ios/Eden/AppUI.swift index b8f79528b7..6bd4544b0d 100644 --- a/src/ios/Eden/AppUI.swift +++ b/src/ios/Eden/AppUI.swift @@ -80,13 +80,9 @@ public struct AppUI { public func gyroMoved(x: Float, y: Float, z: Float, accelX: Float, accelY: Float, accelZ: Float, controllerId: Int32, deltaTimestamp: Int32) { // Calling the Objective-C function with both gyroscope and accelerometer data appUIObjC.virtualControllerGyro(controllerId, - deltaTimestamp: deltaTimestamp, - gyroX: x, - gyroY: y, - gyroZ: z, - accelX: accelX, - accelY: accelY, - accelZ: accelZ) + deltaTimestamp: deltaTimestamp, + gyroX: x, gyroY: y, gyroZ: z, + accelX: accelX, accelY: accelY, accelZ: accelZ) } diff --git a/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.mm b/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.mm index 00c894d078..ef65c723f8 100644 --- a/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.mm +++ b/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.mm @@ -26,7 +26,7 @@ struct GameMetadata { }; -class SdlConfig final : public YuzuConfig { +class SdlConfig final : public Config { public: explicit SdlConfig(std::optional config_path); ~SdlConfig() override; @@ -59,12 +59,12 @@ protected: void SaveUILayoutValues() override {} void SaveMultiplayerValues() override {} - std::vector& FindRelevantList(YuzuSettings::Category category) override; + std::vector& FindRelevantList(Settings::Category category) override; public: - static const std::array default_buttons; - static const std::array default_motions; - static const std::array, YuzuSettings::NativeAnalog::NumAnalogs> default_analogs; + static const std::array default_buttons; + static const std::array default_motions; + static const std::array, Settings::NativeAnalog::NumAnalogs> default_analogs; static const std::array default_stick_mod; static const std::array default_ringcon_analogs; }; @@ -76,18 +76,18 @@ public: #include "common/logging/log.h" #include "input_common/main.h" -const std::array SdlConfig::default_buttons = { +const std::array SdlConfig::default_buttons = { SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_T, SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H, SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_B, }; -const std::array SdlConfig::default_motions = { +const std::array SdlConfig::default_motions = { SDL_SCANCODE_7, SDL_SCANCODE_8, }; -const std::array, YuzuSettings::NativeAnalog::NumAnalogs> SdlConfig::default_analogs{ +const std::array, Settings::NativeAnalog::NumAnalogs> SdlConfig::default_analogs{ { { SDL_SCANCODE_UP, @@ -141,10 +141,10 @@ void SdlConfig::ReadSdlValues() { } void SdlConfig::ReadSdlControlValues() { - BeginGroup(YuzuSettings::TranslateCategory(YuzuSettings::Category::Controls)); + BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); - YuzuSettings::values.players.SetGlobal(!IsCustomConfig()); - for (std::size_t p = 0; p < YuzuSettings::values.players.GetValue().size(); ++p) { + Settings::values.players.SetGlobal(!IsCustomConfig()); + for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { ReadSdlPlayerValues(p); } if (IsCustomConfig()) { @@ -163,48 +163,48 @@ void SdlConfig::ReadSdlPlayerValues(const std::size_t player_index) { player_prefix.append("player_").append(ToString(player_index)).append("_"); } - auto& player = YuzuSettings::values.players.GetValue()[player_index]; + auto& player = Settings::values.players.GetValue()[player_index]; if (IsCustomConfig()) { const auto profile_name = ReadStringSetting(std::string(player_prefix).append("profile_name")); if (profile_name.empty()) { // Use the global input config - player = YuzuSettings::values.players.GetValue(true)[player_index]; + player = Settings::values.players.GetValue(true)[player_index]; player.profile_name = ""; return; } } - for (int i = 0; i < YuzuSettings::NativeButton::NumButtons; ++i) { + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); auto& player_buttons = player.buttons[i]; player_buttons = ReadStringSetting( - std::string(player_prefix).append(YuzuSettings::NativeButton::mapping[i]), default_param); + std::string(player_prefix).append(Settings::NativeButton::mapping[i]), default_param); if (player_buttons.empty()) { player_buttons = default_param; } } - for (int i = 0; i < YuzuSettings::NativeAnalog::NumAnalogs; ++i) { + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], default_analogs[i][3], default_stick_mod[i], 0.5f); auto& player_analogs = player.analogs[i]; player_analogs = ReadStringSetting( - std::string(player_prefix).append(YuzuSettings::NativeAnalog::mapping[i]), default_param); + std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), default_param); if (player_analogs.empty()) { player_analogs = default_param; } } - for (int i = 0; i < YuzuSettings::NativeMotion::NumMotions; ++i) { + for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); auto& player_motions = player.motions[i]; player_motions = ReadStringSetting( - std::string(player_prefix).append(YuzuSettings::NativeMotion::mapping[i]), default_param); + std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), default_param); if (player_motions.empty()) { player_motions = default_param; } @@ -212,22 +212,22 @@ void SdlConfig::ReadSdlPlayerValues(const std::size_t player_index) { } void SdlConfig::ReadDebugControlValues() { - for (int i = 0; i < YuzuSettings::NativeButton::NumButtons; ++i) { + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - auto& debug_pad_buttons = YuzuSettings::values.debug_pad_buttons[i]; + auto& debug_pad_buttons = Settings::values.debug_pad_buttons[i]; debug_pad_buttons = ReadStringSetting( - std::string("debug_pad_").append(YuzuSettings::NativeButton::mapping[i]), default_param); + std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), default_param); if (debug_pad_buttons.empty()) { debug_pad_buttons = default_param; } } - for (int i = 0; i < YuzuSettings::NativeAnalog::NumAnalogs; ++i) { + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], default_analogs[i][3], default_stick_mod[i], 0.5f); - auto& debug_pad_analogs = YuzuSettings::values.debug_pad_analogs[i]; + auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i]; debug_pad_analogs = ReadStringSetting( - std::string("debug_pad_").append(YuzuSettings::NativeAnalog::mapping[i]), default_param); + std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), default_param); if (debug_pad_analogs.empty()) { debug_pad_analogs = default_param; } @@ -237,7 +237,7 @@ void SdlConfig::ReadDebugControlValues() { void SdlConfig::ReadHidbusValues() { const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); - auto& ringcon_analogs = YuzuSettings::values.ringcon_analogs; + auto& ringcon_analogs = Settings::values.ringcon_analogs; ringcon_analogs = ReadStringSetting(std::string("ring_controller"), default_param); if (ringcon_analogs.empty()) { @@ -253,10 +253,10 @@ void SdlConfig::SaveSdlValues() { } void SdlConfig::SaveSdlControlValues() { - BeginGroup(YuzuSettings::TranslateCategory(YuzuSettings::Category::Controls)); + BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); - YuzuSettings::values.players.SetGlobal(!IsCustomConfig()); - for (std::size_t p = 0; p < YuzuSettings::values.players.GetValue().size(); ++p) { + Settings::values.players.SetGlobal(!IsCustomConfig()); + for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { SaveSdlPlayerValues(p); } if (IsCustomConfig()) { @@ -275,44 +275,44 @@ void SdlConfig::SaveSdlPlayerValues(const std::size_t player_index) { player_prefix = std::string("player_").append(ToString(player_index)).append("_"); } - const auto& player = YuzuSettings::values.players.GetValue()[player_index]; + const auto& player = Settings::values.players.GetValue()[player_index]; if (IsCustomConfig() && player.profile_name.empty()) { // No custom profile selected return; } - for (int i = 0; i < YuzuSettings::NativeButton::NumButtons; ++i) { + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - WriteStringSetting(std::string(player_prefix).append(YuzuSettings::NativeButton::mapping[i]), + WriteStringSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]), player.buttons[i], std::make_optional(default_param)); } - for (int i = 0; i < YuzuSettings::NativeAnalog::NumAnalogs; ++i) { + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], default_analogs[i][3], default_stick_mod[i], 0.5f); - WriteStringSetting(std::string(player_prefix).append(YuzuSettings::NativeAnalog::mapping[i]), + WriteStringSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), player.analogs[i], std::make_optional(default_param)); } - for (int i = 0; i < YuzuSettings::NativeMotion::NumMotions; ++i) { + for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); - WriteStringSetting(std::string(player_prefix).append(YuzuSettings::NativeMotion::mapping[i]), + WriteStringSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), player.motions[i], std::make_optional(default_param)); } } void SdlConfig::SaveDebugControlValues() { - for (int i = 0; i < YuzuSettings::NativeButton::NumButtons; ++i) { + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - WriteStringSetting(std::string("debug_pad_").append(YuzuSettings::NativeButton::mapping[i]), - YuzuSettings::values.debug_pad_buttons[i], + WriteStringSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), + Settings::values.debug_pad_buttons[i], std::make_optional(default_param)); } - for (int i = 0; i < YuzuSettings::NativeAnalog::NumAnalogs; ++i) { + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], default_analogs[i][3], default_stick_mod[i], 0.5f); - WriteStringSetting(std::string("debug_pad_").append(YuzuSettings::NativeAnalog::mapping[i]), - YuzuSettings::values.debug_pad_analogs[i], + WriteStringSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), + Settings::values.debug_pad_analogs[i], std::make_optional(default_param)); } } @@ -320,12 +320,12 @@ void SdlConfig::SaveDebugControlValues() { void SdlConfig::SaveHidbusValues() { const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); - WriteStringSetting(std::string("ring_controller"), YuzuSettings::values.ringcon_analogs, + WriteStringSetting(std::string("ring_controller"), Settings::values.ringcon_analogs, std::make_optional(default_param)); } -std::vector& SdlConfig::FindRelevantList(YuzuSettings::Category category) { - return YuzuSettings::values.linkage.by_category[category]; +std::vector& SdlConfig::FindRelevantList(Settings::Category category) { + return Settings::values.linkage.by_category[category]; } diff --git a/src/ios/Eden/Wrapper/Config/Config.h b/src/ios/Eden/Wrapper/Config/Config.h index 5e29db42cf..4adc23fe44 100644 --- a/src/ios/Eden/Wrapper/Config/Config.h +++ b/src/ios/Eden/Wrapper/Config/Config.h @@ -1,568 +1,19 @@ -// -// Config.h -// AppUI -// -// Created by Jarrod Norwell on 13/3/2024. -// - -// SPDX-FileCopyrightText: 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later #pragma once -namespace DefaultINI { - -const char* android_config_file = R"( - -[ControlsP0] -# The input devices and parameters for each Switch native input -# The config section determines the player number where the config will be applied on. For example "ControlsP0", "ControlsP1", ... -# It should be in the format of "engine:[engine_name],[param1]:[value1],[param2]:[value2]..." -# Escape characters $0 (for ':'), $1 (for ',') and $2 (for '$') can be used in values - -# Indicates if this player should be connected at boot -connected= - -# for button input, the following devices are available: -# - "keyboard" (default) for keyboard input. Required parameters: -# - "code": the code of the key to bind -# - "sdl" for joystick input using SDL. Required parameters: -# - "guid": SDL identification GUID of the joystick -# - "port": the index of the joystick to bind -# - "button"(optional): the index of the button to bind -# - "hat"(optional): the index of the hat to bind as direction buttons -# - "axis"(optional): the index of the axis to bind -# - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", "down", "left" or "right" -# - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is -# triggered if the axis value crosses -# - "direction"(only used for axis): "+" means the button is triggered when the axis value -# is greater than the threshold; "-" means the button is triggered when the axis value -# is smaller than the threshold -button_a= -button_b= -button_x= -button_y= -button_lstick= -button_rstick= -button_l= -button_r= -button_zl= -button_zr= -button_plus= -button_minus= -button_dleft= -button_dup= -button_dright= -button_ddown= -button_lstick_left= -button_lstick_up= -button_lstick_right= -button_lstick_down= -button_sl= -button_sr= -button_home= -button_screenshot= - -# for analog input, the following devices are available: -# - "analog_from_button" (default) for emulating analog input from direction buttons. Required parameters: -# - "up", "down", "left", "right": sub-devices for each direction. -# Should be in the format as a button input devices using escape characters, for example, "engine$0keyboard$1code$00" -# - "modifier": sub-devices as a modifier. -# - "modifier_scale": a float number representing the applied modifier scale to the analog input. -# Must be in range of 0.0-1.0. Defaults to 0.5 -# - "sdl" for joystick input using SDL. Required parameters: -# - "guid": SDL identification GUID of the joystick -# - "port": the index of the joystick to bind -# - "axis_x": the index of the axis to bind as x-axis (default to 0) -# - "axis_y": the index of the axis to bind as y-axis (default to 1) -lstick= -rstick= - -# for motion input, the following devices are available: -# - "keyboard" (default) for emulating random motion input from buttons. Required parameters: -# - "code": the code of the key to bind -# - "sdl" for motion input using SDL. Required parameters: -# - "guid": SDL identification GUID of the joystick -# - "port": the index of the joystick to bind -# - "motion": the index of the motion sensor to bind -# - "cemuhookudp" for motion input using Cemu Hook protocol. Required parameters: -# - "guid": the IP address of the cemu hook server encoded to a hex string. for example 192.168.0.1 = "c0a80001" -# - "port": the port of the cemu hook server -# - "pad": the index of the joystick -# - "motion": the index of the motion sensor of the joystick to bind -motionleft= -motionright= - -[ControlsGeneral] -# To use the debug_pad, prepend debug_pad_ before each button setting above. -# i.e. debug_pad_button_a= - -# Enable debug pad inputs to the guest -# 0 (default): Disabled, 1: Enabled -debug_pad_enabled = - -# Whether to enable or disable vibration -# 0: Disabled, 1 (default): Enabled -vibration_enabled = - -# Whether to enable or disable accurate vibrations -# 0 (default): Disabled, 1: Enabled -enable_accurate_vibrations = - -# Enables controller motion inputs -# 0: Disabled, 1 (default): Enabled -motion_enabled = - -# Defines the udp device's touch screen coordinate system for cemuhookudp devices -# - "min_x", "min_y", "max_x", "max_y" -touch_device= - -# for mapping buttons to touch inputs. -#touch_from_button_map=1 -#touch_from_button_maps_0_name=default -#touch_from_button_maps_0_count=2 -#touch_from_button_maps_0_bind_0=foo -#touch_from_button_maps_0_bind_1=bar -# etc. - -# List of Cemuhook UDP servers, delimited by ','. -# Default: 127.0.0.1:26760 -# Example: 127.0.0.1:26760,123.4.5.67:26761 -udp_input_servers = - -# Enable controlling an axis via a mouse input. -# 0 (default): Off, 1: On -mouse_panning = - -# Set mouse sensitivity. -# Default: 1.0 -mouse_panning_sensitivity = - -# Emulate an analog control stick from keyboard inputs. -# 0 (default): Disabled, 1: Enabled -emulate_analog_keyboard = - -# Enable mouse inputs to the guest -# 0 (default): Disabled, 1: Enabled -mouse_enabled = - -# Enable keyboard inputs to the guest -# 0 (default): Disabled, 1: Enabled -keyboard_enabled = - -[Core] -# Whether to use multi-core for CPU emulation -# 0: Disabled, 1 (default): Enabled -use_multi_core = - -# Enable unsafe extended guest system memory layout (8GB DRAM) -# 0 (default): Disabled, 1: Enabled -use_unsafe_extended_memory_layout = - -[Cpu] -# Adjusts various optimizations. -# Auto-select mode enables choice unsafe optimizations. -# Accurate enables only safe optimizations. -# Unsafe allows any unsafe optimizations. -# 0 (default): Auto-select, 1: Accurate, 2: Enable unsafe optimizations -cpu_accuracy = - -# Allow disabling safe optimizations. -# 0 (default): Disabled, 1: Enabled -cpu_debug_mode = - -# Enable inline page tables optimization (faster guest memory access) -# 0: Disabled, 1 (default): Enabled -cpuopt_page_tables = - -# Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps) -# 0: Disabled, 1 (default): Enabled -cpuopt_block_linking = - -# Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns) -# 0: Disabled, 1 (default): Enabled -cpuopt_return_stack_buffer = - -# Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture) -# 0: Disabled, 1 (default): Enabled -cpuopt_fast_dispatcher = - -# Enable context elimination CPU Optimization (reduce host memory use for guest context) -# 0: Disabled, 1 (default): Enabled -cpuopt_context_elimination = - -# Enable constant propagation CPU optimization (basic IR optimization) -# 0: Disabled, 1 (default): Enabled -cpuopt_const_prop = - -# Enable miscellaneous CPU optimizations (basic IR optimization) -# 0: Disabled, 1 (default): Enabled -cpuopt_misc_ir = - -# Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access) -# 0: Disabled, 1 (default): Enabled -cpuopt_reduce_misalign_checks = - -# Enable Host MMU Emulation (faster guest memory access) -# 0: Disabled, 1 (default): Enabled -cpuopt_fastmem = - -# Enable Host MMU Emulation for exclusive memory instructions (faster guest memory access) -# 0: Disabled, 1 (default): Enabled -cpuopt_fastmem_exclusives = - -# Enable fallback on failure of fastmem of exclusive memory instructions (faster guest memory access) -# 0: Disabled, 1 (default): Enabled -cpuopt_recompile_exclusives = - -# Enable optimization to ignore invalid memory accesses (faster guest memory access) -# 0: Disabled, 1 (default): Enabled -cpuopt_ignore_memory_aborts = - -# Enable unfuse FMA (improve performance on CPUs without FMA) -# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. -# 0: Disabled, 1 (default): Enabled -cpuopt_unsafe_unfuse_fma = - -# Enable faster FRSQRTE and FRECPE -# Only enabled if cpu_accuracy is set to Unsafe. -# 0: Disabled, 1 (default): Enabled -cpuopt_unsafe_reduce_fp_error = - -# Enable faster ASIMD instructions (32 bits only) -# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. -# 0: Disabled, 1 (default): Enabled -cpuopt_unsafe_ignore_standard_fpcr = - -# Enable inaccurate NaN handling -# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. -# 0: Disabled, 1 (default): Enabled -cpuopt_unsafe_inaccurate_nan = - -# Disable address space checks (64 bits only) -# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. -# 0: Disabled, 1 (default): Enabled -cpuopt_unsafe_fastmem_check = - -# Enable faster exclusive instructions -# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. -# 0: Disabled, 1 (default): Enabled -cpuopt_unsafe_ignore_global_monitor = - -[Renderer] -# Which backend API to use. -# 0: OpenGL (unsupported), 1 (default): Vulkan, 2: Null -backend = - -# Whether to enable asynchronous presentation (Vulkan only) -# 0: Off, 1 (default): On -async_presentation = - -# Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied). -# 0 (default): Disabled, 1: Enabled -force_max_clock = - -# Enable graphics API debugging mode. -# 0 (default): Disabled, 1: Enabled -debug = - -# Enable shader feedback. -# 0 (default): Disabled, 1: Enabled -renderer_shader_feedback = - -# Enable Nsight Aftermath crash dumps -# 0 (default): Disabled, 1: Enabled -nsight_aftermath = - -# Disable shader loop safety checks, executing the shader without loop logic changes -# 0 (default): Disabled, 1: Enabled -disable_shader_loop_safety_checks = - -# Which Vulkan physical device to use (defaults to 0) -vulkan_device = - -# 0: 0.5x (360p/540p) [EXPERIMENTAL] -# 1: 0.75x (540p/810p) [EXPERIMENTAL] -# 2 (default): 1x (720p/1080p) -# 3: 2x (1440p/2160p) -# 4: 3x (2160p/3240p) -# 5: 4x (2880p/4320p) -# 6: 5x (3600p/5400p) -# 7: 6x (4320p/6480p) -resolution_setup = - -# Pixel filter to use when up- or down-sampling rendered frames. -# 0: Nearest Neighbor -# 1 (default): Bilinear -# 2: Bicubic -# 3: Gaussian -# 4: ScaleForce -# 5: AMD FidelityFX™️ Super Resolution [Vulkan Only] -scaling_filter = - -# Anti-Aliasing (AA) -# 0 (default): None, 1: FXAA -anti_aliasing = - -# Whether to use fullscreen or borderless window mode -# 0 (Windows default): Borderless window, 1 (All other default): Exclusive fullscreen -fullscreen_mode = - -# Aspect ratio -# 0: Default (16:9), 1: Force 4:3, 2: Force 21:9, 3: Force 16:10, 4: Stretch to Window -aspect_ratio = - -# Anisotropic filtering -# 0: Default, 1: 2x, 2: 4x, 3: 8x, 4: 16x -max_anisotropy = - -# Whether to enable VSync or not. -# OpenGL: Values other than 0 enable VSync -# Vulkan: FIFO is selected if the requested mode is not supported by the driver. -# FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. -# FIFO Relaxed is similar to FIFO but allows tearing as it recovers from a slow down. -# Mailbox can have lower latency than FIFO and does not tear but may drop frames. -# Immediate (no synchronization) just presents whatever is available and can exhibit tearing. -# 0: Immediate (Off), 1 (Default): Mailbox (On), 2: FIFO, 3: FIFO Relaxed -use_vsync = - -# Selects the OpenGL shader backend. NV_gpu_program5 is required for GLASM. If NV_gpu_program5 is -# not available and GLASM is selected, GLSL will be used. -# 0: GLSL, 1 (default): GLASM, 2: SPIR-V -shader_backend = - -# Whether to allow asynchronous shader building. -# 0 (default): Off, 1: On -use_asynchronous_shaders = - -# Uses reactive flushing instead of predictive flushing. Allowing a more accurate syncing of memory. -# 0 (default): Off, 1: On -use_reactive_flushing = - -# NVDEC emulation. -# 0: Disabled, 1: CPU Decoding, 2 (default): GPU Decoding -nvdec_emulation = - -# Accelerate ASTC texture decoding. -# 0 (default): Off, 1: On -accelerate_astc = - -# Turns on the speed limiter, which will limit the emulation speed to the desired speed limit value -# 0: Off, 1: On (default) -use_speed_limit = - -# Limits the speed of the game to run no faster than this value as a percentage of target speed -# 1 - 9999: Speed limit as a percentage of target game speed. 100 (default) -speed_limit = - -# Whether to use disk based shader cache -# 0: Off, 1 (default): On -use_disk_shader_cache = - -# Which gpu accuracy level to use -# 0 (default): Normal, 1: High, 2: Extreme (Very slow) -gpu_accuracy = - -# Whether to use asynchronous GPU emulation -# 0 : Off (slow), 1 (default): On (fast) -use_asynchronous_gpu_emulation = - -# Inform the guest that GPU operations completed more quickly than they did. -# 0: Off, 1 (default): On -use_fast_gpu_time = - -# Force unmodified buffers to be flushed, which can cost performance. -# 0: Off (default), 1: On -use_pessimistic_flushes = - -# Whether to use garbage collection or not for GPU caches. -# 0 (default): Off, 1: On -use_caches_gc = - -# The clear color for the renderer. What shows up on the sides of the bottom screen. -# Must be in range of 0-255. Defaults to 0 for all. -bg_red = -bg_blue = -bg_green = - -[Audio] -# Which audio output engine to use. -# auto (default): Auto-select -# cubeb: Cubeb audio engine (if available) -# sdl2: SDL2 audio engine (if available) -# null: No audio output -output_engine = - -# Which audio device to use. -# auto (default): Auto-select -output_device = - -# Output volume. -# 100 (default): 100%, 0; mute -volume = - -[Data Storage] -# Whether to create a virtual SD card. -# 1: Yes, 0 (default): No -use_virtual_sd = - -# Whether or not to enable gamecard emulation -# 1: Yes, 0 (default): No -gamecard_inserted = - -# Whether or not the gamecard should be emulated as the current game -# If 'gamecard_inserted' is 0 this setting is irrelevant -# 1: Yes, 0 (default): No -gamecard_current_game = - -# Path to an XCI file to use as the gamecard -# If 'gamecard_inserted' is 0 this setting is irrelevant -# If 'gamecard_current_game' is 1 this setting is irrelevant -gamecard_path = - -[System] -# Whether the system is docked -# 1: Yes, 0 (default): No -use_docked_mode = - -# Sets the seed for the RNG generator built into the switch -# rng_seed will be ignored and randomly generated if rng_seed_enabled is false -rng_seed_enabled = -rng_seed = - -# Sets the current time (in seconds since 12:00 AM Jan 1, 1970) that will be used by the time service -# This will auto-increment, with the time set being the time the game is started -# This override will only occur if custom_rtc_enabled is true, otherwise the current time is used -custom_rtc_enabled = -custom_rtc = - -# Sets the systems language index -# 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese, -# 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French, -# 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese, 17: Brazilian Portuguese -language_index = - -# The system region that yuzu will use during emulation -# -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan -region_index = - -# The system time zone that yuzu will use during emulation -# 0: Auto-select (default), 1: Default (system archive value), Others: Index for specified time zone -time_zone_index = - -# Sets the sound output mode. -# 0: Mono, 1 (default): Stereo, 2: Surround -sound_index = - -[Miscellaneous] -# A filter which removes logs below a certain logging level. -# Examples: *:Debug Kernel.SVC:Trace Service.*:Critical -log_filter = *:Trace - -# Use developer keys -# 0 (default): Disabled, 1: Enabled -use_dev_keys = - -[Debugging] -# Record frame time data, can be found in the log directory. Boolean value -record_frame_times = -# Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them -dump_exefs=false -# Determines whether or not yuzu will dump all NSOs it attempts to load while loading them -dump_nso=false -# Determines whether or not yuzu will save the filesystem access log. -enable_fs_access_log=false -# Enables verbose reporting services -reporting_services = -# Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode -# false: Retail/Normal Mode (default), true: Kiosk Mode -quest_flag = -# Determines whether debug asserts should be enabled, which will throw an exception on asserts. -# false: Disabled (default), true: Enabled -use_debug_asserts = -# Determines whether unimplemented HLE service calls should be automatically stubbed. -# false: Disabled (default), true: Enabled -use_auto_stub = -# Enables/Disables the macro JIT compiler -disable_macro_jit=false -# Determines whether to enable the GDB stub and wait for the debugger to attach before running. -# false: Disabled (default), true: Enabled -use_gdbstub=false -# The port to use for the GDB server, if it is enabled. -gdbstub_port=6543 - -[WebService] -# Whether or not to enable telemetry -# 0: No, 1 (default): Yes -enable_telemetry = -# URL for Web API -web_api_url = -# Username and token for yuzu Web Service -# See https://profile.yuzu-emu.org/ for more info -yuzu_username = -yuzu_token = - -[Network] -# Name of the network interface device to use with yuzu LAN play. -# e.g. On *nix: 'enp7s0', 'wlp6s0u1u3u3', 'lo' -# e.g. On Windows: 'Ethernet', 'Wi-Fi' -network_interface = - -[AddOns] -# Used to disable add-ons -# List of title IDs of games that will have add-ons disabled (separated by '|'): -title_ids = -# For each title ID, have a key/value pair called `disabled_` equal to the names of the add-ons to disable (sep. by '|') -# e.x. disabled_0100000000010000 = Update|DLC <- disables Updates and - on Super Mario Odyssey -)"; -} // namespace DefaultINI - - -// SPDX-FileCopyrightText: 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include -#include - -#include "common/settings.h" - -class INIReader; - -class Config { - bool LoadINI(const std::string& default_contents = "", bool retry = true); - -public: - enum class ConfigType { - GlobalConfig, - PerGameConfig, - InputProfile, +#include +#include "common/common_types.h" +#include "common/settings_setting.h" +#include "common/settings_enums.h" + +namespace IOSSettings { + struct Values { + Settings::Linkage linkage; + Settings::Setting touchscreen{linkage, true, "touchscreen", Settings::Category::Overlay}; }; - explicit Config(const std::string& config_name = "config", - ConfigType config_type = ConfigType::GlobalConfig); - ~Config(); + extern Values values; - void Initialize(const std::string& config_name); - -private: - /** - * Applies a value read from the config to a Setting. - * - * @param group The name of the INI group - * @param setting The yuzu setting to modify - */ - template - void ReadSetting(const std::string& group, YuzuSettings::Setting& setting); - - void ReadValues(); - - const ConfigType type; - std::unique_ptr config; - std::string config_loc; - const bool global; -}; +} // namespace IOSSettings diff --git a/src/ios/Eden/Wrapper/Config/Config.mm b/src/ios/Eden/Wrapper/Config/Config.mm index 3460ee08de..0a01d234df 100644 --- a/src/ios/Eden/Wrapper/Config/Config.mm +++ b/src/ios/Eden/Wrapper/Config/Config.mm @@ -1,330 +1,8 @@ -// -// Config.m - Sudachi -// Created by Jarrod Norwell on 13/3/2024. -// -#import "Config.h" +#include "Config.h" -// SPDX-FileCopyrightText: 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +namespace IOSSettings { -#include -#include -#include +Values values; -#include -#include "common/fs/file.h" -#include "common/fs/fs.h" -#include "common/fs/path_util.h" -#include "common/logging/log.h" -#include "common/settings.h" -#include "common/settings_enums.h" -#include "core/hle/service/acc/profile_manager.h" -#include "input_common/main.h" - -namespace FS = Common::FS; - -Config::Config(const std::string& config_name, ConfigType config_type) - : type(config_type), global{config_type == ConfigType::GlobalConfig} { - Initialize(config_name); -} - -Config::~Config() = default; - -bool Config::LoadINI(const std::string& default_contents, bool retry) { - void(FS::CreateParentDir(config_loc)); - config = std::make_unique(FS::PathToUTF8String(config_loc)); - const auto config_loc_str = FS::PathToUTF8String(config_loc); - if (config->ParseError() < 0) { - if (retry) { - LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...", - config_loc_str); - - void(FS::CreateParentDir(config_loc)); - void(FS::WriteStringToFile(config_loc, FS::FileType::TextFile, default_contents)); - - config = std::make_unique(config_loc_str); - - return LoadINI(default_contents, false); - } - LOG_ERROR(Config, "Failed."); - return false; - } - LOG_INFO(Config, "Successfully loaded {}", config_loc_str); - return true; -} - -template <> -void Config::ReadSetting(const std::string& group, YuzuSettings::Setting& setting) { - std::string setting_value = config->Get(group, setting.GetLabel(), setting.GetDefault()); - if (setting_value.empty()) { - setting_value = setting.GetDefault(); - } - setting = std::move(setting_value); -} - -template <> -void Config::ReadSetting(const std::string& group, YuzuSettings::Setting& setting) { - setting = config->GetBoolean(group, setting.GetLabel(), setting.GetDefault()); -} - -template -void Config::ReadSetting(const std::string& group, YuzuSettings::Setting& setting) { - setting = static_cast( - config->GetInteger(group, setting.GetLabel(), static_cast(setting.GetDefault()))); -} - -void Config::ReadValues() { - ReadSetting("ControlsGeneral", YuzuSettings::values.mouse_enabled); - ReadSetting("ControlsGeneral", YuzuSettings::values.touch_device); - ReadSetting("ControlsGeneral", YuzuSettings::values.keyboard_enabled); - ReadSetting("ControlsGeneral", YuzuSettings::values.debug_pad_enabled); - ReadSetting("ControlsGeneral", YuzuSettings::values.vibration_enabled); - ReadSetting("ControlsGeneral", YuzuSettings::values.enable_accurate_vibrations); - ReadSetting("ControlsGeneral", YuzuSettings::values.motion_enabled); - YuzuSettings::values.touchscreen.enabled = - config->GetBoolean("ControlsGeneral", "touch_enabled", true); - YuzuSettings::values.touchscreen.rotation_angle = - config->GetInteger("ControlsGeneral", "touch_angle", 0); - YuzuSettings::values.touchscreen.diameter_x = - config->GetInteger("ControlsGeneral", "touch_diameter_x", 15); - YuzuSettings::values.touchscreen.diameter_y = - config->GetInteger("ControlsGeneral", "touch_diameter_y", 15); - - int num_touch_from_button_maps = - config->GetInteger("ControlsGeneral", "touch_from_button_map", 0); - if (num_touch_from_button_maps > 0) { - for (int i = 0; i < num_touch_from_button_maps; ++i) { - YuzuSettings::TouchFromButtonMap map; - map.name = config->Get("ControlsGeneral", - std::string("touch_from_button_maps_") + std::to_string(i) + - std::string("_name"), - "default"); - const int num_touch_maps = config->GetInteger( - "ControlsGeneral", - std::string("touch_from_button_maps_") + std::to_string(i) + std::string("_count"), - 0); - map.buttons.reserve(num_touch_maps); - - for (int j = 0; j < num_touch_maps; ++j) { - std::string touch_mapping = - config->Get("ControlsGeneral", - std::string("touch_from_button_maps_") + std::to_string(i) + - std::string("_bind_") + std::to_string(j), - ""); - map.buttons.emplace_back(std::move(touch_mapping)); - } - - YuzuSettings::values.touch_from_button_maps.emplace_back(std::move(map)); - } - } else { - YuzuSettings::values.touch_from_button_maps.emplace_back( - YuzuSettings::TouchFromButtonMap{"default", {}}); - num_touch_from_button_maps = 1; - } - YuzuSettings::values.touch_from_button_map_index = std::clamp( - YuzuSettings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); - - ReadSetting("ControlsGeneral", YuzuSettings::values.udp_input_servers); - - // Data Storage - ReadSetting("Data Storage", YuzuSettings::values.use_virtual_sd); - FS::SetYuzuPath(FS::YuzuPath::NANDDir, - config->Get("Data Storage", "nand_directory", - FS::GetYuzuPathString(FS::YuzuPath::NANDDir))); - FS::SetYuzuPath(FS::YuzuPath::SDMCDir, - config->Get("Data Storage", "sdmc_directory", - FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))); - FS::SetYuzuPath(FS::YuzuPath::LoadDir, - config->Get("Data Storage", "load_directory", - FS::GetYuzuPathString(FS::YuzuPath::LoadDir))); - FS::SetYuzuPath(FS::YuzuPath::DumpDir, - config->Get("Data Storage", "dump_directory", - FS::GetYuzuPathString(FS::YuzuPath::DumpDir))); - ReadSetting("Data Storage", YuzuSettings::values.gamecard_inserted); - ReadSetting("Data Storage", YuzuSettings::values.gamecard_current_game); - ReadSetting("Data Storage", YuzuSettings::values.gamecard_path); - - // System - ReadSetting("System", YuzuSettings::values.current_user); - YuzuSettings::values.current_user = std::clamp(YuzuSettings::values.current_user.GetValue(), 0, - Service::Account::MAX_USERS - 1); - - // Enable docked mode by default on iOS - YuzuSettings::values.use_docked_mode.SetValue(config->GetBoolean("System", "use_docked_mode", false) - ? YuzuSettings::ConsoleMode::Docked - : YuzuSettings::ConsoleMode::Handheld); - - const auto rng_seed_enabled = config->GetBoolean("System", "rng_seed_enabled", false); - if (rng_seed_enabled) { - YuzuSettings::values.rng_seed.SetValue(config->GetInteger("System", "rng_seed", 0)); - } else { - YuzuSettings::values.rng_seed.SetValue(0); - } - YuzuSettings::values.rng_seed_enabled.SetValue(rng_seed_enabled); - - const auto custom_rtc_enabled = config->GetBoolean("System", "custom_rtc_enabled", false); - if (custom_rtc_enabled) { - YuzuSettings::values.custom_rtc = config->GetInteger("System", "custom_rtc", 0); - } else { - YuzuSettings::values.custom_rtc = 0; - } - YuzuSettings::values.custom_rtc_enabled = custom_rtc_enabled; - - ReadSetting("System", YuzuSettings::values.language_index); - ReadSetting("System", YuzuSettings::values.region_index); - ReadSetting("System", YuzuSettings::values.time_zone_index); - ReadSetting("System", YuzuSettings::values.sound_index); - - // Core - ReadSetting("Core", YuzuSettings::values.use_multi_core); - ReadSetting("Core", YuzuSettings::values.memory_layout_mode); - - // Cpu - ReadSetting("Cpu", YuzuSettings::values.cpu_accuracy); - ReadSetting("Cpu", YuzuSettings::values.cpu_debug_mode); - ReadSetting("Cpu", YuzuSettings::values.cpuopt_page_tables); - ReadSetting("Cpu", YuzuSettings::values.cpuopt_block_linking); - ReadSetting("Cpu", YuzuSettings::values.cpuopt_return_stack_buffer); - ReadSetting("Cpu", YuzuSettings::values.cpuopt_fast_dispatcher); - ReadSetting("Cpu", YuzuSettings::values.cpuopt_context_elimination); - ReadSetting("Cpu", YuzuSettings::values.cpuopt_const_prop); - ReadSetting("Cpu", YuzuSettings::values.cpuopt_misc_ir); - ReadSetting("Cpu", YuzuSettings::values.cpuopt_reduce_misalign_checks); - ReadSetting("Cpu", YuzuSettings::values.cpuopt_fastmem); - ReadSetting("Cpu", YuzuSettings::values.cpuopt_fastmem_exclusives); - ReadSetting("Cpu", YuzuSettings::values.cpuopt_recompile_exclusives); - ReadSetting("Cpu", YuzuSettings::values.cpuopt_ignore_memory_aborts); - ReadSetting("Cpu", YuzuSettings::values.cpuopt_unsafe_unfuse_fma); - ReadSetting("Cpu", YuzuSettings::values.cpuopt_unsafe_reduce_fp_error); - ReadSetting("Cpu", YuzuSettings::values.cpuopt_unsafe_ignore_standard_fpcr); - ReadSetting("Cpu", YuzuSettings::values.cpuopt_unsafe_inaccurate_nan); - ReadSetting("Cpu", YuzuSettings::values.cpuopt_unsafe_fastmem_check); - ReadSetting("Cpu", YuzuSettings::values.cpuopt_unsafe_ignore_global_monitor); - - // Renderer - ReadSetting("Renderer", YuzuSettings::values.renderer_backend); - ReadSetting("Renderer", YuzuSettings::values.renderer_debug); - ReadSetting("Renderer", YuzuSettings::values.renderer_shader_feedback); - ReadSetting("Renderer", YuzuSettings::values.enable_nsight_aftermath); - ReadSetting("Renderer", YuzuSettings::values.disable_shader_loop_safety_checks); - ReadSetting("Renderer", YuzuSettings::values.vulkan_device); - - ReadSetting("Renderer", YuzuSettings::values.resolution_setup); - ReadSetting("Renderer", YuzuSettings::values.scaling_filter); - ReadSetting("Renderer", YuzuSettings::values.fsr_sharpening_slider); - ReadSetting("Renderer", YuzuSettings::values.anti_aliasing); - ReadSetting("Renderer", YuzuSettings::values.fullscreen_mode); - ReadSetting("Renderer", YuzuSettings::values.aspect_ratio); - ReadSetting("Renderer", YuzuSettings::values.max_anisotropy); - ReadSetting("Renderer", YuzuSettings::values.use_speed_limit); - ReadSetting("Renderer", YuzuSettings::values.speed_limit); - ReadSetting("Renderer", YuzuSettings::values.use_disk_shader_cache); - ReadSetting("Renderer", YuzuSettings::values.use_asynchronous_gpu_emulation); - ReadSetting("Renderer", YuzuSettings::values.vsync_mode); - ReadSetting("Renderer", YuzuSettings::values.shader_backend); - ReadSetting("Renderer", YuzuSettings::values.use_asynchronous_shaders); - ReadSetting("Renderer", YuzuSettings::values.nvdec_emulation); - ReadSetting("Renderer", YuzuSettings::values.use_fast_gpu_time); - ReadSetting("Renderer", YuzuSettings::values.use_vulkan_driver_pipeline_cache); - - ReadSetting("Renderer", YuzuSettings::values.bg_red); - ReadSetting("Renderer", YuzuSettings::values.bg_green); - ReadSetting("Renderer", YuzuSettings::values.bg_blue); - - // Use GPU accuracy normal by default on Android - YuzuSettings::values.gpu_accuracy = static_cast(config->GetInteger( - "Renderer", "gpu_accuracy", static_cast(YuzuSettings::GpuAccuracy::Normal))); - - // Use GPU default anisotropic filtering on Android - YuzuSettings::values.max_anisotropy = - static_cast(config->GetInteger("Renderer", "max_anisotropy", 1)); - - // Disable ASTC compute by default on iOS - YuzuSettings::values.accelerate_astc.SetValue( - config->GetBoolean("Renderer", "accelerate_astc", false) ? YuzuSettings::AstcDecodeMode::Gpu - : YuzuSettings::AstcDecodeMode::Cpu); - - // Enable asynchronous presentation by default on Android - YuzuSettings::values.async_presentation = - config->GetBoolean("Renderer", "async_presentation", true); - - // Disable force_max_clock by default on Android - YuzuSettings::values.renderer_force_max_clock = - config->GetBoolean("Renderer", "force_max_clock", false); - - // Disable use_reactive_flushing by default on Android - YuzuSettings::values.use_reactive_flushing = - config->GetBoolean("Renderer", "use_reactive_flushing", false); - - // Audio - ReadSetting("Audio", YuzuSettings::values.sink_id); - ReadSetting("Audio", YuzuSettings::values.audio_output_device_id); - ReadSetting("Audio", YuzuSettings::values.volume); - - // Miscellaneous - // log_filter has a different default here than from common - YuzuSettings::values.log_filter = "*:Info"; - ReadSetting("Miscellaneous", YuzuSettings::values.use_dev_keys); - - // Debugging - YuzuSettings::values.record_frame_times = - config->GetBoolean("Debugging", "record_frame_times", false); - ReadSetting("Debugging", YuzuSettings::values.dump_exefs); - ReadSetting("Debugging", YuzuSettings::values.dump_nso); - ReadSetting("Debugging", YuzuSettings::values.enable_fs_access_log); - ReadSetting("Debugging", YuzuSettings::values.reporting_services); - ReadSetting("Debugging", YuzuSettings::values.quest_flag); - ReadSetting("Debugging", YuzuSettings::values.use_debug_asserts); - ReadSetting("Debugging", YuzuSettings::values.use_auto_stub); - ReadSetting("Debugging", YuzuSettings::values.disable_macro_jit); - ReadSetting("Debugging", YuzuSettings::values.disable_macro_hle); - ReadSetting("Debugging", YuzuSettings::values.use_gdbstub); - ReadSetting("Debugging", YuzuSettings::values.gdbstub_port); - - const auto title_list = config->Get("AddOns", "title_ids", ""); - std::stringstream ss(title_list); - std::string line; - while (std::getline(ss, line, '|')) { - const auto title_id = std::strtoul(line.c_str(), nullptr, 16); - const auto disabled_list = config->Get("AddOns", "disabled_" + line, ""); - - std::stringstream inner_ss(disabled_list); - std::string inner_line; - std::vector out; - while (std::getline(inner_ss, inner_line, '|')) { - out.push_back(inner_line); - } - - YuzuSettings::values.disabled_addons.insert_or_assign(title_id, out); - } - - // Web Service - ReadSetting("WebService", YuzuSettings::values.enable_telemetry); - ReadSetting("WebService", YuzuSettings::values.web_api_url); - ReadSetting("WebService", YuzuSettings::values.yuzu_username); - ReadSetting("WebService", YuzuSettings::values.yuzu_token); - - // Network - ReadSetting("Network", YuzuSettings::values.network_interface); -} - -void Config::Initialize(const std::string& config_name) { - const auto fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir); - const auto config_file = fmt::format("{}.ini", config_name); - - switch (type) { - case ConfigType::GlobalConfig: - config_loc = FS::PathToUTF8String(fs_config_loc / config_file); - break; - case ConfigType::PerGameConfig: - config_loc = FS::PathToUTF8String(fs_config_loc / "custom" / FS::ToU8String(config_file)); - break; - case ConfigType::InputProfile: - config_loc = FS::PathToUTF8String(fs_config_loc / "input" / config_file); - LoadINI(DefaultINI::android_config_file); - return; - } - LoadINI(DefaultINI::android_config_file); - ReadValues(); -} +} // namespace IOSSettings diff --git a/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.mm b/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.mm index 428244fea1..857002adfc 100644 --- a/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.mm +++ b/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.mm @@ -4,7 +4,6 @@ // #import - #import "DirectoryManager.h" NSURL *DocumentsDirectory() { From 71d22bb979d647eb0972ba37f6f2310396372fc1 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Feb 2026 03:53:16 +0000 Subject: [PATCH 04/54] loicense --- src/ios/Eden/AppUI-Bridging-Header.h | 3 +++ src/ios/Eden/AppUI.swift | 3 +++ .../AppUIGameInformation/AppUIGameInformation.h | 3 +++ .../AppUIGameInformation/AppUIGameInformation.mm | 3 +++ src/ios/Eden/Wrapper/AppUIObjC.h | 3 +++ src/ios/Eden/Wrapper/AppUIObjC.mm | 15 +++++++++------ src/ios/Eden/Wrapper/Config/Config.mm | 3 +++ .../Wrapper/DirectoryManager/DirectoryManager.h | 3 +++ .../Wrapper/DirectoryManager/DirectoryManager.mm | 3 +++ .../Wrapper/EmulationSession/EmulationSession.h | 3 +++ .../Wrapper/EmulationSession/EmulationSession.mm | 15 +++++++++------ .../Wrapper/EmulationWindow/EmulationWindow.h | 3 +++ .../Wrapper/EmulationWindow/EmulationWindow.mm | 3 +++ 13 files changed, 51 insertions(+), 12 deletions(-) diff --git a/src/ios/Eden/AppUI-Bridging-Header.h b/src/ios/Eden/AppUI-Bridging-Header.h index a75f43550d..091fe7117f 100644 --- a/src/ios/Eden/AppUI-Bridging-Header.h +++ b/src/ios/Eden/AppUI-Bridging-Header.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // // AppUI-Bridging-Header.h - Sudachi // Created by Jarrod Norwell on 4/3/2024. diff --git a/src/ios/Eden/AppUI.swift b/src/ios/Eden/AppUI.swift index 6bd4544b0d..0dd7ac4dd8 100644 --- a/src/ios/Eden/AppUI.swift +++ b/src/ios/Eden/AppUI.swift @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // // AppUI.swift - Sudachi // Created by Jarrod Norwell on 4/3/2024. diff --git a/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.h b/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.h index 5040775ad0..ef8537faee 100644 --- a/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.h +++ b/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // // AppUIGameInformation.h - Sudachi // Created by Jarrod Norwell on 1/20/24. diff --git a/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.mm b/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.mm index ef65c723f8..33ff14a875 100644 --- a/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.mm +++ b/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.mm @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + // // AppUIGameInformation.mm - Sudachi // Created by Jarrod Norwell on 1/20/24. diff --git a/src/ios/Eden/Wrapper/AppUIObjC.h b/src/ios/Eden/Wrapper/AppUIObjC.h index d3594d74d1..1a79babf4f 100644 --- a/src/ios/Eden/Wrapper/AppUIObjC.h +++ b/src/ios/Eden/Wrapper/AppUIObjC.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // // AppUIObjC.h - Sudachi // Created by Jarrod Norwell on 1/8/24. diff --git a/src/ios/Eden/Wrapper/AppUIObjC.mm b/src/ios/Eden/Wrapper/AppUIObjC.mm index 065ce6d046..81070bb3fb 100644 --- a/src/ios/Eden/Wrapper/AppUIObjC.mm +++ b/src/ios/Eden/Wrapper/AppUIObjC.mm @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // // AppUIObjC.mm - Sudachi // Created by Jarrod Norwell on 1/8/24. @@ -79,12 +82,12 @@ EmulationSession::GetInstance().InitializeGpuDriver(); - YuzuSettings::values.dump_shaders.SetValue(true); - YuzuSettings::values.use_asynchronous_shaders.SetValue(true); - // YuzuSettings::values.astc_recompression.SetValue(YuzuSettings::AstcRecompression::Bc3); - YuzuSettings::values.shader_backend.SetValue(YuzuSettings::ShaderBackend::SpirV); - // YuzuSettings::values.resolution_setup.SetValue(YuzuSettings::ResolutionSetup::Res1X); - // YuzuSettings::values.scaling_filter.SetValue(YuzuSettings::ScalingFilter::Bilinear); + Settings::values.dump_shaders.SetValue(true); + Settings::values.use_asynchronous_shaders.SetValue(true); + // Settings::values.astc_recompression.SetValue(Settings::AstcRecompression::Bc3); + Settings::values.shader_backend.SetValue(Settings::ShaderBackend::SpirV); + // Settings::values.resolution_setup.SetValue(Settings::ResolutionSetup::Res1X); + // Settings::values.scaling_filter.SetValue(Settings::ScalingFilter::Bilinear); } return self; } diff --git a/src/ios/Eden/Wrapper/Config/Config.mm b/src/ios/Eden/Wrapper/Config/Config.mm index 0a01d234df..5b063d79f9 100644 --- a/src/ios/Eden/Wrapper/Config/Config.mm +++ b/src/ios/Eden/Wrapper/Config/Config.mm @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include "Config.h" diff --git a/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.h b/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.h index 3965b6c2bb..0fc74a4a93 100644 --- a/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.h +++ b/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // // DirectoryManager.h - Sudachi // Created by Jarrod Norwell on 1/18/24. diff --git a/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.mm b/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.mm index 857002adfc..ad8b37c932 100644 --- a/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.mm +++ b/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.mm @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // // DirectoryManager.mm - Sudachi // Created by Jarrod Norwell on 1/18/24. diff --git a/src/ios/Eden/Wrapper/EmulationSession/EmulationSession.h b/src/ios/Eden/Wrapper/EmulationSession/EmulationSession.h index 291d414b37..c3692eede6 100644 --- a/src/ios/Eden/Wrapper/EmulationSession/EmulationSession.h +++ b/src/ios/Eden/Wrapper/EmulationSession/EmulationSession.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // // EmulationSession.h - Sudachi // Created by Jarrod Norwell on 1/20/24. diff --git a/src/ios/Eden/Wrapper/EmulationSession/EmulationSession.mm b/src/ios/Eden/Wrapper/EmulationSession/EmulationSession.mm index 18793ca9fe..2575f053e2 100644 --- a/src/ios/Eden/Wrapper/EmulationSession/EmulationSession.mm +++ b/src/ios/Eden/Wrapper/EmulationSession/EmulationSession.mm @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // // EmulationSession.m - Sudachi // Created by Jarrod Norwell on 1/20/24. @@ -204,7 +207,7 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string // Initialize system. m_system.SetShuttingDown(false); m_system.ApplySettings(); - YuzuSettings::LogSettings(); + Settings::LogSettings(); m_system.HIDCore().ReloadInputDevices(); m_system.SetFrontendAppletSet({ nullptr, // Amiibo Settings @@ -238,7 +241,7 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string m_system.GetCpuManager().OnGpuReady(); m_system.RegisterExitCallback([&] { HaltEmulation(); }); - if (YuzuSettings::values.use_disk_shader_cache.GetValue()) { + if (Settings::values.use_disk_shader_cache.GetValue()) { m_system.Renderer().ReadRasterizer()->LoadDiskResources( m_system.GetApplicationProcessProgramID(), std::stop_token{}, [](VideoCore::LoadCallbackStage, size_t value, size_t total) {}); @@ -265,7 +268,7 @@ Core::SystemResultStatus EmulationSession::BootOS() { // Initialize system. m_system.SetShuttingDown(false); m_system.ApplySettings(); - YuzuSettings::LogSettings(); + Settings::LogSettings(); m_system.HIDCore().ReloadInputDevices(); m_system.SetFrontendAppletSet({ nullptr, // Amiibo Settings @@ -305,7 +308,7 @@ Core::SystemResultStatus EmulationSession::BootOS() { m_system.GetCpuManager().OnGpuReady(); m_system.RegisterExitCallback([&] { HaltEmulation(); }); - if (YuzuSettings::values.use_disk_shader_cache.GetValue()) { + if (Settings::values.use_disk_shader_cache.GetValue()) { m_system.Renderer().ReadRasterizer()->LoadDiskResources( m_system.GetApplicationProcessProgramID(), std::stop_token{}, [](VideoCore::LoadCallbackStage, size_t value, size_t total) {}); @@ -377,7 +380,7 @@ void EmulationSession::RunEmulation() { } // Load the disk shader cache. - if (YuzuSettings::values.use_disk_shader_cache.GetValue()) { + if (Settings::values.use_disk_shader_cache.GetValue()) { LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); m_system.Renderer().ReadRasterizer()->LoadDiskResources( m_system.GetApplicationProcessProgramID(), std::stop_token{}, LoadDiskCacheProgress); @@ -484,7 +487,7 @@ bool EmulationSession::IsHandheldOnly() { return false; } - return !YuzuSettings::IsDockedMode(); + return !Settings::IsDockedMode(); } void EmulationSession::SetDeviceType([[maybe_unused]] int index, int type) { diff --git a/src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.h b/src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.h index d099c88c55..4d8b0b888f 100644 --- a/src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.h +++ b/src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // // EmulationWindow.h - Sudachi // Created by Jarrod Norwell on 1/18/24. diff --git a/src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.mm b/src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.mm index a0e388e751..a82c5b5a7f 100644 --- a/src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.mm +++ b/src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.mm @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // // EmulationWindow.mm - Sudachi // Created by Jarrod Norwell on 1/18/24. From 1709fb1ad244a1d68c547149c5773701ca54b4af Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Feb 2026 04:02:03 +0000 Subject: [PATCH 05/54] flatten --- .../AppUIGameInformation.h | 0 .../AppUIGameInformation.mm | 8 +++++--- src/ios/Eden/{Wrapper => }/AppUIObjC.h | 0 src/ios/Eden/{Wrapper => }/AppUIObjC.mm | 4 +++- src/ios/Eden/{Wrapper/Config => }/Config.h | 0 src/ios/Eden/{Wrapper/Config => }/Config.mm | 0 .../EmulationSession => }/EmulationSession.h | 2 +- .../EmulationSession => }/EmulationSession.mm | 0 .../EmulationWindow => }/EmulationWindow.h | 0 .../EmulationWindow => }/EmulationWindow.mm | 10 +++------- .../DirectoryManager/DirectoryManager.h | 13 ------------- .../DirectoryManager/DirectoryManager.mm | 18 ------------------ 12 files changed, 12 insertions(+), 43 deletions(-) rename src/ios/Eden/{Wrapper/AppUIGameInformation => }/AppUIGameInformation.h (100%) rename src/ios/Eden/{Wrapper/AppUIGameInformation => }/AppUIGameInformation.mm (97%) rename src/ios/Eden/{Wrapper => }/AppUIObjC.h (100%) rename src/ios/Eden/{Wrapper => }/AppUIObjC.mm (97%) rename src/ios/Eden/{Wrapper/Config => }/Config.h (100%) rename src/ios/Eden/{Wrapper/Config => }/Config.mm (100%) rename src/ios/Eden/{Wrapper/EmulationSession => }/EmulationSession.h (98%) rename src/ios/Eden/{Wrapper/EmulationSession => }/EmulationSession.mm (100%) rename src/ios/Eden/{Wrapper/EmulationWindow => }/EmulationWindow.h (100%) rename src/ios/Eden/{Wrapper/EmulationWindow => }/EmulationWindow.mm (85%) delete mode 100644 src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.h delete mode 100644 src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.mm diff --git a/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.h b/src/ios/Eden/AppUIGameInformation.h similarity index 100% rename from src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.h rename to src/ios/Eden/AppUIGameInformation.h diff --git a/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.mm b/src/ios/Eden/AppUIGameInformation.mm similarity index 97% rename from src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.mm rename to src/ios/Eden/AppUIGameInformation.mm index 33ff14a875..3397faa1a7 100644 --- a/src/ios/Eden/Wrapper/AppUIGameInformation/AppUIGameInformation.mm +++ b/src/ios/Eden/AppUIGameInformation.mm @@ -6,9 +6,9 @@ // Created by Jarrod Norwell on 1/20/24. // +#import #import "AppUIGameInformation.h" -#import "../DirectoryManager/DirectoryManager.h" -#import "../EmulationSession/EmulationSession.h" +#import "EmulationSession/EmulationSession.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" @@ -382,7 +382,9 @@ GameMetadata CacheGameMetadata(const std::string& path) { GameMetadata GameMetadata(const std::string& path, bool reload = false) { if (!EmulationSession::GetInstance().IsInitialized()) { - Common::FS::SetAppDirectory(DirectoryManager::AppUIDirectory()); + NSURL *dir_url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject]; + const char *directory_cstr = [[dir_url path] UTF8String]; + Common::FS::SetAppDirectory(directory_cstr); EmulationSession::GetInstance().System().Initialize(); EmulationSession::GetInstance().InitializeSystem(false); diff --git a/src/ios/Eden/Wrapper/AppUIObjC.h b/src/ios/Eden/AppUIObjC.h similarity index 100% rename from src/ios/Eden/Wrapper/AppUIObjC.h rename to src/ios/Eden/AppUIObjC.h diff --git a/src/ios/Eden/Wrapper/AppUIObjC.mm b/src/ios/Eden/AppUIObjC.mm similarity index 97% rename from src/ios/Eden/Wrapper/AppUIObjC.mm rename to src/ios/Eden/AppUIObjC.mm index 81070bb3fb..97cdc894b5 100644 --- a/src/ios/Eden/Wrapper/AppUIObjC.mm +++ b/src/ios/Eden/AppUIObjC.mm @@ -73,8 +73,10 @@ if (self = [super init]) { _gameInformation = [AppUIGameInformation sharedInstance]; + NSURL *dir_url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject]; + const char *directory_cstr = [[dir_url path] UTF8String]; - Common::FS::SetAppDirectory(DirectoryManager::AppUIDirectory()); + Common::FS::SetAppDirectory(directory_cstr); Config{"config", Config::ConfigType::GlobalConfig}; EmulationSession::GetInstance().System().Initialize(); diff --git a/src/ios/Eden/Wrapper/Config/Config.h b/src/ios/Eden/Config.h similarity index 100% rename from src/ios/Eden/Wrapper/Config/Config.h rename to src/ios/Eden/Config.h diff --git a/src/ios/Eden/Wrapper/Config/Config.mm b/src/ios/Eden/Config.mm similarity index 100% rename from src/ios/Eden/Wrapper/Config/Config.mm rename to src/ios/Eden/Config.mm diff --git a/src/ios/Eden/Wrapper/EmulationSession/EmulationSession.h b/src/ios/Eden/EmulationSession.h similarity index 98% rename from src/ios/Eden/Wrapper/EmulationSession/EmulationSession.h rename to src/ios/Eden/EmulationSession.h index c3692eede6..56c1930df6 100644 --- a/src/ios/Eden/Wrapper/EmulationSession/EmulationSession.h +++ b/src/ios/Eden/EmulationSession.h @@ -11,7 +11,7 @@ #import #import -#import "../EmulationWindow/EmulationWindow.h" +#import "EmulationWindow/EmulationWindow.h" #include "common/detached_tasks.h" #include "core/core.h" diff --git a/src/ios/Eden/Wrapper/EmulationSession/EmulationSession.mm b/src/ios/Eden/EmulationSession.mm similarity index 100% rename from src/ios/Eden/Wrapper/EmulationSession/EmulationSession.mm rename to src/ios/Eden/EmulationSession.mm diff --git a/src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.h b/src/ios/Eden/EmulationWindow.h similarity index 100% rename from src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.h rename to src/ios/Eden/EmulationWindow.h diff --git a/src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.mm b/src/ios/Eden/EmulationWindow.mm similarity index 85% rename from src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.mm rename to src/ios/Eden/EmulationWindow.mm index a82c5b5a7f..f5c53309b4 100644 --- a/src/ios/Eden/Wrapper/EmulationWindow/EmulationWindow.mm +++ b/src/ios/Eden/EmulationWindow.mm @@ -7,7 +7,7 @@ // #import "EmulationWindow.h" -#import "../EmulationSession/EmulationSession.h" +#import "EmulationSession/EmulationSession.h" #include @@ -58,9 +58,7 @@ void EmulationWindow::OnGamepadJoystickEvent(int player_index, int stick_id, flo m_input_subsystem->GetVirtualGamepad()->SetStickPosition(player_index, stick_id, x, y); } -void EmulationWindow::OnGamepadMotionEvent(int player_index, u64 delta_timestamp, float gyro_x, - float gyro_y, float gyro_z, float accel_x, - float accel_y, float accel_z) { +void EmulationWindow::OnGamepadMotionEvent(int player_index, u64 delta_timestamp, float gyro_x, float gyro_y, float gyro_z, float accel_x, float accel_y, float accel_z) { m_input_subsystem->GetVirtualGamepad()->SetMotionState(player_index, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z); } @@ -70,9 +68,7 @@ void EmulationWindow::OnFrameDisplayed() { } } -EmulationWindow::EmulationWindow(InputCommon::InputSubsystem* input_subsystem, CA::MetalLayer* surface, CGSize size, - std::shared_ptr driver_library) -: m_input_subsystem{input_subsystem}, m_size{size}, m_driver_library{driver_library} { +EmulationWindow::EmulationWindow(InputCommon::InputSubsystem* input_subsystem, CA::MetalLayer* surface, CGSize size, std::shared_ptr driver_library) : m_input_subsystem{input_subsystem}, m_size{size}, m_driver_library{driver_library} { LOG_INFO(Frontend, "initializing"); if (!surface) { diff --git a/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.h b/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.h deleted file mode 100644 index 0fc74a4a93..0000000000 --- a/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.h +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -// -// DirectoryManager.h - Sudachi -// Created by Jarrod Norwell on 1/18/24. -// - -#pragma once - -namespace DirectoryManager { -const char* AppUIDirectory(void); -} diff --git a/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.mm b/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.mm deleted file mode 100644 index ad8b37c932..0000000000 --- a/src/ios/Eden/Wrapper/DirectoryManager/DirectoryManager.mm +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -// -// DirectoryManager.mm - Sudachi -// Created by Jarrod Norwell on 1/18/24. -// - -#import -#import "DirectoryManager.h" - -NSURL *DocumentsDirectory() { - return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject]; -} - -const char* DirectoryManager::AppUIDirectory(void) { - return [[DocumentsDirectory() path] UTF8String]; -} From d29cc2949f77c1fe82268d79d24a005e037e8cc3 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Feb 2026 04:21:48 +0000 Subject: [PATCH 06/54] flatten + cmake --- src/CMakeLists.txt | 4 +++ src/ios/{Eden => }/AppUI-Bridging-Header.h | 0 src/ios/{Eden => }/AppUI.swift | 0 src/ios/{Eden => }/AppUIGameInformation.h | 0 src/ios/{Eden => }/AppUIGameInformation.mm | 0 src/ios/{Eden => }/AppUIObjC.h | 0 src/ios/{Eden => }/AppUIObjC.mm | 0 src/ios/CMakeLists.txt | 29 ++++++++++++++++++++++ src/ios/{Eden => }/Config.h | 0 src/ios/{Eden => }/Config.mm | 0 src/ios/{Eden => }/EmulationSession.h | 0 src/ios/{Eden => }/EmulationSession.mm | 0 src/ios/{Eden => }/EmulationWindow.h | 0 src/ios/{Eden => }/EmulationWindow.mm | 0 14 files changed, 33 insertions(+) rename src/ios/{Eden => }/AppUI-Bridging-Header.h (100%) rename src/ios/{Eden => }/AppUI.swift (100%) rename src/ios/{Eden => }/AppUIGameInformation.h (100%) rename src/ios/{Eden => }/AppUIGameInformation.mm (100%) rename src/ios/{Eden => }/AppUIObjC.h (100%) rename src/ios/{Eden => }/AppUIObjC.mm (100%) create mode 100644 src/ios/CMakeLists.txt rename src/ios/{Eden => }/Config.h (100%) rename src/ios/{Eden => }/Config.mm (100%) rename src/ios/{Eden => }/EmulationSession.h (100%) rename src/ios/{Eden => }/EmulationSession.mm (100%) rename src/ios/{Eden => }/EmulationWindow.h (100%) rename src/ios/{Eden => }/EmulationWindow.mm (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 600b985609..3759878c2a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -249,4 +249,8 @@ if (ANDROID) target_include_directories(yuzu-android PRIVATE android/app/src/main) endif() +if (IOS) + add_subdirectory(ios) +endif() + include(GenerateDepHashes) diff --git a/src/ios/Eden/AppUI-Bridging-Header.h b/src/ios/AppUI-Bridging-Header.h similarity index 100% rename from src/ios/Eden/AppUI-Bridging-Header.h rename to src/ios/AppUI-Bridging-Header.h diff --git a/src/ios/Eden/AppUI.swift b/src/ios/AppUI.swift similarity index 100% rename from src/ios/Eden/AppUI.swift rename to src/ios/AppUI.swift diff --git a/src/ios/Eden/AppUIGameInformation.h b/src/ios/AppUIGameInformation.h similarity index 100% rename from src/ios/Eden/AppUIGameInformation.h rename to src/ios/AppUIGameInformation.h diff --git a/src/ios/Eden/AppUIGameInformation.mm b/src/ios/AppUIGameInformation.mm similarity index 100% rename from src/ios/Eden/AppUIGameInformation.mm rename to src/ios/AppUIGameInformation.mm diff --git a/src/ios/Eden/AppUIObjC.h b/src/ios/AppUIObjC.h similarity index 100% rename from src/ios/Eden/AppUIObjC.h rename to src/ios/AppUIObjC.h diff --git a/src/ios/Eden/AppUIObjC.mm b/src/ios/AppUIObjC.mm similarity index 100% rename from src/ios/Eden/AppUIObjC.mm rename to src/ios/AppUIObjC.mm diff --git a/src/ios/CMakeLists.txt b/src/ios/CMakeLists.txt new file mode 100644 index 0000000000..73f95b8ee5 --- /dev/null +++ b/src/ios/CMakeLists.txt @@ -0,0 +1,29 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +enable_language(Swift OBJC) + +add_executable(eden-ios + AppUI-Bridging-Header.h + AppUI.swift + AppUIGameInformation.h + AppUIGameInformation.mm + AppUIObjC.h + AppUIObjC.mm + Config.h + Config.mm + EmulationSession.h + EmulationSession.mm + EmulationWindow.h + EmulationWindow.mm +) + +target_link_libraries(eden-ios PRIVATE common core input_common frontend_common video_core glad) +target_link_libraries(eden-ios PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) +target_link_libraries(eden-ios PRIVATE SDL2::SDL2) +create_target_directory_groups(eden-ios) +target_compile_options(eden-ios PRIVATE + -Wno-conversion + -Wno-unused-variable + -Wno-unused-parameter + -Wno-missing-field-initializers) diff --git a/src/ios/Eden/Config.h b/src/ios/Config.h similarity index 100% rename from src/ios/Eden/Config.h rename to src/ios/Config.h diff --git a/src/ios/Eden/Config.mm b/src/ios/Config.mm similarity index 100% rename from src/ios/Eden/Config.mm rename to src/ios/Config.mm diff --git a/src/ios/Eden/EmulationSession.h b/src/ios/EmulationSession.h similarity index 100% rename from src/ios/Eden/EmulationSession.h rename to src/ios/EmulationSession.h diff --git a/src/ios/Eden/EmulationSession.mm b/src/ios/EmulationSession.mm similarity index 100% rename from src/ios/Eden/EmulationSession.mm rename to src/ios/EmulationSession.mm diff --git a/src/ios/Eden/EmulationWindow.h b/src/ios/EmulationWindow.h similarity index 100% rename from src/ios/Eden/EmulationWindow.h rename to src/ios/EmulationWindow.h diff --git a/src/ios/Eden/EmulationWindow.mm b/src/ios/EmulationWindow.mm similarity index 100% rename from src/ios/Eden/EmulationWindow.mm rename to src/ios/EmulationWindow.mm From 3df9e8da21fcb17f9c09afd0d7a27457617e8593 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Feb 2026 04:21:54 +0000 Subject: [PATCH 07/54] license headers --- .ci/license-header.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/license-header.sh b/.ci/license-header.sh index 6b19f91185..b674234c7c 100755 --- a/.ci/license-header.sh +++ b/.ci/license-header.sh @@ -115,7 +115,7 @@ for file in $FILES; do *.cmake|*.sh|*CMakeLists.txt) begin="#" ;; - *.kt*|*.cpp|*.h|*.qml) + *.kt*|*.cpp|*.h|*.qml|*.swift|*.mm) begin="//" ;; *) From 40c0ae74343e36f291e0a0e3eb2ab00d604faf58 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 19 Feb 2026 04:22:20 +0000 Subject: [PATCH 08/54] license --- src/ios/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ios/CMakeLists.txt b/src/ios/CMakeLists.txt index 73f95b8ee5..6ddc7eb109 100644 --- a/src/ios/CMakeLists.txt +++ b/src/ios/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later enable_language(Swift OBJC) From 5c983b417d7bf226480c61e4d0ce172d00febdab Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 21 Feb 2026 23:39:01 +0000 Subject: [PATCH 09/54] ios toolchain cmake --- .ci/ios/build.sh | 27 + .ci/ios/ios-toolchain.cmake | 1177 +++++++++++++++++++++++++++++++++++ 2 files changed, 1204 insertions(+) create mode 100644 .ci/ios/build.sh create mode 100644 .ci/ios/ios-toolchain.cmake diff --git a/.ci/ios/build.sh b/.ci/ios/build.sh new file mode 100644 index 0000000000..f179a6c929 --- /dev/null +++ b/.ci/ios/build.sh @@ -0,0 +1,27 @@ +#!/bin/sh -ex + +WORK_DIR="$PWD" +if [ -z "$NPROC" ]; then + NPROC="$(nproc)" +fi + +cmake -G Xcode -B build \ + -DCMAKE_TOOLCHAIN_FILE="$WORK_DIR/ios-toolchain.cmake" \ + -DPLATFORM=OS64 \ + -DENABLE_LIBUSB=OFF \ + -DENABLE_UPDATE_CHECKER=OFF \ + -DENABLE_QT=OFF \ + -DENABLE_OPENSSL=OFF \ + -DENABLE_WEB_SERVICE=OFF \ + -DENABLE_CUBEB=OFF \ + -DYUZU_ROOM=OFF \ + -DYUZU_ROOM_STANDALONE=OFF \ + -DYUZU_CMD=OFF \ + -DUSE_DISCORD_PRESENCE=OFF \ + -DYUZU_USE_EXTERNAL_FFMPEG=ON \ + -DYUZU_USE_CPM=ON \ + -DYUZU_USE_EXTERNAL_SDL2=ON \ + -DCPMUTIL_FORCE_BUNDLED=ON \ + -DCMAKE_BUILD_TYPE=Release + +cmake --build build -- -j${NPROC} diff --git a/.ci/ios/ios-toolchain.cmake b/.ci/ios/ios-toolchain.cmake new file mode 100644 index 0000000000..3ee3940a38 --- /dev/null +++ b/.ci/ios/ios-toolchain.cmake @@ -0,0 +1,1177 @@ +# This file is part of the ios-cmake project. It was retrieved from +# https://github.com/leetal/ios-cmake.git, which is a fork of +# https://github.com/gerstrong/ios-cmake.git, which is a fork of +# https://github.com/cristeab/ios-cmake.git, which is a fork of +# https://code.google.com/p/ios-cmake/. Which in turn is based off of +# the Platform/Darwin.cmake and Platform/UnixPaths.cmake files which +# are included with CMake 2.8.4 +# +# The ios-cmake project is licensed under the new BSD license. +# +# Copyright (c) 2014, Bogdan Cristea and LTE Engineering Software, +# Kitware, Inc., Insight Software Consortium. All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# This file is based on the Platform/Darwin.cmake and +# Platform/UnixPaths.cmake files which are included with CMake 2.8.4 +# It has been altered for iOS development. +# +# Updated by Alex Stewart (alexs.mac@gmail.com) +# +# ***************************************************************************** +# Now maintained by Alexander Widerberg (widerbergaren [at] gmail.com) +# under the BSD-3-Clause license +# https://github.com/leetal/ios-cmake +# ***************************************************************************** +# +# INFORMATION / HELP +# +############################################################################### +# OPTIONS # +############################################################################### +# +# PLATFORM: (default "OS64") +# OS = Build for iPhoneOS. +# OS64 = Build for arm64 iphoneOS. +# OS64COMBINED = Build for arm64 x86_64 iphoneOS + iphoneOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) +# SIMULATOR = Build for x86 i386 iphoneOS Simulator. +# SIMULATOR64 = Build for x86_64 iphoneOS Simulator. +# SIMULATORARM64 = Build for arm64 iphoneOS Simulator. +# SIMULATOR64COMBINED = Build for arm64 x86_64 iphoneOS Simulator. Combined into FAT STATIC lib (supported on 3.14+ of CMakewith "-G Xcode" argument ONLY) +# TVOS = Build for arm64 tvOS. +# TVOSCOMBINED = Build for arm64 x86_64 tvOS + tvOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) +# SIMULATOR_TVOS = Build for x86_64 tvOS Simulator. +# SIMULATORARM64_TVOS = Build for arm64 tvOS Simulator. +# VISIONOSCOMBINED = Build for arm64 visionOS + visionOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) +# VISIONOS = Build for arm64 visionOS. +# SIMULATOR_VISIONOS = Build for arm64 visionOS Simulator. +# WATCHOS = Build for armv7k arm64_32 for watchOS. +# WATCHOSCOMBINED = Build for armv7k arm64_32 x86_64 watchOS + watchOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) +# SIMULATOR_WATCHOS = Build for x86_64 for watchOS Simulator. +# SIMULATORARM64_WATCHOS = Build for arm64 for watchOS Simulator. +# SIMULATOR_WATCHOSCOMBINED = Build for arm64 x86_64 for watchOS Simulator. Combined into FAT STATIC lib (supported on 3.14+ of CMakewith "-G Xcode" argument ONLY) +# MAC = Build for x86_64 macOS. +# MAC_ARM64 = Build for Apple Silicon macOS. +# MAC_UNIVERSAL = Combined build for x86_64 and Apple Silicon on macOS. +# MAC_CATALYST = Build for x86_64 macOS with Catalyst support (iOS toolchain on macOS). +# Note: The build argument "MACOSX_DEPLOYMENT_TARGET" can be used to control min-version of macOS +# MAC_CATALYST_ARM64 = Build for Apple Silicon macOS with Catalyst support (iOS toolchain on macOS). +# Note: The build argument "MACOSX_DEPLOYMENT_TARGET" can be used to control min-version of macOS +# MAC_CATALYST_UNIVERSAL = Combined build for x86_64 and Apple Silicon on Catalyst. +# +# CMAKE_OSX_SYSROOT: Path to the SDK to use. By default this is +# automatically determined from PLATFORM and xcodebuild, but +# can also be manually specified (although this should not be required). +# +# CMAKE_DEVELOPER_ROOT: Path to the Developer directory for the platform +# being compiled for. By default, this is automatically determined from +# CMAKE_OSX_SYSROOT, but can also be manually specified (although this should +# not be required). +# +# DEPLOYMENT_TARGET: Minimum SDK version to target. Default 6.0 on watchOS, 13.0 on tvOS+iOS/iPadOS, 11.0 on macOS, 1.0 on visionOS +# +# NAMED_LANGUAGE_SUPPORT: +# ON (default) = Will require "enable_language(OBJC) and/or enable_language(OBJCXX)" for full OBJC|OBJCXX support +# OFF = Will embed the OBJC and OBJCXX flags into the CMAKE_C_FLAGS and CMAKE_CXX_FLAGS (legacy behavior, CMake version < 3.16) +# +# ENABLE_BITCODE: (ON|OFF) Enables or disables bitcode support. Default OFF +# +# ENABLE_ARC: (ON|OFF) Enables or disables ARC support. Default ON (ARC enabled by default) +# +# ENABLE_VISIBILITY: (ON|OFF) Enables or disables symbol visibility support. Default OFF (visibility hidden by default) +# +# ENABLE_STRICT_TRY_COMPILE: (ON|OFF) Enables or disables strict try_compile() on all Check* directives (will run linker +# to actually check if linking is possible). Default OFF (will set CMAKE_TRY_COMPILE_TARGET_TYPE to STATIC_LIBRARY) +# +# ARCHS: (armv7 armv7s armv7k arm64 arm64_32 i386 x86_64) If specified, will override the default architectures for the given PLATFORM +# OS = armv7 armv7s arm64 (if applicable) +# OS64 = arm64 (if applicable) +# SIMULATOR = i386 +# SIMULATOR64 = x86_64 +# SIMULATORARM64 = arm64 +# TVOS = arm64 +# SIMULATOR_TVOS = x86_64 (i386 has since long been deprecated) +# SIMULATORARM64_TVOS = arm64 +# WATCHOS = armv7k arm64_32 (if applicable) +# SIMULATOR_WATCHOS = x86_64 (i386 has since long been deprecated) +# SIMULATORARM64_WATCHOS = arm64 +# MAC = x86_64 +# MAC_ARM64 = arm64 +# MAC_UNIVERSAL = x86_64 arm64 +# MAC_CATALYST = x86_64 +# MAC_CATALYST_ARM64 = arm64 +# MAC_CATALYST_UNIVERSAL = x86_64 arm64 +# +# NOTE: When manually specifying ARCHS, put a semi-colon between the entries. E.g., -DARCHS="armv7;arm64" +# +############################################################################### +# END OPTIONS # +############################################################################### +# +# This toolchain defines the following properties (available via get_property()) for use externally: +# +# PLATFORM: The currently targeted platform. +# XCODE_VERSION: Version number (not including Build version) of Xcode detected. +# SDK_VERSION: Version of SDK being used. +# OSX_ARCHITECTURES: Architectures being compiled for (generated from PLATFORM). +# APPLE_TARGET_TRIPLE: Used by autoconf build systems. NOTE: If "ARCHS" is overridden, this will *NOT* be set! +# +# This toolchain defines the following macros for use externally: +# +# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE XCODE_VARIANT) +# A convenience macro for setting xcode specific properties on targets. +# Available variants are: All, Release, RelWithDebInfo, Debug, MinSizeRel +# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1" "all"). +# +# find_host_package (PROGRAM ARGS) +# A macro used to find executable programs on the host system, not within the +# environment. Thanks to the android-cmake project for providing the +# command. +# + +cmake_minimum_required(VERSION 3.8.0) + +# CMake invokes the toolchain file twice during the first build, but only once during subsequent rebuilds. +# NOTE: To improve single-library build-times, provide the flag "OS_SINGLE_BUILD" as a build argument. +if(DEFINED OS_SINGLE_BUILD AND DEFINED ENV{_IOS_TOOLCHAIN_HAS_RUN}) + return() +endif() +set(ENV{_IOS_TOOLCHAIN_HAS_RUN} true) + +# List of supported platform values +list(APPEND _supported_platforms + "OS" "OS64" "OS64COMBINED" "SIMULATOR" "SIMULATOR64" "SIMULATORARM64" "SIMULATOR64COMBINED" + "TVOS" "TVOSCOMBINED" "SIMULATOR_TVOS" "SIMULATORARM64_TVOS" + "WATCHOS" "WATCHOSCOMBINED" "SIMULATOR_WATCHOS" "SIMULATORARM64_WATCHOS" "SIMULATOR_WATCHOSCOMBINED" + "MAC" "MAC_ARM64" "MAC_UNIVERSAL" + "VISIONOS" "SIMULATOR_VISIONOS" "VISIONOSCOMBINED" + "MAC_CATALYST" "MAC_CATALYST_ARM64" "MAC_CATALYST_UNIVERSAL") + +# Cache what generator is used +set(USED_CMAKE_GENERATOR "${CMAKE_GENERATOR}") + +# Check if using a CMake version capable of building combined FAT builds (simulator and target slices combined in one static lib) +if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14") + set(MODERN_CMAKE YES) +endif() + +# Get the Xcode version being used. +# Problem: CMake runs toolchain files multiple times, but can't read cache variables on some runs. +# Workaround: On the first run (in which cache variables are always accessible), set an intermediary environment variable. +# +# NOTE: This pattern is used in many places in this toolchain to speed up checks of all sorts +if(DEFINED XCODE_VERSION_INT) + # Environment variables are always preserved. + set(ENV{_XCODE_VERSION_INT} "${XCODE_VERSION_INT}") +elseif(DEFINED ENV{_XCODE_VERSION_INT}) + set(XCODE_VERSION_INT "$ENV{_XCODE_VERSION_INT}") +elseif(NOT DEFINED XCODE_VERSION_INT) + find_program(XCODEBUILD_EXECUTABLE xcodebuild) + if(NOT XCODEBUILD_EXECUTABLE) + message(FATAL_ERROR "xcodebuild not found. Please install either the standalone commandline tools or Xcode.") + endif() + execute_process(COMMAND ${XCODEBUILD_EXECUTABLE} -version + OUTPUT_VARIABLE XCODE_VERSION_INT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REGEX MATCH "Xcode [0-9\\.]+" XCODE_VERSION_INT "${XCODE_VERSION_INT}") + string(REGEX REPLACE "Xcode ([0-9\\.]+)" "\\1" XCODE_VERSION_INT "${XCODE_VERSION_INT}") + set(XCODE_VERSION_INT "${XCODE_VERSION_INT}" CACHE INTERNAL "") +endif() + +# Assuming that xcode 12.0 is installed you most probably have ios sdk 14.0 or later installed (tested on Big Sur) +# if you don't set a deployment target it will be set the way you only get 64-bit builds +#if(NOT DEFINED DEPLOYMENT_TARGET AND XCODE_VERSION_INT VERSION_GREATER 12.0) +# Temporarily fix the arm64 issues in CMake install-combined by excluding arm64 for simulator builds (needed for Apple Silicon...) +# set(CMAKE_XCODE_ATTRIBUTE_EXCLUDED_ARCHS[sdk=iphonesimulator*] "arm64") +#endif() + +# Check if the platform variable is set +if(DEFINED PLATFORM) + # Environment variables are always preserved. + set(ENV{_PLATFORM} "${PLATFORM}") +elseif(DEFINED ENV{_PLATFORM}) + set(PLATFORM "$ENV{_PLATFORM}") +elseif(NOT DEFINED PLATFORM) + message(FATAL_ERROR "PLATFORM argument not set. Bailing configure since I don't know what target you want to build for!") +endif () + +if(PLATFORM MATCHES ".*COMBINED" AND NOT CMAKE_GENERATOR MATCHES "Xcode") + message(FATAL_ERROR "The combined builds support requires Xcode to be used as a generator via '-G Xcode' command-line argument in CMake") +endif() + +# Safeguard that the platform value is set and is one of the supported values +list(FIND _supported_platforms ${PLATFORM} contains_PLATFORM) +if("${contains_PLATFORM}" EQUAL "-1") + string(REPLACE ";" "\n * " _supported_platforms_formatted "${_supported_platforms}") + message(FATAL_ERROR " Invalid PLATFORM specified! Current value: ${PLATFORM}.\n" + " Supported PLATFORM values: \n * ${_supported_platforms_formatted}") +endif() + +# Check if Apple Silicon is supported +if(PLATFORM MATCHES "^(MAC_ARM64)$|^(MAC_CATALYST_ARM64)$|^(MAC_UNIVERSAL)$|^(MAC_CATALYST_UNIVERSAL)$" AND ${CMAKE_VERSION} VERSION_LESS "3.19.5") + message(FATAL_ERROR "Apple Silicon builds requires a minimum of CMake 3.19.5") +endif() + +# Touch the toolchain variable to suppress the "unused variable" warning. +# This happens if CMake is invoked with the same command line the second time. +if(CMAKE_TOOLCHAIN_FILE) +endif() + +# Fix for PThread library not in path +set(CMAKE_THREAD_LIBS_INIT "-lpthread") +set(CMAKE_HAVE_THREADS_LIBRARY 1) +set(CMAKE_USE_WIN32_THREADS_INIT 0) +set(CMAKE_USE_PTHREADS_INIT 1) + +# Specify named language support defaults. +if(NOT DEFINED NAMED_LANGUAGE_SUPPORT AND ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16") + set(NAMED_LANGUAGE_SUPPORT ON) + message(STATUS "[DEFAULTS] Using explicit named language support! E.g., enable_language(CXX) is needed in the project files.") +elseif(NOT DEFINED NAMED_LANGUAGE_SUPPORT AND ${CMAKE_VERSION} VERSION_LESS "3.16") + set(NAMED_LANGUAGE_SUPPORT OFF) + message(STATUS "[DEFAULTS] Disabling explicit named language support. Falling back to legacy behavior.") +elseif(DEFINED NAMED_LANGUAGE_SUPPORT AND ${CMAKE_VERSION} VERSION_LESS "3.16") + message(FATAL_ERROR "CMake named language support for OBJC and OBJCXX was added in CMake 3.16.") +endif() +set(NAMED_LANGUAGE_SUPPORT_INT ${NAMED_LANGUAGE_SUPPORT} CACHE BOOL + "Whether or not to enable explicit named language support" FORCE) + +# Specify the minimum version of the deployment target. +if(NOT DEFINED DEPLOYMENT_TARGET) + if (PLATFORM MATCHES "WATCHOS") + # Unless specified, SDK version 6.0 is used by default as minimum target version (watchOS). + set(DEPLOYMENT_TARGET "6.0") + elseif(PLATFORM STREQUAL "MAC") + # Unless specified, SDK version 11.0 (Big Sur) is used by default as the minimum target version (macOS on x86). + set(DEPLOYMENT_TARGET "11.0") + elseif(PLATFORM STREQUAL "VISIONOS" OR PLATFORM STREQUAL "SIMULATOR_VISIONOS" OR PLATFORM STREQUAL "VISIONOSCOMBINED") + # Unless specified, SDK version 1.0 is used by default as minimum target version (visionOS). + set(DEPLOYMENT_TARGET "1.0") + elseif(PLATFORM STREQUAL "MAC_ARM64") + # Unless specified, SDK version 11.0 (Big Sur) is used by default as the minimum target version (macOS on arm). + set(DEPLOYMENT_TARGET "11.0") + elseif(PLATFORM STREQUAL "MAC_UNIVERSAL") + # Unless specified, SDK version 11.0 (Big Sur) is used by default as minimum target version for universal builds. + set(DEPLOYMENT_TARGET "11.0") + elseif(PLATFORM STREQUAL "MAC_CATALYST" OR PLATFORM STREQUAL "MAC_CATALYST_ARM64" OR PLATFORM STREQUAL "MAC_CATALYST_UNIVERSAL") + # Unless specified, SDK version 13.1 is used by default as the minimum target version (mac catalyst minimum requirement). + set(DEPLOYMENT_TARGET "13.1") + else() + # Unless specified, SDK version 13.0 is used by default as the minimum target version (iOS, tvOS). + set(DEPLOYMENT_TARGET "13.0") + endif() + message(STATUS "[DEFAULTS] Using the default min-version since DEPLOYMENT_TARGET not provided!") +elseif(DEFINED DEPLOYMENT_TARGET AND PLATFORM MATCHES "^MAC_CATALYST" AND ${DEPLOYMENT_TARGET} VERSION_LESS "13.1") + message(FATAL_ERROR "Mac Catalyst builds requires a minimum deployment target of 13.1!") +endif() + +# Store the DEPLOYMENT_TARGET in the cache +set(DEPLOYMENT_TARGET "${DEPLOYMENT_TARGET}" CACHE INTERNAL "") + +# Handle the case where we are targeting iOS and a version above 10.3.4 (32-bit support dropped officially) +if(PLATFORM STREQUAL "OS" AND DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.3.4) + set(PLATFORM "OS64") + message(STATUS "Targeting minimum SDK version ${DEPLOYMENT_TARGET}. Dropping 32-bit support.") +elseif(PLATFORM STREQUAL "SIMULATOR" AND DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.3.4) + set(PLATFORM "SIMULATOR64") + message(STATUS "Targeting minimum SDK version ${DEPLOYMENT_TARGET}. Dropping 32-bit support.") +endif() + +set(PLATFORM_INT "${PLATFORM}") + +if(DEFINED ARCHS) + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") +endif() + +# Determine the platform name and architectures for use in xcodebuild commands +# from the specified PLATFORM_INT name. +if(PLATFORM_INT STREQUAL "OS") + set(SDK_NAME iphoneos) + if(NOT ARCHS) + set(ARCHS armv7 armv7s arm64) + set(APPLE_TARGET_TRIPLE_INT arm-apple-ios${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}) + endif() +elseif(PLATFORM_INT STREQUAL "OS64") + set(SDK_NAME iphoneos) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 10.0) + set(ARCHS arm64) # FIXME: Add arm64e when Apple has fixed the integration issues with it, libarclite_iphoneos.a is currently missing bitcode markers for example + else() + set(ARCHS arm64) + endif() + set(APPLE_TARGET_TRIPLE_INT arm64-apple-ios${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}) + endif() +elseif(PLATFORM_INT STREQUAL "OS64COMBINED") + set(SDK_NAME iphoneos) + if(MODERN_CMAKE) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 12.0) + set(ARCHS arm64 x86_64) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") + else() + set(ARCHS arm64 x86_64) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64") + endif() + set(APPLE_TARGET_TRIPLE_INT arm64-x86_64-apple-ios${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the OS64COMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR64COMBINED") + set(SDK_NAME iphonesimulator) + if(MODERN_CMAKE) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 12.0) + set(ARCHS arm64 x86_64) # FIXME: Add arm64e when Apple have fixed the integration issues with it, libarclite_iphoneos.a is currently missing bitcode markers for example + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") + else() + set(ARCHS arm64 x86_64) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64") + endif() + set(APPLE_TARGET_TRIPLE_INT aarch64-x86_64-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the SIMULATOR64COMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR") + set(SDK_NAME iphonesimulator) + if(NOT ARCHS) + set(ARCHS i386) + set(APPLE_TARGET_TRIPLE_INT i386-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() + message(DEPRECATION "SIMULATOR IS DEPRECATED. Consider using SIMULATOR64 instead.") +elseif(PLATFORM_INT STREQUAL "SIMULATOR64") + set(SDK_NAME iphonesimulator) + if(NOT ARCHS) + set(ARCHS x86_64) + set(APPLE_TARGET_TRIPLE_INT x86_64-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATORARM64") + set(SDK_NAME iphonesimulator) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "TVOS") + set(SDK_NAME appletvos) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-tvos${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}) + endif() +elseif (PLATFORM_INT STREQUAL "TVOSCOMBINED") + set(SDK_NAME appletvos) + if(MODERN_CMAKE) + if(NOT ARCHS) + set(ARCHS arm64 x86_64) + set(APPLE_TARGET_TRIPLE_INT arm64-x86_64-apple-tvos${DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=appletvos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=appletvsimulator*] "x86_64 arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=appletvos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=appletvsimulator*] "x86_64 arm64") + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the TVOSCOMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR_TVOS") + set(SDK_NAME appletvsimulator) + if(NOT ARCHS) + set(ARCHS x86_64) + set(APPLE_TARGET_TRIPLE_INT x86_64-apple-tvos${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_TVOS") + set(SDK_NAME appletvsimulator) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-tvos${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "WATCHOS") + set(SDK_NAME watchos) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 10.0) + set(ARCHS armv7k arm64_32) + set(APPLE_TARGET_TRIPLE_INT arm64_32-apple-watchos${DEPLOYMENT_TARGET}) + else() + set(ARCHS armv7k) + set(APPLE_TARGET_TRIPLE_INT arm-apple-watchos${DEPLOYMENT_TARGET}) + endif() + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}) + endif() +elseif(PLATFORM_INT STREQUAL "WATCHOSCOMBINED") + set(SDK_NAME watchos) + if(MODERN_CMAKE) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 10.0) + set(ARCHS armv7k arm64_32 x86_64) + set(APPLE_TARGET_TRIPLE_INT arm64_32-x86_64-apple-watchos${DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchos*] "armv7k arm64_32") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchsimulator*] "x86_64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchos*] "armv7k arm64_32") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchsimulator*] "x86_64") + else() + set(ARCHS armv7k i386) + set(APPLE_TARGET_TRIPLE_INT arm-i386-apple-watchos${DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchos*] "armv7k") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchsimulator*] "i386") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchos*] "armv7k") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchsimulator*] "i386") + endif() + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the WATCHOSCOMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOS") + set(SDK_NAME watchsimulator) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 10.0) + set(ARCHS x86_64) + set(APPLE_TARGET_TRIPLE_INT x86_64-apple-watchos${DEPLOYMENT_TARGET}-simulator) + else() + set(ARCHS i386) + set(APPLE_TARGET_TRIPLE_INT i386-apple-watchos${DEPLOYMENT_TARGET}-simulator) + endif() + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_WATCHOS") + set(SDK_NAME watchsimulator) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-watchos${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOSCOMBINED") + set(SDK_NAME watchsimulator) + if(MODERN_CMAKE) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 12.0) + set(ARCHS arm64 x86_64) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchos*] "") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchsimulator*] "arm64 x86_64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchos*] "") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchsimulator*] "arm64 x86_64") + set(APPLE_TARGET_TRIPLE_INT arm64_x86_64-apple-watchos${DEPLOYMENT_TARGET}-simulator) + else() + set(ARCHS arm64 i386) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchos*] "") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchsimulator*] "i386") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchos*] "") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchsimulator*] "i386") + set(APPLE_TARGET_TRIPLE_INT arm64_i386-apple-watchos${DEPLOYMENT_TARGET}-simulator) + endif() + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}-simulator) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the SIMULATOR_WATCHOSCOMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR_VISIONOS") + set(SDK_NAME xrsimulator) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-xros${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-xros${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "VISIONOS") + set(SDK_NAME xros) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-xros${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-xros${DEPLOYMENT_TARGET}) + endif() +elseif(PLATFORM_INT STREQUAL "VISIONOSCOMBINED") + set(SDK_NAME xros) + if(MODERN_CMAKE) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT arm64-apple-xros${DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=xros*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=xrsimulator*] "arm64") + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-xros${DEPLOYMENT_TARGET}) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the VISIONOSCOMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "MAC" OR PLATFORM_INT STREQUAL "MAC_CATALYST") + set(SDK_NAME macosx) + if(NOT ARCHS) + set(ARCHS x86_64) + endif() + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") + if(PLATFORM_INT STREQUAL "MAC") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-macosx${DEPLOYMENT_TARGET}) + elseif(PLATFORM_INT STREQUAL "MAC_CATALYST") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-macabi) + endif() +elseif(PLATFORM_INT MATCHES "^(MAC_ARM64)$|^(MAC_CATALYST_ARM64)$") + set(SDK_NAME macosx) + if(NOT ARCHS) + set(ARCHS arm64) + endif() + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") + if(PLATFORM_INT STREQUAL "MAC_ARM64") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-macosx${DEPLOYMENT_TARGET}) + elseif(PLATFORM_INT STREQUAL "MAC_CATALYST_ARM64") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-macabi) + endif() +elseif(PLATFORM_INT STREQUAL "MAC_UNIVERSAL") + set(SDK_NAME macosx) + if(NOT ARCHS) + set(ARCHS "x86_64;arm64") + endif() + # For universal builds, don't set target triple - let CMake handle it + # string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") + # set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-macosx${DEPLOYMENT_TARGET}) +elseif(PLATFORM_INT STREQUAL "MAC_CATALYST_UNIVERSAL") + set(SDK_NAME macosx) + if(NOT ARCHS) + set(ARCHS "x86_64;arm64") + endif() + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") + set(APPLE_TARGET_TRIPLE_INT apple-ios${DEPLOYMENT_TARGET}-macabi) +else() + message(FATAL_ERROR "Invalid PLATFORM: ${PLATFORM_INT}") +endif() + +string(REPLACE ";" " " ARCHS_SPACED "${ARCHS}") + +if(MODERN_CMAKE AND PLATFORM_INT MATCHES ".*COMBINED" AND NOT CMAKE_GENERATOR MATCHES "Xcode") + message(FATAL_ERROR "The COMBINED options only work with Xcode generator, -G Xcode") +endif() + +if(CMAKE_GENERATOR MATCHES "Xcode" AND PLATFORM_INT MATCHES "^MAC_CATALYST") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") + set(CMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS "macosx") + set(CMAKE_XCODE_ATTRIBUTE_SUPPORTS_MACCATALYST "YES") + if(NOT DEFINED MACOSX_DEPLOYMENT_TARGET) + set(CMAKE_XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "10.15") + else() + set(CMAKE_XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "${MACOSX_DEPLOYMENT_TARGET}") + endif() +elseif(CMAKE_GENERATOR MATCHES "Xcode") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") + set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "${DEPLOYMENT_TARGET}") + if(NOT PLATFORM_INT MATCHES ".*COMBINED") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=${SDK_NAME}*] "${ARCHS_SPACED}") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=${SDK_NAME}*] "${ARCHS_SPACED}") + endif() +endif() + +# If the user did not specify the SDK root to use, then query xcodebuild for it. +if(DEFINED CMAKE_OSX_SYSROOT_INT) + # Environment variables are always preserved. + set(ENV{_CMAKE_OSX_SYSROOT_INT} "${CMAKE_OSX_SYSROOT_INT}") +elseif(DEFINED ENV{_CMAKE_OSX_SYSROOT_INT}) + set(CMAKE_OSX_SYSROOT_INT "$ENV{_CMAKE_OSX_SYSROOT_INT}") +elseif(NOT DEFINED CMAKE_OSX_SYSROOT_INT) + execute_process(COMMAND ${XCODEBUILD_EXECUTABLE} -version -sdk ${SDK_NAME} Path + OUTPUT_VARIABLE CMAKE_OSX_SYSROOT_INT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +if (NOT DEFINED CMAKE_OSX_SYSROOT_INT AND NOT DEFINED CMAKE_OSX_SYSROOT) + message(SEND_ERROR "Please make sure that Xcode is installed and that the toolchain" + "is pointing to the correct path. Please run:" + "sudo xcode-select -s /Applications/Xcode.app/Contents/Developer" + "and see if that fixes the problem for you.") + message(FATAL_ERROR "Invalid CMAKE_OSX_SYSROOT: ${CMAKE_OSX_SYSROOT} " + "does not exist.") +elseif(DEFINED CMAKE_OSX_SYSROOT_INT) + set(CMAKE_OSX_SYSROOT_INT "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") + # Specify the location or name of the platform SDK to be used in CMAKE_OSX_SYSROOT. + set(CMAKE_OSX_SYSROOT "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") +endif() + +# Use bitcode or not +if(NOT DEFINED ENABLE_BITCODE) + message(STATUS "[DEFAULTS] Disabling bitcode support by default. ENABLE_BITCODE not provided for override!") + set(ENABLE_BITCODE OFF) +endif() +set(ENABLE_BITCODE_INT ${ENABLE_BITCODE} CACHE BOOL + "Whether or not to enable bitcode" FORCE) +# Use ARC or not +if(NOT DEFINED ENABLE_ARC) + # Unless specified, enable ARC support by default + set(ENABLE_ARC ON) + message(STATUS "[DEFAULTS] Enabling ARC support by default. ENABLE_ARC not provided!") +endif() +set(ENABLE_ARC_INT ${ENABLE_ARC} CACHE BOOL "Whether or not to enable ARC" FORCE) +# Use hidden visibility or not +if(NOT DEFINED ENABLE_VISIBILITY) + # Unless specified, disable symbols visibility by default + set(ENABLE_VISIBILITY OFF) + message(STATUS "[DEFAULTS] Hiding symbols visibility by default. ENABLE_VISIBILITY not provided!") +endif() +set(ENABLE_VISIBILITY_INT ${ENABLE_VISIBILITY} CACHE BOOL "Whether or not to hide symbols from the dynamic linker (-fvisibility=hidden)" FORCE) +# Set strict compiler checks or not +if(NOT DEFINED ENABLE_STRICT_TRY_COMPILE) + # Unless specified, disable strict try_compile() + set(ENABLE_STRICT_TRY_COMPILE OFF) + message(STATUS "[DEFAULTS] Using NON-strict compiler checks by default. ENABLE_STRICT_TRY_COMPILE not provided!") +endif() +set(ENABLE_STRICT_TRY_COMPILE_INT ${ENABLE_STRICT_TRY_COMPILE} CACHE BOOL + "Whether or not to use strict compiler checks" FORCE) + +# Get the SDK version information. +if(DEFINED SDK_VERSION) + # Environment variables are always preserved. + set(ENV{_SDK_VERSION} "${SDK_VERSION}") +elseif(DEFINED ENV{_SDK_VERSION}) + set(SDK_VERSION "$ENV{_SDK_VERSION}") +elseif(NOT DEFINED SDK_VERSION) + execute_process(COMMAND ${XCODEBUILD_EXECUTABLE} -sdk ${CMAKE_OSX_SYSROOT_INT} -version SDKVersion + OUTPUT_VARIABLE SDK_VERSION + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +# Find the Developer root for the specific iOS platform being compiled for +# from CMAKE_OSX_SYSROOT. Should be ../../ from SDK specified in +# CMAKE_OSX_SYSROOT. There does not appear to be a direct way to obtain +# this information from xcrun or xcodebuild. +if (NOT DEFINED CMAKE_DEVELOPER_ROOT AND NOT CMAKE_GENERATOR MATCHES "Xcode") + get_filename_component(PLATFORM_SDK_DIR ${CMAKE_OSX_SYSROOT_INT} PATH) + get_filename_component(CMAKE_DEVELOPER_ROOT ${PLATFORM_SDK_DIR} PATH) + if (NOT EXISTS "${CMAKE_DEVELOPER_ROOT}") + message(FATAL_ERROR "Invalid CMAKE_DEVELOPER_ROOT: ${CMAKE_DEVELOPER_ROOT} does not exist.") + endif() +endif() + +# Find the C & C++ compilers for the specified SDK. +if(DEFINED CMAKE_C_COMPILER) + # Environment variables are always preserved. + set(ENV{_CMAKE_C_COMPILER} "${CMAKE_C_COMPILER}") +elseif(DEFINED ENV{_CMAKE_C_COMPILER}) + set(CMAKE_C_COMPILER "$ENV{_CMAKE_C_COMPILER}") + set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +elseif(NOT DEFINED CMAKE_C_COMPILER) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find clang + OUTPUT_VARIABLE CMAKE_C_COMPILER + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +endif() +if(DEFINED CMAKE_CXX_COMPILER) + # Environment variables are always preserved. + set(ENV{_CMAKE_CXX_COMPILER} "${CMAKE_CXX_COMPILER}") +elseif(DEFINED ENV{_CMAKE_CXX_COMPILER}) + set(CMAKE_CXX_COMPILER "$ENV{_CMAKE_CXX_COMPILER}") +elseif(NOT DEFINED CMAKE_CXX_COMPILER) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find clang++ + OUTPUT_VARIABLE CMAKE_CXX_COMPILER + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() +# Find (Apple's) libtool. +if(DEFINED BUILD_LIBTOOL) + # Environment variables are always preserved. + set(ENV{_BUILD_LIBTOOL} "${BUILD_LIBTOOL}") +elseif(DEFINED ENV{_BUILD_LIBTOOL}) + set(BUILD_LIBTOOL "$ENV{_BUILD_LIBTOOL}") +elseif(NOT DEFINED BUILD_LIBTOOL) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find libtool + OUTPUT_VARIABLE BUILD_LIBTOOL + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() +# Find the toolchain's provided install_name_tool if none is found on the host +if(DEFINED CMAKE_INSTALL_NAME_TOOL) + # Environment variables are always preserved. + set(ENV{_CMAKE_INSTALL_NAME_TOOL} "${CMAKE_INSTALL_NAME_TOOL}") +elseif(DEFINED ENV{_CMAKE_INSTALL_NAME_TOOL}) + set(CMAKE_INSTALL_NAME_TOOL "$ENV{_CMAKE_INSTALL_NAME_TOOL}") +elseif(NOT DEFINED CMAKE_INSTALL_NAME_TOOL) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find install_name_tool + OUTPUT_VARIABLE CMAKE_INSTALL_NAME_TOOL_INT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(CMAKE_INSTALL_NAME_TOOL ${CMAKE_INSTALL_NAME_TOOL_INT} CACHE INTERNAL "") +endif() + +# Configure libtool to be used instead of ar + ranlib to build static libraries. +# This is required on Xcode 7+, but should also work on previous versions of +# Xcode. +get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) +foreach(lang ${languages}) + set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "${BUILD_LIBTOOL} -static -o " CACHE INTERNAL "") +endforeach() + +# CMake 3.14+ support building for iOS, watchOS, and tvOS out of the box. +if(MODERN_CMAKE) + if(SDK_NAME MATCHES "iphone") + set(CMAKE_SYSTEM_NAME iOS) + elseif(SDK_NAME MATCHES "xros") + set(CMAKE_SYSTEM_NAME visionOS) + elseif(SDK_NAME MATCHES "xrsimulator") + set(CMAKE_SYSTEM_NAME visionOS) + elseif(SDK_NAME MATCHES "macosx") + set(CMAKE_SYSTEM_NAME Darwin) + elseif(SDK_NAME MATCHES "appletv") + set(CMAKE_SYSTEM_NAME tvOS) + elseif(SDK_NAME MATCHES "watch") + set(CMAKE_SYSTEM_NAME watchOS) + endif() + # Provide flags for a combined FAT library build on newer CMake versions + if(PLATFORM_INT MATCHES ".*COMBINED") + set(CMAKE_IOS_INSTALL_COMBINED YES) + if(CMAKE_GENERATOR MATCHES "Xcode") + # Set the SDKROOT Xcode properties to a Xcode-friendly value (the SDK_NAME, E.g, iphoneos) + # This way, Xcode will automatically switch between the simulator and device SDK when building. + set(CMAKE_XCODE_ATTRIBUTE_SDKROOT "${SDK_NAME}") + # Force to not build just one ARCH, but all! + set(CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH "NO") + endif() + endif() +elseif(NOT DEFINED CMAKE_SYSTEM_NAME AND ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.10") + # Legacy code path prior to CMake 3.14 or fallback if no CMAKE_SYSTEM_NAME specified + set(CMAKE_SYSTEM_NAME iOS) +elseif(NOT DEFINED CMAKE_SYSTEM_NAME) + # Legacy code path before CMake 3.14 or fallback if no CMAKE_SYSTEM_NAME specified + set(CMAKE_SYSTEM_NAME Darwin) +endif() +# Standard settings. +set(CMAKE_SYSTEM_VERSION ${SDK_VERSION} CACHE INTERNAL "") +set(UNIX ON CACHE BOOL "") +set(APPLE ON CACHE BOOL "") +if(PLATFORM STREQUAL "MAC" OR PLATFORM STREQUAL "MAC_ARM64" OR PLATFORM STREQUAL "MAC_UNIVERSAL") + set(IOS OFF CACHE BOOL "") + set(MACOS ON CACHE BOOL "") +elseif(PLATFORM STREQUAL "MAC_CATALYST" OR PLATFORM STREQUAL "MAC_CATALYST_ARM64" OR PLATFORM STREQUAL "MAC_CATALYST_UNIVERSAL") + set(IOS ON CACHE BOOL "") + set(MACOS ON CACHE BOOL "") +elseif(PLATFORM STREQUAL "VISIONOS" OR PLATFORM STREQUAL "SIMULATOR_VISIONOS" OR PLATFORM STREQUAL "VISIONOSCOMBINED") + set(IOS OFF CACHE BOOL "") + set(VISIONOS ON CACHE BOOL "") +else() + set(IOS ON CACHE BOOL "") +endif() +# Set the architectures for which to build. +set(CMAKE_OSX_ARCHITECTURES ${ARCHS} CACHE INTERNAL "") +# Change the type of target generated for try_compile() so it'll work when cross-compiling, weak compiler checks +if(NOT ENABLE_STRICT_TRY_COMPILE_INT) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +endif() +# All iOS/Darwin specific settings - some may be redundant. +if (NOT DEFINED CMAKE_MACOSX_BUNDLE) + set(CMAKE_MACOSX_BUNDLE YES) +endif() +set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO") +set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO") +set(CMAKE_SHARED_LIBRARY_PREFIX "lib") +set(CMAKE_SHARED_LIBRARY_SUFFIX ".dylib") +set(CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES ".tbd" ".so") +set(CMAKE_SHARED_MODULE_PREFIX "lib") +set(CMAKE_SHARED_MODULE_SUFFIX ".so") +set(CMAKE_C_COMPILER_ABI ELF) +set(CMAKE_CXX_COMPILER_ABI ELF) +set(CMAKE_C_HAS_ISYSROOT 1) +set(CMAKE_CXX_HAS_ISYSROOT 1) +set(CMAKE_MODULE_EXISTS 1) +set(CMAKE_DL_LIBS "") +set(CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ") +set(CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ") +set(CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}") +set(CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") + +if(ARCHS MATCHES "((^|;|, )(arm64|arm64e|x86_64))+") + set(CMAKE_C_SIZEOF_DATA_PTR 8) + set(CMAKE_CXX_SIZEOF_DATA_PTR 8) + if(ARCHS MATCHES "((^|;|, )(arm64|arm64e))+") + set(CMAKE_SYSTEM_PROCESSOR "aarch64") + else() + set(CMAKE_SYSTEM_PROCESSOR "x86_64") + endif() +else() + set(CMAKE_C_SIZEOF_DATA_PTR 4) + set(CMAKE_CXX_SIZEOF_DATA_PTR 4) + set(CMAKE_SYSTEM_PROCESSOR "arm") +endif() + +# Note that only Xcode 7+ supports the newer more specific: +# -m${SDK_NAME}-version-min flags, older versions of Xcode use: +# -m(ios/ios-simulator)-version-min instead. +if(${CMAKE_VERSION} VERSION_LESS "3.11") + if(PLATFORM_INT STREQUAL "OS" OR PLATFORM_INT STREQUAL "OS64") + if(XCODE_VERSION_INT VERSION_LESS 7.0) + set(SDK_NAME_VERSION_FLAGS + "-mios-version-min=${DEPLOYMENT_TARGET}") + else() + # Xcode 7.0+ uses flags we can build directly from SDK_NAME. + set(SDK_NAME_VERSION_FLAGS + "-m${SDK_NAME}-version-min=${DEPLOYMENT_TARGET}") + endif() + elseif(PLATFORM_INT STREQUAL "TVOS") + set(SDK_NAME_VERSION_FLAGS + "-mtvos-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "SIMULATOR_TVOS") + set(SDK_NAME_VERSION_FLAGS + "-mtvos-simulator-version-min=${DEPLOYMENT_TARGET}") +elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_TVOS") + set(SDK_NAME_VERSION_FLAGS + "-mtvos-simulator-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "WATCHOS") + set(SDK_NAME_VERSION_FLAGS + "-mwatchos-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOS") + set(SDK_NAME_VERSION_FLAGS + "-mwatchos-simulator-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_WATCHOS") + set(SDK_NAME_VERSION_FLAGS + "-mwatchos-simulator-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "MAC") + set(SDK_NAME_VERSION_FLAGS + "-mmacosx-version-min=${DEPLOYMENT_TARGET}") + else() + # SIMULATOR or SIMULATOR64 both use -mios-simulator-version-min. + set(SDK_NAME_VERSION_FLAGS + "-mios-simulator-version-min=${DEPLOYMENT_TARGET}") + endif() +elseif(NOT PLATFORM_INT MATCHES "^MAC_CATALYST") + # Newer versions of CMake sets the version min flags correctly, skip this for Mac Catalyst targets + set(CMAKE_OSX_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET} CACHE INTERNAL "Minimum OS X deployment version") +endif() + +if(DEFINED APPLE_TARGET_TRIPLE_INT) + set(APPLE_TARGET_TRIPLE ${APPLE_TARGET_TRIPLE_INT} CACHE INTERNAL "") + set(CMAKE_C_COMPILER_TARGET ${APPLE_TARGET_TRIPLE}) + set(CMAKE_CXX_COMPILER_TARGET ${APPLE_TARGET_TRIPLE}) + set(CMAKE_ASM_COMPILER_TARGET ${APPLE_TARGET_TRIPLE}) +endif() + +if(PLATFORM_INT MATCHES "^MAC_CATALYST") + set(C_TARGET_FLAGS "-isystem ${CMAKE_OSX_SYSROOT_INT}/System/iOSSupport/usr/include -iframework ${CMAKE_OSX_SYSROOT_INT}/System/iOSSupport/System/Library/Frameworks") +endif() + +if(ENABLE_BITCODE_INT) + set(BITCODE "-fembed-bitcode") + set(CMAKE_XCODE_ATTRIBUTE_BITCODE_GENERATION_MODE "bitcode") + set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "YES") +else() + set(BITCODE "") + set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "NO") +endif() + +if(ENABLE_ARC_INT) + set(FOBJC_ARC "-fobjc-arc") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "YES") +else() + set(FOBJC_ARC "-fno-objc-arc") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "NO") +endif() + +if(NAMED_LANGUAGE_SUPPORT_INT) + set(OBJC_VARS "-fobjc-abi-version=2 -DOBJC_OLD_DISPATCH_PROTOTYPES=0") + set(OBJC_LEGACY_VARS "") +else() + set(OBJC_VARS "") + set(OBJC_LEGACY_VARS "-fobjc-abi-version=2 -DOBJC_OLD_DISPATCH_PROTOTYPES=0") +endif() + +if(NOT ENABLE_VISIBILITY_INT) + foreach(lang ${languages}) + set(CMAKE_${lang}_VISIBILITY_PRESET "hidden" CACHE INTERNAL "") + endforeach() + set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "YES") + set(VISIBILITY "-fvisibility=hidden -fvisibility-inlines-hidden") +else() + foreach(lang ${languages}) + set(CMAKE_${lang}_VISIBILITY_PRESET "default" CACHE INTERNAL "") + endforeach() + set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "NO") + set(VISIBILITY "-fvisibility=default") +endif() + +if(DEFINED APPLE_TARGET_TRIPLE) + set(APPLE_TARGET_TRIPLE_FLAG "-target ${APPLE_TARGET_TRIPLE}") +endif() + +#Check if Xcode generator is used since that will handle these flags automagically +if(CMAKE_GENERATOR MATCHES "Xcode") + message(STATUS "Not setting any manual command-line buildflags, since Xcode is selected as the generator. Modifying the Xcode build-settings directly instead.") +else() + set(CMAKE_C_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${OBJC_LEGACY_VARS} ${BITCODE} ${VISIBILITY} ${CMAKE_C_FLAGS}" CACHE INTERNAL + "Flags used by the compiler during all C build types.") + set(CMAKE_C_FLAGS_DEBUG "-O0 -g ${CMAKE_C_FLAGS_DEBUG}") + set(CMAKE_C_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_C_FLAGS_MINSIZEREL}") + set(CMAKE_C_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_C_FLAGS_RELWITHDEBINFO}") + set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_C_FLAGS_RELEASE}") + set(CMAKE_CXX_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${OBJC_LEGACY_VARS} ${BITCODE} ${VISIBILITY} ${CMAKE_CXX_FLAGS}" CACHE INTERNAL + "Flags used by the compiler during all CXX build types.") + set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g ${CMAKE_CXX_FLAGS_DEBUG}") + set(CMAKE_CXX_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_CXX_FLAGS_MINSIZEREL}") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_CXX_FLAGS_RELEASE}") + if(NAMED_LANGUAGE_SUPPORT_INT) + set(CMAKE_OBJC_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${BITCODE} ${VISIBILITY} ${FOBJC_ARC} ${OBJC_VARS} ${CMAKE_OBJC_FLAGS}" CACHE INTERNAL + "Flags used by the compiler during all OBJC build types.") + set(CMAKE_OBJC_FLAGS_DEBUG "-O0 -g ${CMAKE_OBJC_FLAGS_DEBUG}") + set(CMAKE_OBJC_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_OBJC_FLAGS_MINSIZEREL}") + set(CMAKE_OBJC_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_OBJC_FLAGS_RELWITHDEBINFO}") + set(CMAKE_OBJC_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_OBJC_FLAGS_RELEASE}") + set(CMAKE_OBJCXX_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${BITCODE} ${VISIBILITY} ${FOBJC_ARC} ${OBJC_VARS} ${CMAKE_OBJCXX_FLAGS}" CACHE INTERNAL + "Flags used by the compiler during all OBJCXX build types.") + set(CMAKE_OBJCXX_FLAGS_DEBUG "-O0 -g ${CMAKE_OBJCXX_FLAGS_DEBUG}") + set(CMAKE_OBJCXX_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_OBJCXX_FLAGS_MINSIZEREL}") + set(CMAKE_OBJCXX_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_OBJCXX_FLAGS_RELWITHDEBINFO}") + set(CMAKE_OBJCXX_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_OBJCXX_FLAGS_RELEASE}") + endif() + set(CMAKE_C_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}" CACHE INTERNAL + "Flags used by the compiler for all C link types.") + set(CMAKE_CXX_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}" CACHE INTERNAL + "Flags used by the compiler for all CXX link types.") + if(NAMED_LANGUAGE_SUPPORT_INT) + set(CMAKE_OBJC_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_OBJC_LINK_FLAGS}" CACHE INTERNAL + "Flags used by the compiler for all OBJC link types.") + set(CMAKE_OBJCXX_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_OBJCXX_LINK_FLAGS}" CACHE INTERNAL + "Flags used by the compiler for all OBJCXX link types.") + endif() + set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp" CACHE INTERNAL + "Flags used by the compiler for all ASM build types.") +endif() + +## Print status messages to inform of the current state +message(STATUS "Configuring ${SDK_NAME} build for platform: ${PLATFORM_INT}, architecture(s): ${ARCHS}") +message(STATUS "Using SDK: ${CMAKE_OSX_SYSROOT_INT}") +message(STATUS "Using C compiler: ${CMAKE_C_COMPILER}") +message(STATUS "Using CXX compiler: ${CMAKE_CXX_COMPILER}") +message(STATUS "Using libtool: ${BUILD_LIBTOOL}") +message(STATUS "Using install name tool: ${CMAKE_INSTALL_NAME_TOOL}") +if(DEFINED APPLE_TARGET_TRIPLE) + message(STATUS "Autoconf target triple: ${APPLE_TARGET_TRIPLE}") +endif() +message(STATUS "Using minimum deployment version: ${DEPLOYMENT_TARGET}" + " (SDK version: ${SDK_VERSION})") +if(MODERN_CMAKE) + message(STATUS "Merging integrated CMake 3.14+ iOS,tvOS,watchOS,macOS toolchain(s) with this toolchain!") + if(PLATFORM_INT MATCHES ".*COMBINED") + message(STATUS "Will combine built (static) artifacts into FAT lib...") + endif() +endif() +if(CMAKE_GENERATOR MATCHES "Xcode") + message(STATUS "Using Xcode version: ${XCODE_VERSION_INT}") +endif() +message(STATUS "CMake version: ${CMAKE_VERSION}") +if(DEFINED SDK_NAME_VERSION_FLAGS) + message(STATUS "Using version flags: ${SDK_NAME_VERSION_FLAGS}") +endif() +message(STATUS "Using a data_ptr size of: ${CMAKE_CXX_SIZEOF_DATA_PTR}") +if(ENABLE_BITCODE_INT) + message(STATUS "Bitcode: Enabled") +else() + message(STATUS "Bitcode: Disabled") +endif() + +if(ENABLE_ARC_INT) + message(STATUS "ARC: Enabled") +else() + message(STATUS "ARC: Disabled") +endif() + +if(ENABLE_VISIBILITY_INT) + message(STATUS "Hiding symbols: Disabled") +else() + message(STATUS "Hiding symbols: Enabled") +endif() + +# Set global properties +set_property(GLOBAL PROPERTY PLATFORM "${PLATFORM}") +set_property(GLOBAL PROPERTY APPLE_TARGET_TRIPLE "${APPLE_TARGET_TRIPLE_INT}") +set_property(GLOBAL PROPERTY SDK_VERSION "${SDK_VERSION}") +set_property(GLOBAL PROPERTY XCODE_VERSION "${XCODE_VERSION_INT}") +set_property(GLOBAL PROPERTY OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}") + +# Export configurable variables for the try_compile() command. +set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES + PLATFORM + XCODE_VERSION_INT + SDK_VERSION + NAMED_LANGUAGE_SUPPORT + DEPLOYMENT_TARGET + CMAKE_DEVELOPER_ROOT + CMAKE_OSX_SYSROOT_INT + ENABLE_BITCODE + ENABLE_ARC + CMAKE_ASM_COMPILER + CMAKE_C_COMPILER + CMAKE_C_COMPILER_TARGET + CMAKE_CXX_COMPILER + CMAKE_CXX_COMPILER_TARGET + BUILD_LIBTOOL + CMAKE_INSTALL_NAME_TOOL + CMAKE_C_FLAGS + CMAKE_C_DEBUG + CMAKE_C_MINSIZEREL + CMAKE_C_RELWITHDEBINFO + CMAKE_C_RELEASE + CMAKE_CXX_FLAGS + CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_CXX_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS_RELEASE + CMAKE_C_LINK_FLAGS + CMAKE_CXX_LINK_FLAGS + CMAKE_ASM_FLAGS +) + +if(NAMED_LANGUAGE_SUPPORT_INT) + list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES + CMAKE_OBJC_FLAGS + CMAKE_OBJC_DEBUG + CMAKE_OBJC_MINSIZEREL + CMAKE_OBJC_RELWITHDEBINFO + CMAKE_OBJC_RELEASE + CMAKE_OBJCXX_FLAGS + CMAKE_OBJCXX_DEBUG + CMAKE_OBJCXX_MINSIZEREL + CMAKE_OBJCXX_RELWITHDEBINFO + CMAKE_OBJCXX_RELEASE + CMAKE_OBJC_LINK_FLAGS + CMAKE_OBJCXX_LINK_FLAGS + ) +endif() + +set(CMAKE_PLATFORM_HAS_INSTALLNAME 1) +set(CMAKE_SHARED_LINKER_FLAGS "-rpath @executable_path/Frameworks -rpath @loader_path/Frameworks") +set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -Wl,-headerpad_max_install_names") +set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -Wl,-headerpad_max_install_names") +set(CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,") +set(CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,") +set(CMAKE_FIND_LIBRARY_SUFFIXES ".tbd" ".dylib" ".so" ".a") +set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-install_name") + +# Set the find root to the SDK developer roots. +# Note: CMAKE_FIND_ROOT_PATH is only useful when cross-compiling. Thus, do not set on macOS builds. +if(NOT PLATFORM_INT MATCHES "^MAC.*$") + list(APPEND CMAKE_FIND_ROOT_PATH "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") + set(CMAKE_IGNORE_PATH "/System/Library/Frameworks;/usr/local/lib;/opt/homebrew" CACHE INTERNAL "") +endif() + +# Default to searching for frameworks first. +IF(NOT DEFINED CMAKE_FIND_FRAMEWORK) + set(CMAKE_FIND_FRAMEWORK FIRST) +ENDIF(NOT DEFINED CMAKE_FIND_FRAMEWORK) + +# Set up the default search directories for frameworks. +if(PLATFORM_INT MATCHES "^MAC_CATALYST") + set(CMAKE_FRAMEWORK_PATH + ${CMAKE_DEVELOPER_ROOT}/Library/PrivateFrameworks + ${CMAKE_OSX_SYSROOT_INT}/System/Library/Frameworks + ${CMAKE_OSX_SYSROOT_INT}/System/iOSSupport/System/Library/Frameworks + ${CMAKE_FRAMEWORK_PATH} CACHE INTERNAL "") +else() + set(CMAKE_FRAMEWORK_PATH + ${CMAKE_DEVELOPER_ROOT}/Library/PrivateFrameworks + ${CMAKE_OSX_SYSROOT_INT}/System/Library/Frameworks + ${CMAKE_FRAMEWORK_PATH} CACHE INTERNAL "") +endif() + +# By default, search both the specified iOS SDK and the remainder of the host filesystem. +if(NOT CMAKE_FIND_ROOT_PATH_MODE_PROGRAM) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH CACHE INTERNAL "") +endif() +if(NOT CMAKE_FIND_ROOT_PATH_MODE_LIBRARY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH CACHE INTERNAL "") +endif() +if(NOT CMAKE_FIND_ROOT_PATH_MODE_INCLUDE) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH CACHE INTERNAL "") +endif() +if(NOT CMAKE_FIND_ROOT_PATH_MODE_PACKAGE) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH CACHE INTERNAL "") +endif() + +# +# Some helper-macros below to simplify and beautify the CMakeFile +# + +# This little macro lets you set any Xcode specific property. +macro(set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE XCODE_RELVERSION) + set(XCODE_RELVERSION_I "${XCODE_RELVERSION}") + if(XCODE_RELVERSION_I STREQUAL "All") + set_property(TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} "${XCODE_VALUE}") + else() + set_property(TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY}[variant=${XCODE_RELVERSION_I}] "${XCODE_VALUE}") + endif() +endmacro(set_xcode_property) + +# This macro lets you find executable programs on the host system. +macro(find_host_package) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE NEVER) + set(_TOOLCHAIN_IOS ${IOS}) + set(IOS OFF) + find_package(${ARGN}) + set(IOS ${_TOOLCHAIN_IOS}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH) +endmacro(find_host_package) From dec74b7ebc2b965adc72081f81579db93eaae538 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 21 Feb 2026 23:39:48 +0000 Subject: [PATCH 10/54] license --- .ci/ios/build.sh | 3 +++ .ci/ios/ios-toolchain.cmake | 3 +++ 2 files changed, 6 insertions(+) mode change 100644 => 100755 .ci/ios/build.sh diff --git a/.ci/ios/build.sh b/.ci/ios/build.sh old mode 100644 new mode 100755 index f179a6c929..24837e5408 --- a/.ci/ios/build.sh +++ b/.ci/ios/build.sh @@ -1,5 +1,8 @@ #!/bin/sh -ex +# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + WORK_DIR="$PWD" if [ -z "$NPROC" ]; then NPROC="$(nproc)" diff --git a/.ci/ios/ios-toolchain.cmake b/.ci/ios/ios-toolchain.cmake index 3ee3940a38..b0defa25aa 100644 --- a/.ci/ios/ios-toolchain.cmake +++ b/.ci/ios/ios-toolchain.cmake @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # This file is part of the ios-cmake project. It was retrieved from # https://github.com/leetal/ios-cmake.git, which is a fork of # https://github.com/gerstrong/ios-cmake.git, which is a fork of From deaa54e123a749c08660fd53efd184414f1f0851 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 21 Feb 2026 23:40:46 +0000 Subject: [PATCH 11/54] fx --- .ci/ios/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/ios/build.sh b/.ci/ios/build.sh index 24837e5408..bb905c1894 100755 --- a/.ci/ios/build.sh +++ b/.ci/ios/build.sh @@ -9,7 +9,7 @@ if [ -z "$NPROC" ]; then fi cmake -G Xcode -B build \ - -DCMAKE_TOOLCHAIN_FILE="$WORK_DIR/ios-toolchain.cmake" \ + -DCMAKE_TOOLCHAIN_FILE="$WORK_DIR/.ci/ios/ios-toolchain.cmake" \ -DPLATFORM=OS64 \ -DENABLE_LIBUSB=OFF \ -DENABLE_UPDATE_CHECKER=OFF \ From c1b4112aabb3b617a579c32bd12d6f91c60262df Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 22 Feb 2026 02:53:02 +0000 Subject: [PATCH 12/54] fx --- .ci/ios/build.sh | 3 +++ .../cmake-modules/DetectArchitecture.cmake | 19 ++++++++++++------- externals/ffmpeg/CMakeLists.txt | 4 ++-- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/.ci/ios/build.sh b/.ci/ios/build.sh index bb905c1894..64c52733e6 100755 --- a/.ci/ios/build.sh +++ b/.ci/ios/build.sh @@ -8,9 +8,12 @@ if [ -z "$NPROC" ]; then NPROC="$(nproc)" fi +[ ! -z "$IOS_SDK" ] + cmake -G Xcode -B build \ -DCMAKE_TOOLCHAIN_FILE="$WORK_DIR/.ci/ios/ios-toolchain.cmake" \ -DPLATFORM=OS64 \ + -DCOCOA_LIBRARY="$IOS_SDK/System/Library/Frameworks/Cocoa.framework" \ -DENABLE_LIBUSB=OFF \ -DENABLE_UPDATE_CHECKER=OFF \ -DENABLE_QT=OFF \ diff --git a/externals/cmake-modules/DetectArchitecture.cmake b/externals/cmake-modules/DetectArchitecture.cmake index 105963c8c2..a2f78b86de 100644 --- a/externals/cmake-modules/DetectArchitecture.cmake +++ b/externals/cmake-modules/DetectArchitecture.cmake @@ -38,13 +38,18 @@ This file is based off of Yuzu and Dynarmic. if (CMAKE_OSX_ARCHITECTURES) set(MULTIARCH_BUILD 1) set(ARCHITECTURE "${CMAKE_OSX_ARCHITECTURES}") - - # hope and pray the architecture names match - foreach(ARCH IN ${CMAKE_OSX_ARCHITECTURES}) - set(ARCHITECTURE_${ARCH} 1 PARENT_SCOPE) - add_definitions(-DARCHITECTURE_${ARCH}=1) - endforeach() - + if (IOS) + # TODO: Right... the toolchain file won't properly accomodate OSX_ARCHITECTURE + # they aren't defining it as a list properly I assume? + set(ARCHITECTURE_arm64 1 PARENT_SCOPE) + add_definitions(-DARCHITECTURE_arm64=1) + else () + # hope and pray the architecture names match + foreach(ARCH IN ${CMAKE_OSX_ARCHITECTURES}) + set(ARCHITECTURE_${ARCH} 1 PARENT_SCOPE) + add_definitions(-DARCHITECTURE_${ARCH}=1) + endforeach() + endif() return() endif() diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index 3140f8e545..328cf5ec21 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -11,9 +11,9 @@ set(FFmpeg_HWACCEL_FLAGS) set(FFmpeg_HWACCEL_INCLUDE_DIRS) set(FFmpeg_HWACCEL_LDFLAGS) -if (UNIX AND NOT ANDROID) +if (UNIX AND NOT ANDROID AND NOT IOS) find_package(PkgConfig REQUIRED) - if (NOT ANDROID) + if (NOT ANDROID AND NOT IOS) pkg_check_modules(LIBVA libva) pkg_check_modules(CUDA cuda) pkg_check_modules(FFNVCODEC ffnvcodec) From a8e1a12d2d7813b6a37491bb87072575519b234e Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 22 Feb 2026 03:18:09 +0000 Subject: [PATCH 13/54] fix ffmpeg --- CMakeLists.txt | 7 ++++++- externals/ffmpeg/CMakeLists.txt | 21 +++++++++++++++++---- src/ios/CMakeLists.txt | 2 +- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 42717c496d..cb4a135d17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -486,7 +486,12 @@ endfunction() # ============================================= if (APPLE) - foreach(fw Carbon Metal Cocoa IOKit CoreVideo CoreMedia) + set(_libs Carbon Metal Cocoa IOKit CoreVideo CoreMedia) + if (IOS) + list(APPEND _libs objc) + endif() + + foreach(fw ${_libs}) find_library(${fw}_LIBRARY ${fw} REQUIRED) list(APPEND PLATFORM_LIBRARIES ${${fw}_LIBRARY}) endforeach() diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index 328cf5ec21..7428c44695 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -182,6 +182,10 @@ else() find_program(BASH_PROGRAM bash REQUIRED) set(FFmpeg_CROSS_COMPILE_FLAGS "") + # `configure` parameters builds only exactly what yuzu needs from FFmpeg + # `--disable-vdpau` is needed to avoid linking issues + set(FFmpeg_CC ${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER}) + set(FFmpeg_CXX ${CMAKE_CXX_COMPILER_LAUNCHER} ${CMAKE_CXX_COMPILER}) if (ANDROID) string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" FFmpeg_HOST_SYSTEM_NAME) set(TOOLCHAIN "${ANDROID_NDK}/toolchains/llvm/prebuilt/${FFmpeg_HOST_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}") @@ -197,12 +201,21 @@ else() --extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld" --extra-ldflags="-nostdlib" ) + elseif(IOS) + execute_process(COMMAND xcrun --sdk iphoneos --show-sdk-path OUTPUT_VARIABLE SYSROOT) + set(FFmpeg_CC "xcrun --sdk iphoneos clang -arch arm64") + set(FFmpeg_CXX "xcrun --sdk iphoneos clang++ -arch arm64") + list(APPEND FFmpeg_CROSS_COMPILE_FLAGS + --arch=arm64 + --enable-cross-compile + --sysroot=${SYSROOT} + --target-os=darwin + --extra-ldflags="-miphoneos-version-min=16.0" + --install-name-dir="@rpath" + --disable-audiotoolbox + ) endif() - # `configure` parameters builds only exactly what yuzu needs from FFmpeg - # `--disable-vdpau` is needed to avoid linking issues - set(FFmpeg_CC ${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER}) - set(FFmpeg_CXX ${CMAKE_CXX_COMPILER_LAUNCHER} ${CMAKE_CXX_COMPILER}) add_custom_command( OUTPUT ${FFmpeg_MAKEFILE} diff --git a/src/ios/CMakeLists.txt b/src/ios/CMakeLists.txt index 6ddc7eb109..dc2f8b53fc 100644 --- a/src/ios/CMakeLists.txt +++ b/src/ios/CMakeLists.txt @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later -enable_language(Swift OBJC) +enable_language(Swift OBJCXX) add_executable(eden-ios AppUI-Bridging-Header.h From 87fb06454a1e7c4089e351435ccdd267e483bc15 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 22 Feb 2026 22:02:56 +0000 Subject: [PATCH 14/54] fix license --- externals/ffmpeg/CMakeLists.txt | 2 +- src/ios/AppUIGameInformation.mm | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index 7428c44695..9387ab3db0 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later # SPDX-FileCopyrightText: 2021 yuzu Emulator Project diff --git a/src/ios/AppUIGameInformation.mm b/src/ios/AppUIGameInformation.mm index 3397faa1a7..2a76e7dc7d 100644 --- a/src/ios/AppUIGameInformation.mm +++ b/src/ios/AppUIGameInformation.mm @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later From 2aad053510c13e07a56ff8607385d8e11b638372 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 22 Feb 2026 22:50:56 +0000 Subject: [PATCH 15/54] fixes for ios spirv tools --- .patch/spirv-tools/0003-ios-fix.patch | 21 +++++++++++++++++++++ externals/cpmfile.json | 3 ++- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 .patch/spirv-tools/0003-ios-fix.patch diff --git a/.patch/spirv-tools/0003-ios-fix.patch b/.patch/spirv-tools/0003-ios-fix.patch new file mode 100644 index 0000000000..2486eba82a --- /dev/null +++ b/.patch/spirv-tools/0003-ios-fix.patch @@ -0,0 +1,21 @@ +diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt +index 7ab2319..0d6b382 100644 +--- a/source/CMakeLists.txt ++++ b/source/CMakeLists.txt +@@ -151,9 +151,6 @@ add_custom_command(OUTPUT ${SPIRV_TOOLS_BUILD_VERSION_INC} + COMMENT "Update build-version.inc in the SPIRV-Tools build directory (if necessary).") + # Convenience target for standalone generation of the build-version.inc file. + # This is not required for any dependence chain. +-add_custom_target(spirv-tools-build-version +- DEPENDS ${SPIRV_TOOLS_BUILD_VERSION_INC}) +-set_property(TARGET spirv-tools-build-version PROPERTY FOLDER "SPIRV-Tools build") + + list(APPEND PCH_DEPENDS + ${CORE_TABLES_HEADER_INC_FILE} +@@ -339,7 +336,7 @@ function(spirv_tools_default_target_options target) + set_property(TARGET ${target} PROPERTY FOLDER "SPIRV-Tools libraries") + spvtools_check_symbol_exports(${target}) + add_dependencies(${target} +- spirv-tools-build-version core_tables extinst_tables) ++ core_tables extinst_tables) + endfunction() diff --git a/externals/cpmfile.json b/externals/cpmfile.json index f849426a4d..66f5ee8a5a 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -111,7 +111,8 @@ ], "patches": [ "0001-netbsd-fix.patch", - "0002-allow-static-only.patch" + "0002-allow-static-only.patch", + "0003-ios-fix.patch" ] }, "spirv-headers": { From ecd2485faedb4f21f4adf633fbaf79a95be1f2e6 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 22 Feb 2026 23:03:43 +0000 Subject: [PATCH 16/54] fix spirv-tools --- .ci/ios/build.sh | 1 + .patch/spirv-tools/0003-ios-fix.patch | 24 ++++++++++++++++++------ CMakeLists.txt | 2 +- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/.ci/ios/build.sh b/.ci/ios/build.sh index 64c52733e6..61bd45f593 100755 --- a/.ci/ios/build.sh +++ b/.ci/ios/build.sh @@ -22,6 +22,7 @@ cmake -G Xcode -B build \ -DENABLE_CUBEB=OFF \ -DYUZU_ROOM=OFF \ -DYUZU_ROOM_STANDALONE=OFF \ + -DYUZU_STATIC_ROOM=OFF \ -DYUZU_CMD=OFF \ -DUSE_DISCORD_PRESENCE=OFF \ -DYUZU_USE_EXTERNAL_FFMPEG=ON \ diff --git a/.patch/spirv-tools/0003-ios-fix.patch b/.patch/spirv-tools/0003-ios-fix.patch index 2486eba82a..7d5710ef68 100644 --- a/.patch/spirv-tools/0003-ios-fix.patch +++ b/.patch/spirv-tools/0003-ios-fix.patch @@ -1,21 +1,33 @@ diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt -index 7ab2319..0d6b382 100644 +index 7ab2319..333e325 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt -@@ -151,9 +151,6 @@ add_custom_command(OUTPUT ${SPIRV_TOOLS_BUILD_VERSION_INC} +@@ -151,9 +151,11 @@ add_custom_command(OUTPUT ${SPIRV_TOOLS_BUILD_VERSION_INC} COMMENT "Update build-version.inc in the SPIRV-Tools build directory (if necessary).") # Convenience target for standalone generation of the build-version.inc file. # This is not required for any dependence chain. -add_custom_target(spirv-tools-build-version - DEPENDS ${SPIRV_TOOLS_BUILD_VERSION_INC}) -set_property(TARGET spirv-tools-build-version PROPERTY FOLDER "SPIRV-Tools build") ++if (NOT IOS) ++ add_custom_target(spirv-tools-build-version ++ DEPENDS ${SPIRV_TOOLS_BUILD_VERSION_INC}) ++ set_property(TARGET spirv-tools-build-version PROPERTY FOLDER "SPIRV-Tools build") ++endif() list(APPEND PCH_DEPENDS - ${CORE_TABLES_HEADER_INC_FILE} -@@ -339,7 +336,7 @@ function(spirv_tools_default_target_options target) + ${CORE_TABLES_HEADER_INC_FILE} +@@ -338,8 +340,11 @@ function(spirv_tools_default_target_options target) + ) set_property(TARGET ${target} PROPERTY FOLDER "SPIRV-Tools libraries") spvtools_check_symbol_exports(${target}) - add_dependencies(${target} +- add_dependencies(${target} - spirv-tools-build-version core_tables extinst_tables) -+ core_tables extinst_tables) ++ if (IOS) ++ add_dependencies(${target} core_tables extinst_tables) ++ else () ++ add_dependencies(${target} spirv-tools-build-version core_tables extinst_tables) ++ endif() endfunction() + + if (SPIRV_TOOLS_BUILD_SHARED) diff --git a/CMakeLists.txt b/CMakeLists.txt index cb4a135d17..d23d8d776a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -212,7 +212,7 @@ option(YUZU_LEGACY "Apply patches that improve compatibility with older GPUs (e. option(NIGHTLY_BUILD "Use Nightly qualifiers in the update checker and build metadata" OFF) -cmake_dependent_option(YUZU_ROOM "Enable dedicated room functionality" ON "NOT ANDROID" OFF) +cmake_dependent_option(YUZU_ROOM "Enable dedicated room functionality" ON "NOT ANDROID AND NOT IOS" OFF) cmake_dependent_option(YUZU_ROOM_STANDALONE "Enable standalone room executable" ON "YUZU_ROOM" OFF) cmake_dependent_option(YUZU_CMD "Compile the eden-cli executable" ON "NOT ANDROID" OFF) From 5b8cd60309b692eed59611f9afb73c65cd894025 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 23 Feb 2026 02:55:16 +0000 Subject: [PATCH 17/54] fx --- externals/ffmpeg/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index 9387ab3db0..f91e58bdaa 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -203,8 +203,8 @@ else() ) elseif(IOS) execute_process(COMMAND xcrun --sdk iphoneos --show-sdk-path OUTPUT_VARIABLE SYSROOT) - set(FFmpeg_CC "xcrun --sdk iphoneos clang -arch arm64") - set(FFmpeg_CXX "xcrun --sdk iphoneos clang++ -arch arm64") + set(FFmpeg_CC xcrun --sdk iphoneos clang -arch arm64) + set(FFmpeg_CXX xcrun --sdk iphoneos clang++ -arch arm64) list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --arch=arm64 --enable-cross-compile From b55b3dc8529ec5834a938a651da1dc1263c2e230 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 23 Feb 2026 04:31:43 +0000 Subject: [PATCH 18/54] fix1 --- .ci/ios/build.sh | 1 - CMakeLists.txt | 2 +- docs/Caveats.md | 11 +++++++++++ externals/cmake-modules/DetectPlatform.cmake | 6 ++++++ externals/ffmpeg/CMakeLists.txt | 7 ++++--- 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/.ci/ios/build.sh b/.ci/ios/build.sh index 61bd45f593..808fe05976 100755 --- a/.ci/ios/build.sh +++ b/.ci/ios/build.sh @@ -26,7 +26,6 @@ cmake -G Xcode -B build \ -DYUZU_CMD=OFF \ -DUSE_DISCORD_PRESENCE=OFF \ -DYUZU_USE_EXTERNAL_FFMPEG=ON \ - -DYUZU_USE_CPM=ON \ -DYUZU_USE_EXTERNAL_SDL2=ON \ -DCPMUTIL_FORCE_BUNDLED=ON \ -DCMAKE_BUILD_TYPE=Release diff --git a/CMakeLists.txt b/CMakeLists.txt index d23d8d776a..f5ebbce74a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -283,7 +283,7 @@ if (YUZU_ROOM) add_compile_definitions(YUZU_ROOM) endif() -if ((ANDROID OR APPLE OR UNIX) AND (NOT PLATFORM_LINUX OR ANDROID) AND NOT WIN32) +if ((ANDROID OR APPLE OR UNIX OR IOS) AND (NOT PLATFORM_LINUX OR ANDROID) AND NOT WIN32) if(CXX_APPLE OR CXX_CLANG) # libc++ has stop_token and jthread as experimental set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexperimental-library") diff --git a/docs/Caveats.md b/docs/Caveats.md index d554f3ff77..ad3fde1876 100644 --- a/docs/Caveats.md +++ b/docs/Caveats.md @@ -4,6 +4,7 @@ - [Arch Linux](#arch-linux) - [Gentoo Linux](#gentoo-linux) - [macOS](#macos) +- [iOS](#ios) - [Solaris](#solaris) - [HaikuOS](#haikuos) - [OpenBSD](#openbsd) @@ -31,6 +32,16 @@ If you're having issues with building, always consult that ebuild. macOS is largely untested. Expect crashes, significant Vulkan issues, and other fun stuff. +## iOS + +iOS has a dedicated build script, we **highly** recommend using that instead of doing anything else, we don't support any other configuration than the one present in said build script. + +To build, it's simply as easy as doing +```sh +chmod +x .ci/ios/build.sh +.ci/ios/build.sh +``` + ## Solaris Always consult [the OpenIndiana package list](https://pkg.openindiana.org/hipster/en/index.shtml) to cross-verify availability. diff --git a/externals/cmake-modules/DetectPlatform.cmake b/externals/cmake-modules/DetectPlatform.cmake index 6475884f1f..bac5180770 100644 --- a/externals/cmake-modules/DetectPlatform.cmake +++ b/externals/cmake-modules/DetectPlatform.cmake @@ -51,6 +51,12 @@ elseif (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") set(CXX_APPLE ON) endif() +# This fixes some quirks with xcrun or weird iOS toolchain cmake files +if (IOS) + unser(CXX_CLANG) + set(CXX_APPLE ON) +endif() + # https://gitlab.kitware.com/cmake/cmake/-/merge_requests/11112 # This works totally fine on MinGW64, but not CLANG{,ARM}64 if(MINGW AND CXX_CLANG) diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index f91e58bdaa..b8d7ae3a12 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -203,15 +203,16 @@ else() ) elseif(IOS) execute_process(COMMAND xcrun --sdk iphoneos --show-sdk-path OUTPUT_VARIABLE SYSROOT) + # Lovely extra newline apple adds that **we** must remove... thank you apple! + string(STRIP "${SYSROOT}" SYSROOT) set(FFmpeg_CC xcrun --sdk iphoneos clang -arch arm64) set(FFmpeg_CXX xcrun --sdk iphoneos clang++ -arch arm64) list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --arch=arm64 --enable-cross-compile - --sysroot=${SYSROOT} - --target-os=darwin + --sysroot="${SYSROOT}" --extra-ldflags="-miphoneos-version-min=16.0" - --install-name-dir="@rpath" + --install-name-dir='@rpath' --disable-audiotoolbox ) endif() From 29e77a20f1339727fddc70d1bb802d1120c973ef Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 23 Feb 2026 05:15:17 +0000 Subject: [PATCH 19/54] stupid macos --- .ci/ios/build.sh | 1 + externals/cmake-modules/DetectPlatform.cmake | 2 +- src/common/host_memory.cpp | 6 +++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.ci/ios/build.sh b/.ci/ios/build.sh index 808fe05976..ca37ce9da2 100755 --- a/.ci/ios/build.sh +++ b/.ci/ios/build.sh @@ -13,6 +13,7 @@ fi cmake -G Xcode -B build \ -DCMAKE_TOOLCHAIN_FILE="$WORK_DIR/.ci/ios/ios-toolchain.cmake" \ -DPLATFORM=OS64 \ + -DDEPLOYMENT_TARGET=16.0 \ -DCOCOA_LIBRARY="$IOS_SDK/System/Library/Frameworks/Cocoa.framework" \ -DENABLE_LIBUSB=OFF \ -DENABLE_UPDATE_CHECKER=OFF \ diff --git a/externals/cmake-modules/DetectPlatform.cmake b/externals/cmake-modules/DetectPlatform.cmake index bac5180770..eec94d839c 100644 --- a/externals/cmake-modules/DetectPlatform.cmake +++ b/externals/cmake-modules/DetectPlatform.cmake @@ -53,7 +53,7 @@ endif() # This fixes some quirks with xcrun or weird iOS toolchain cmake files if (IOS) - unser(CXX_CLANG) + unset(CXX_CLANG) set(CXX_APPLE ON) endif() diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 04f3a65778..9e7fab9db3 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -27,13 +27,17 @@ #include #elif defined(__APPLE__) #include -#include #include #include #elif defined(__FreeBSD__) #include #endif +// Not available on iOS for some fucking stupid reason... +#if defined(__APPLE__) && TARGET_OS_MAC +#include +#endif + // FreeBSD #ifndef MAP_NORESERVE #define MAP_NORESERVE 0 From 14d8ff5378879af457db1264bc51523f24bc14cb Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 23 Feb 2026 05:24:15 +0000 Subject: [PATCH 20/54] fix stuff --- .ci/ios/build.sh | 2 ++ src/common/device_power_state.cpp | 3 +-- src/common/host_memory.cpp | 10 +++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.ci/ios/build.sh b/.ci/ios/build.sh index ca37ce9da2..2f15472178 100755 --- a/.ci/ios/build.sh +++ b/.ci/ios/build.sh @@ -15,6 +15,8 @@ cmake -G Xcode -B build \ -DPLATFORM=OS64 \ -DDEPLOYMENT_TARGET=16.0 \ -DCOCOA_LIBRARY="$IOS_SDK/System/Library/Frameworks/Cocoa.framework" \ + -DCMAKE_C_COMPILER="$(xcrun --sdk iphoneos clang -arch arm64)" \ + -DCMAKE_CXX_COMPILER="$(xcrun --sdk iphoneos clang++ -arch arm64)" \ -DENABLE_LIBUSB=OFF \ -DENABLE_UPDATE_CHECKER=OFF \ -DENABLE_QT=OFF \ diff --git a/src/common/device_power_state.cpp b/src/common/device_power_state.cpp index 2dfa7dc305..8419434ef2 100644 --- a/src/common/device_power_state.cpp +++ b/src/common/device_power_state.cpp @@ -14,11 +14,10 @@ extern std::atomic g_has_battery; #elif defined(__APPLE__) #include -#if TARGET_OS_MAC +#if defined(TARGET_OS_MAC) && TARGET_OS_MAC #include #include #endif - #elif defined(__linux__) #include #include diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 9e7fab9db3..11f03867d5 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -27,17 +27,17 @@ #include #elif defined(__APPLE__) #include +#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE +// Not available on iOS for some fucking stupid reason... +#else +#include +#endif #include #include #elif defined(__FreeBSD__) #include #endif -// Not available on iOS for some fucking stupid reason... -#if defined(__APPLE__) && TARGET_OS_MAC -#include -#endif - // FreeBSD #ifndef MAP_NORESERVE #define MAP_NORESERVE 0 From 2b82878af3160516a4fcbaa835730b0d20009cd9 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 23 Feb 2026 07:02:00 +0000 Subject: [PATCH 21/54] fx --- .ci/ios/build.sh | 6 ++---- src/common/device_power_state.cpp | 9 +++++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.ci/ios/build.sh b/.ci/ios/build.sh index 2f15472178..9ab6cfaaa3 100755 --- a/.ci/ios/build.sh +++ b/.ci/ios/build.sh @@ -4,9 +4,7 @@ # SPDX-License-Identifier: GPL-3.0-or-later WORK_DIR="$PWD" -if [ -z "$NPROC" ]; then - NPROC="$(nproc)" -fi +export IOS_SDK="$(xcrun --sdk iphoneos --show-sdk-path)" [ ! -z "$IOS_SDK" ] @@ -33,4 +31,4 @@ cmake -G Xcode -B build \ -DCPMUTIL_FORCE_BUNDLED=ON \ -DCMAKE_BUILD_TYPE=Release -cmake --build build -- -j${NPROC} +cmake --build build diff --git a/src/common/device_power_state.cpp b/src/common/device_power_state.cpp index 8419434ef2..c777cb4009 100644 --- a/src/common/device_power_state.cpp +++ b/src/common/device_power_state.cpp @@ -15,9 +15,13 @@ extern std::atomic g_has_battery; #elif defined(__APPLE__) #include #if defined(TARGET_OS_MAC) && TARGET_OS_MAC +#if TARGET_OS_IPHONE +// ios doesnt have this +#else #include #include #endif +#endif #elif defined(__linux__) #include #include @@ -47,7 +51,9 @@ namespace Common { info.percentage = g_battery_percentage.load(std::memory_order_relaxed); info.charging = g_is_charging.load(std::memory_order_relaxed); info.has_battery = g_has_battery.load(std::memory_order_relaxed); - +#elif defined(__APPLE__) && TARGET_OS_IPHONE + // Not implemented + info.has_battery = false; #elif defined(__APPLE__) && TARGET_OS_MAC CFTypeRef info_ref = IOPSCopyPowerSourcesInfo(); CFArrayRef sources = IOPSCopyPowerSourcesList(info_ref); @@ -95,7 +101,6 @@ namespace Common { #else info.has_battery = false; #endif - return info; } } From 373277af059839433bc63edfa01a25c46c05bb5a Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 23 Feb 2026 18:27:43 +0000 Subject: [PATCH 22/54] fix boost --- .patch/boost/0002-ios-fix.patch | 0 cpmfile.json | 3 ++- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 .patch/boost/0002-ios-fix.patch diff --git a/.patch/boost/0002-ios-fix.patch b/.patch/boost/0002-ios-fix.patch new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpmfile.json b/cpmfile.json index 1bb29afae4..8542fcddc7 100644 --- a/cpmfile.json +++ b/cpmfile.json @@ -17,7 +17,8 @@ "version": "1.57", "find_args": "CONFIG OPTIONAL_COMPONENTS headers context system fiber filesystem", "patches": [ - "0001-clang-cl.patch" + "0001-clang-cl.patch", + "0002-ios-fix.patch" ] }, "fmt": { From 83eea9ba639fd61ad2b854f6989ddf4c8e4becaf Mon Sep 17 00:00:00 2001 From: lizzie Date: Tue, 24 Feb 2026 00:43:59 +0000 Subject: [PATCH 23/54] fx --- .patch/boost/0002-ios-fix.patch | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.patch/boost/0002-ios-fix.patch b/.patch/boost/0002-ios-fix.patch index e69de29bb2..7a68ef6137 100644 --- a/.patch/boost/0002-ios-fix.patch +++ b/.patch/boost/0002-ios-fix.patch @@ -0,0 +1,22 @@ +diff --git a/libs/process/src/shell.cpp b/libs/process/src/shell.cpp +index bf4bbfd8..e45ba39c 100644 +--- a/libs/process/src/shell.cpp ++++ b/libs/process/src/shell.cpp +@@ -19,7 +19,7 @@ + #if defined(BOOST_PROCESS_V2_WINDOWS) + #include + #include +-#elif !defined(__OpenBSD__) && !defined(__ANDROID__) ++#elif !defined(__OpenBSD__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IPHONE) + #include + #endif + +@@ -99,7 +99,7 @@ auto shell::args() const-> args_type + return input_.c_str(); + } + +-#elif !defined(__OpenBSD__) && !defined(__ANDROID__) ++#elif !defined(__OpenBSD__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IPHONE) + + void shell::parse_() + { From 5766888cbf5cf70218c8b680f57648975aeba776 Mon Sep 17 00:00:00 2001 From: lizzie Date: Tue, 24 Feb 2026 00:58:36 +0000 Subject: [PATCH 24/54] fx --- .patch/boost/0002-ios-fix.patch | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.patch/boost/0002-ios-fix.patch b/.patch/boost/0002-ios-fix.patch index 7a68ef6137..4f5d495154 100644 --- a/.patch/boost/0002-ios-fix.patch +++ b/.patch/boost/0002-ios-fix.patch @@ -1,5 +1,5 @@ diff --git a/libs/process/src/shell.cpp b/libs/process/src/shell.cpp -index bf4bbfd8..e45ba39c 100644 +index bf4bbfd8..bc4aae89 100644 --- a/libs/process/src/shell.cpp +++ b/libs/process/src/shell.cpp @@ -19,7 +19,7 @@ @@ -11,6 +11,15 @@ index bf4bbfd8..e45ba39c 100644 #include #endif +@@ -30,7 +30,7 @@ BOOST_PROCESS_V2_DECL const error_category& get_shell_category() + { + return system_category(); + } +-#elif !defined(__OpenBSD__) && !defined(__ANDROID__) ++#elif !defined(__OpenBSD__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IPHONE) + + struct shell_category_t final : public error_category + { @@ -99,7 +99,7 @@ auto shell::args() const-> args_type return input_.c_str(); } From b26c0ba2f66c303d305d0fa6f8458831c570d48d Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 8 Mar 2026 02:42:00 +0000 Subject: [PATCH 25/54] fix xcode paths? --- src/core/arm/dynarmic/arm_dynarmic.h | 2 +- src/core/arm/dynarmic/arm_dynarmic_32.h | 4 ++-- src/core/arm/dynarmic/arm_dynarmic_64.h | 4 ++-- src/core/arm/dynarmic/dynarmic_cp15.h | 2 +- src/core/arm/dynarmic/dynarmic_exclusive_monitor.h | 2 +- src/core/arm/nce/visitor_base.h | 6 +++--- src/core/hle/service/jit/jit_context.cpp | 6 +++--- src/dynarmic/src/dynarmic/interface/exclusive_monitor.h | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index 46384f7e6d..0fb4e9701d 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h @@ -4,7 +4,7 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include +#include "dynarmic/interface/halt_reason.h" #include "core/arm/arm_interface.h" diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index d93cc1cfc9..011751c53d 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -6,8 +6,8 @@ #pragma once -#include -#include +#include "dynarmic/interface/A32/a32.h" +#include "dynarmic/interface/code_page.h" #include "core/arm/arm_interface.h" #include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index 9eff17c5fe..b95462be15 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -10,8 +10,8 @@ #include #include -#include -#include +#include "dynarmic/interface/A64/a64.h" +#include "dynarmic/interface/code_page.h" #include "common/common_types.h" #include "common/hash.h" #include "core/arm/arm_interface.h" diff --git a/src/core/arm/dynarmic/dynarmic_cp15.h b/src/core/arm/dynarmic/dynarmic_cp15.h index f3d96b0d83..e4de20d578 100644 --- a/src/core/arm/dynarmic/dynarmic_cp15.h +++ b/src/core/arm/dynarmic/dynarmic_cp15.h @@ -5,7 +5,7 @@ #include -#include +#include "dynarmic/interface/A32/coprocessor.h" #include "common/common_types.h" namespace Core { diff --git a/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h index c4f22ec891..2362dad90e 100644 --- a/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h +++ b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h @@ -3,7 +3,7 @@ #pragma once -#include +#include "dynarmic/interface/exclusive_monitor.h" #include "common/common_types.h" #include "core/arm/exclusive_monitor.h" diff --git a/src/core/arm/nce/visitor_base.h b/src/core/arm/nce/visitor_base.h index 6a2be3d9bc..1feae327c0 100644 --- a/src/core/arm/nce/visitor_base.h +++ b/src/core/arm/nce/visitor_base.h @@ -7,9 +7,9 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wshadow" -#include -#include -#include +#include "dynarmic/frontend/A64/a64_types.h" +#include "dynarmic/frontend/A64/decoder/a64.h" +#include "dynarmic/frontend/imm.h" #pragma GCC diagnostic pop diff --git a/src/core/hle/service/jit/jit_context.cpp b/src/core/hle/service/jit/jit_context.cpp index 522d849e6f..cd0252c6ec 100644 --- a/src/core/hle/service/jit/jit_context.cpp +++ b/src/core/hle/service/jit/jit_context.cpp @@ -8,9 +8,9 @@ #include #include #include -#include -#include -#include +#include "dynarmic/interface/A64/a64.h" +#include "dynarmic/interface/A64/config.h" +#include "dynarmic/interface/code_page.h" #include "common/alignment.h" #include "common/common_funcs.h" diff --git a/src/dynarmic/src/dynarmic/interface/exclusive_monitor.h b/src/dynarmic/src/dynarmic/interface/exclusive_monitor.h index 566743c767..0d35716c4c 100644 --- a/src/dynarmic/src/dynarmic/interface/exclusive_monitor.h +++ b/src/dynarmic/src/dynarmic/interface/exclusive_monitor.h @@ -11,7 +11,7 @@ #include #include -#include +#include "dynarmic/common/spin_lock.h" namespace Dynarmic { From 100d3cd26df56ea7d87b1228f28d00e3078998a4 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 9 Mar 2026 18:51:54 +0000 Subject: [PATCH 26/54] fix xcode 2? --- src/core/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 08a2d0e2db..3ff901abf3 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1264,6 +1264,10 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) hle/service/jit/jit.cpp hle/service/jit/jit.h) target_link_libraries(core PRIVATE dynarmic::dynarmic) + # Quick hack for XCode generator... + if (IOS) + target_include_directories(core PRIVATE "${CMAKE_SOURCE_DIR}/dynarmic/src") + endif() endif() target_sources(core PRIVATE hle/service/ssl/ssl_backend_openssl.cpp) From 3d298567ca1153bb2941f4deb0c54afebba6b515 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 9 Mar 2026 18:53:04 +0000 Subject: [PATCH 27/54] fix license --- src/common/device_power_state.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/device_power_state.cpp b/src/common/device_power_state.cpp index c777cb4009..01bcedeba2 100644 --- a/src/common/device_power_state.cpp +++ b/src/common/device_power_state.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later #include "device_power_state.h" From 89da1c6b9bcb43c5309ab442d66727b95acb5b2b Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 23 Mar 2026 05:44:56 +0000 Subject: [PATCH 28/54] bridge changes/fixes --- src/ios/AppUI-Bridging-Header.h | 2 +- src/ios/AppUIGameInformation.mm | 7 ++-- src/ios/AppUIObjC.h | 2 +- src/ios/AppUIObjC.mm | 20 ++++------- src/ios/EmulationSession.h | 13 ++++--- src/ios/EmulationSession.mm | 63 +++------------------------------ src/ios/EmulationWindow.h | 10 ++++-- src/ios/EmulationWindow.mm | 9 ++--- 8 files changed, 37 insertions(+), 89 deletions(-) diff --git a/src/ios/AppUI-Bridging-Header.h b/src/ios/AppUI-Bridging-Header.h index 091fe7117f..d3bc77082f 100644 --- a/src/ios/AppUI-Bridging-Header.h +++ b/src/ios/AppUI-Bridging-Header.h @@ -9,6 +9,6 @@ #ifndef AppUI_Bridging_Header_h #define AppUI_Bridging_Header_h -#import "Wrapper/AppUIObjC.h" +#import "AppUIObjC.h" #endif /* AppUI_Bridging_Header_h */ diff --git a/src/ios/AppUIGameInformation.mm b/src/ios/AppUIGameInformation.mm index 2a76e7dc7d..4b69324420 100644 --- a/src/ios/AppUIGameInformation.mm +++ b/src/ios/AppUIGameInformation.mm @@ -1,9 +1,6 @@ // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later -# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -# SPDX-License-Identifier: GPL-3.0-or-later - // // AppUIGameInformation.mm - Sudachi // Created by Jarrod Norwell on 1/20/24. @@ -11,7 +8,7 @@ #import #import "AppUIGameInformation.h" -#import "EmulationSession/EmulationSession.h" +#import "EmulationSession.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" @@ -20,7 +17,7 @@ #include "core/file_sys/patch_manager.h" #include "core/loader/loader.h" #include "core/loader/nro.h" -#include "frontend_common/yuzu_config.h" +#include "frontend_common/config.h" struct GameMetadata { std::string title; diff --git a/src/ios/AppUIObjC.h b/src/ios/AppUIObjC.h index 1a79babf4f..ec5a5f1e8c 100644 --- a/src/ios/AppUIObjC.h +++ b/src/ios/AppUIObjC.h @@ -9,7 +9,7 @@ #import #import -#import "AppUIGameInformation/AppUIGameInformation.h" +#import "AppUIGameInformation.h" NS_ASSUME_NONNULL_BEGIN diff --git a/src/ios/AppUIObjC.mm b/src/ios/AppUIObjC.mm index 97cdc894b5..c03a20c530 100644 --- a/src/ios/AppUIObjC.mm +++ b/src/ios/AppUIObjC.mm @@ -8,9 +8,8 @@ #import "AppUIObjC.h" -#import "Config/Config.h" -#import "EmulationSession/EmulationSession.h" -#import "DirectoryManager/DirectoryManager.h" +#import "Config.h" +#import "EmulationSession.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" @@ -30,8 +29,6 @@ #include "common/fs/path_util.h" #include "common/logging/backend.h" #include "common/logging/log.h" -#include "common/microprofile.h" -#include "common/scm_rev.h" #include "common/scope_exit.h" #include "common/settings.h" #include "common/string_util.h" @@ -56,8 +53,6 @@ #include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/loader.h" -#include "frontend_common/yuzu_config.h" -#include "hid_core/frontend/emulated_controller.h" #include "hid_core/hid_core.h" #include "hid_core/hid_types.h" #include "video_core/renderer_base.h" @@ -77,7 +72,7 @@ const char *directory_cstr = [[dir_url path] UTF8String]; Common::FS::SetAppDirectory(directory_cstr); - Config{"config", Config::ConfigType::GlobalConfig}; + // Config{"config", Config::ConfigType::GlobalConfig}; EmulationSession::GetInstance().System().Initialize(); EmulationSession::GetInstance().InitializeSystem(false); @@ -87,7 +82,6 @@ Settings::values.dump_shaders.SetValue(true); Settings::values.use_asynchronous_shaders.SetValue(true); // Settings::values.astc_recompression.SetValue(Settings::AstcRecompression::Bc3); - Settings::values.shader_backend.SetValue(Settings::ShaderBackend::SpirV); // Settings::values.resolution_setup.SetValue(Settings::ResolutionSetup::Res1X); // Settings::values.scaling_filter.SetValue(Settings::ScalingFilter::Bilinear); } return self; @@ -168,7 +162,7 @@ -(void) configureLayer:(CAMetalLayer *)layer withSize:(CGSize)size { _layer = layer; _size = size; - EmulationSession::GetInstance().SetNativeWindow((__bridge CA::MetalLayer*)layer, size); + EmulationSession::GetInstance().SetNativeWindow(layer, size); } -(void) bootOS { @@ -251,13 +245,11 @@ -(void) orientationChanged:(UIInterfaceOrientation)orientation with:(CAMetalLayer *)layer size:(CGSize)size { _layer = layer; _size = size; - EmulationSession::GetInstance().Window().OnSurfaceChanged((__bridge CA::MetalLayer*)layer, size); + EmulationSession::GetInstance().Window().OnSurfaceChanged(layer, size); } -(void) settingsChanged { - Config{"config", Config::ConfigType::GlobalConfig}; + // } - - @end diff --git a/src/ios/EmulationSession.h b/src/ios/EmulationSession.h index 56c1930df6..287a65839d 100644 --- a/src/ios/EmulationSession.h +++ b/src/ios/EmulationSession.h @@ -8,10 +8,15 @@ #pragma once +#import #import +#if __has_include() #import -#import "EmulationWindow/EmulationWindow.h" +#else +#import +#endif +#import "EmulationWindow.h" #include "common/detached_tasks.h" #include "core/core.h" @@ -34,8 +39,8 @@ public: const EmulationWindow& Window() const; EmulationWindow& Window(); - CA::MetalLayer* NativeWindow() const; - void SetNativeWindow(CA::MetalLayer* native_window, CGSize size); + CAMetalLayer* NativeWindow() const; + void SetNativeWindow(CAMetalLayer* native_window, CGSize size); void SurfaceChanged(); void InitializeGpuDriver(); @@ -73,7 +78,7 @@ private: private: // Window management std::unique_ptr m_window; - CA::MetalLayer* m_native_window{}; + CAMetalLayer* m_native_window{}; // Core emulation Core::System m_system; diff --git a/src/ios/EmulationSession.mm b/src/ios/EmulationSession.mm index 2575f053e2..9b4171e082 100644 --- a/src/ios/EmulationSession.mm +++ b/src/ios/EmulationSession.mm @@ -27,7 +27,6 @@ #include "common/fs/path_util.h" #include "common/logging/backend.h" #include "common/logging/log.h" -#include "common/microprofile.h" #include "common/scm_rev.h" #include "common/scope_exit.h" #include "common/settings.h" @@ -53,7 +52,7 @@ #include "core/hle/service/am/frontend/applets.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/loader.h" -#include "frontend_common/yuzu_config.h" +#include "frontend_common/config.h" #include "hid_core/frontend/emulated_controller.h" #include "hid_core/hid_core.h" #include "hid_core/hid_types.h" @@ -99,11 +98,11 @@ EmulationWindow& EmulationSession::Window() { return *m_window; } -CA::MetalLayer* EmulationSession::NativeWindow() const { +CAMetalLayer* EmulationSession::NativeWindow() const { return m_native_window; } -void EmulationSession::SetNativeWindow(CA::MetalLayer* native_window, CGSize size) { +void EmulationSession::SetNativeWindow(CAMetalLayer* native_window, CGSize size) { m_native_window = native_window; m_size = size; } @@ -209,17 +208,7 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string m_system.ApplySettings(); Settings::LogSettings(); m_system.HIDCore().ReloadInputDevices(); - m_system.SetFrontendAppletSet({ - nullptr, // Amiibo Settings - nullptr, // Controller Selector - nullptr, // Error Display - nullptr, // Mii Editor - nullptr, // Parental Controls - nullptr, // Photo Viewer - nullptr, // Profile Selector - nullptr, // std::move(android_keyboard), // Software Keyboard - nullptr, // Web Browser - }); + m_system.SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet{}); // Initialize filesystem. ConfigureFilesystemProvider(filepath); @@ -270,17 +259,7 @@ Core::SystemResultStatus EmulationSession::BootOS() { m_system.ApplySettings(); Settings::LogSettings(); m_system.HIDCore().ReloadInputDevices(); - m_system.SetFrontendAppletSet({ - nullptr, // Amiibo Settings - nullptr, // Controller Selector - nullptr, // Error Display - nullptr, // Mii Editor - nullptr, // Parental Controls - nullptr, // Photo Viewer - nullptr, // Profile Selector - nullptr, // std::move(android_keyboard), // Software Keyboard - nullptr, // Web Browser - }); + m_system.SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet{}); constexpr u64 QLaunchId = static_cast(Service::AM::AppletProgramId::QLaunch); auto bis_system = m_system.GetFileSystemController().GetSystemNANDContents(); @@ -444,38 +423,6 @@ u64 EmulationSession::GetProgramId(std::string programId) { } } -static Core::SystemResultStatus RunEmulation(const std::string& filepath, - const size_t program_index, - const bool frontend_initiated) { - MicroProfileOnThreadCreate("EmuThread"); - SCOPE_EXIT { - MicroProfileShutdown(); - }; - - LOG_INFO(Frontend, "starting"); - - if (filepath.empty()) { - LOG_CRITICAL(Frontend, "failed to load: filepath empty!"); - return Core::SystemResultStatus::ErrorLoader; - } - - SCOPE_EXIT { - EmulationSession::GetInstance().ShutdownEmulation(); - }; - - jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index, - frontend_initiated); - if (result != Core::SystemResultStatus::Success) { - return result; - } - - EmulationSession::GetInstance().RunEmulation(); - - return Core::SystemResultStatus::Success; -} - - - bool EmulationSession::IsHandheldOnly() { jconst npad_style_set = m_system.HIDCore().GetSupportedStyleTag(); diff --git a/src/ios/EmulationWindow.h b/src/ios/EmulationWindow.h index 4d8b0b888f..53162a7f58 100644 --- a/src/ios/EmulationWindow.h +++ b/src/ios/EmulationWindow.h @@ -8,9 +8,15 @@ #pragma once +#if __has_include() #import +#else +#import +#endif #import #import +#import +#import #include #include @@ -38,12 +44,12 @@ NS_ASSUME_NONNULL_BEGIN class EmulationWindow final : public Core::Frontend::EmuWindow { public: - EmulationWindow(InputCommon::InputSubsystem* input_subsystem, CA::MetalLayer* surface, CGSize size, + EmulationWindow(InputCommon::InputSubsystem* input_subsystem, CAMetalLayer* surface, CGSize size, std::shared_ptr driver_library); ~EmulationWindow() = default; - void OnSurfaceChanged(CA::MetalLayer* surface, CGSize size); + void OnSurfaceChanged(CAMetalLayer* surface, CGSize size); void OrientationChanged(UIInterfaceOrientation orientation); void OnFrameDisplayed() override; diff --git a/src/ios/EmulationWindow.mm b/src/ios/EmulationWindow.mm index f5c53309b4..638db800a8 100644 --- a/src/ios/EmulationWindow.mm +++ b/src/ios/EmulationWindow.mm @@ -7,7 +7,7 @@ // #import "EmulationWindow.h" -#import "EmulationSession/EmulationSession.h" +#import "EmulationSession.h" #include @@ -17,7 +17,7 @@ #include "input_common/drivers/virtual_gamepad.h" #include "input_common/main.h" -void EmulationWindow::OnSurfaceChanged(CA::MetalLayer* surface, CGSize size) { +void EmulationWindow::OnSurfaceChanged(CAMetalLayer* surface, CGSize size) { m_size = size; m_window_width = size.width; @@ -26,7 +26,7 @@ void EmulationWindow::OnSurfaceChanged(CA::MetalLayer* surface, CGSize size) { // Ensures that we emulate with the correct aspect ratio. // UpdateCurrentFramebufferLayout(m_window_width, m_window_height); - window_info.render_surface = reinterpret_cast(surface); + window_info.render_surface = (__bridge void *)surface; window_info.render_surface_scale = [[UIScreen mainScreen] nativeScale]; } @@ -68,7 +68,8 @@ void EmulationWindow::OnFrameDisplayed() { } } -EmulationWindow::EmulationWindow(InputCommon::InputSubsystem* input_subsystem, CA::MetalLayer* surface, CGSize size, std::shared_ptr driver_library) : m_input_subsystem{input_subsystem}, m_size{size}, m_driver_library{driver_library} { +EmulationWindow::EmulationWindow(InputCommon::InputSubsystem* input_subsystem, CAMetalLayer* surface, CGSize size, std::shared_ptr driver_library) + : m_window_width{}, m_window_height{}, m_size{size}, is_portrait{true}, m_input_subsystem{input_subsystem}, m_driver_library{driver_library}, m_first_frame{false} { LOG_INFO(Frontend, "initializing"); if (!surface) { From 2151c2d37a0daab15435599cd99e30bc46141ba5 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 23 Mar 2026 05:48:57 +0000 Subject: [PATCH 29/54] proper linkings?! --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f5ebbce74a..7777deafb1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -484,7 +484,6 @@ endfunction() # Platform-specific library requirements # Put these BEFORE EXTERNALS or Boost WILL die # ============================================= - if (APPLE) set(_libs Carbon Metal Cocoa IOKit CoreVideo CoreMedia) if (IOS) From b8a132110adf209fdd1af31e9890a380d14570c7 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 26 Mar 2026 03:47:30 +0000 Subject: [PATCH 30/54] $<$:-Werror=missing-declarations> --- src/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3759878c2a..db48be86c9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -127,13 +127,15 @@ else() add_compile_options( $<$:-Werror=all> $<$:-Werror=extra> - $<$:-Werror=missing-declarations> $<$:-Werror=shadow> $<$:-Werror=unused> $<$:-Wno-attributes> $<$:-Wno-invalid-offsetof> $<$:-Wno-unused-parameter> $<$:-Wno-missing-field-initializers>) + if (NOT IOS) + add_compile_options($<$:-Werror=missing-declarations>) + endif() if (CXX_CLANG OR CXX_ICC OR CXX_APPLE) # Clang, AppleClang, or Intel C++ if (NOT MSVC) From c7b9af30fa050747a7d3903fcef342219547dc00 Mon Sep 17 00:00:00 2001 From: lizzie Date: Tue, 24 Mar 2026 22:34:05 +0000 Subject: [PATCH 31/54] use language generator exprs --- src/CMakeLists.txt | 1 + src/video_core/CMakeLists.txt | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index db48be86c9..ad8adc7a04 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -253,6 +253,7 @@ endif() if (IOS) add_subdirectory(ios) + add_compile_options($<$:-Wno-error>) endif() include(GenerateDepHashes) diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 362b068656..3a572eb875 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -369,7 +369,6 @@ else() else() target_compile_options(video_core PRIVATE $<$:-Werror=conversion>) endif() - target_compile_options(video_core PRIVATE $<$:-Wno-sign-conversion>) # xbyak From 2479d32b22d98a2378de93fe3f34339ebfd29932 Mon Sep 17 00:00:00 2001 From: lizzie Date: Tue, 24 Mar 2026 22:42:33 +0000 Subject: [PATCH 32/54] bit of cmake fuckery --- .ci/ios/build.sh | 4 + CMakeLists.txt | 38 +++++- src/common/string_util.cpp | 113 +++++++++++++++++- src/core/CMakeLists.txt | 4 +- .../hle/service/bcat/news/builtin_news.cpp | 2 +- src/frontend_common/CMakeLists.txt | 5 +- src/ios/CMakeLists.txt | 4 + src/qt_common/CMakeLists.txt | 4 +- src/web_service/CMakeLists.txt | 27 ++++- 9 files changed, 182 insertions(+), 19 deletions(-) diff --git a/.ci/ios/build.sh b/.ci/ios/build.sh index 9ab6cfaaa3..fa850f3931 100755 --- a/.ci/ios/build.sh +++ b/.ci/ios/build.sh @@ -11,6 +11,7 @@ export IOS_SDK="$(xcrun --sdk iphoneos --show-sdk-path)" cmake -G Xcode -B build \ -DCMAKE_TOOLCHAIN_FILE="$WORK_DIR/.ci/ios/ios-toolchain.cmake" \ -DPLATFORM=OS64 \ + -DARCHS="arm64" \ -DDEPLOYMENT_TARGET=16.0 \ -DCOCOA_LIBRARY="$IOS_SDK/System/Library/Frameworks/Cocoa.framework" \ -DCMAKE_C_COMPILER="$(xcrun --sdk iphoneos clang -arch arm64)" \ @@ -19,6 +20,9 @@ cmake -G Xcode -B build \ -DENABLE_UPDATE_CHECKER=OFF \ -DENABLE_QT=OFF \ -DENABLE_OPENSSL=OFF \ + -DHTTPLIB_USE_OPENSSL=OFF \ + -DCPPHTTPLIB_USE_OPENSSL=OFF \ + -DHTTPLIB_USE_OPENSSL_IF_AVAILABLE=OFF \ -DENABLE_WEB_SERVICE=OFF \ -DENABLE_CUBEB=OFF \ -DYUZU_ROOM=OFF \ diff --git a/CMakeLists.txt b/CMakeLists.txt index 7777deafb1..80b0e59b14 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,3 @@ -# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -# SPDX-License-Identifier: GPL-3.0-or-later - cmake_minimum_required(VERSION 3.22) project(yuzu) @@ -359,7 +356,10 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) -find_package(RenderDoc MODULE) +find_package(RenderDoc MODULE QUIET) +if (NOT RenderDoc_FOUND) + message(WARNING "RenderDoc not found. Some debugging features may be disabled.") +endif() # openssl funniness if (YUZU_USE_BUNDLED_OPENSSL) @@ -370,7 +370,35 @@ if (YUZU_USE_BUNDLED_OPENSSL) endif() endif() -find_package(OpenSSL 3 REQUIRED) +if (IOS) + # TODO: this is horrific wtf + # Modify OpenSSL configuration to dynamically locate OpenSSL + if (NOT OPENSSL_ROOT_DIR) + find_program(HOMEBREW_EXECUTABLE brew) + if (HOMEBREW_EXECUTABLE) + execute_process( + COMMAND ${HOMEBREW_EXECUTABLE} --prefix openssl + OUTPUT_VARIABLE HOMEBREW_OPENSSL_PREFIX + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + set(OPENSSL_ROOT_DIR "${HOMEBREW_OPENSSL_PREFIX}") + endif() + endif() + # Adjust OpenSSL find_package to fallback to default paths + find_package(OpenSSL 3 QUIET PATHS ${OPENSSL_ROOT_DIR} PATHS /usr/local/opt/openssl /opt/homebrew/opt/openssl NO_DEFAULT_PATH) + if (NOT OpenSSL_FOUND) + find_package(OpenSSL 3 QUIET) + if (NOT OpenSSL_FOUND) + message(WARNING "OpenSSL not found. Some features may be disabled.") + endif() + endif() + # Ensure OpenSSL version 3 is correctly located + set(OPENSSL_ROOT_DIR "/opt/homebrew/opt/openssl@3") + set(OPENSSL_LIBRARIES "/opt/homebrew/opt/openssl@3/lib") + set(OPENSSL_INCLUDE_DIR "/opt/homebrew/opt/openssl@3/include") +else() + find_package(OpenSSL 3 REQUIRED) +endif() message(STATUS "Fetching needed dependencies with CPM") diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 7bcbe737b6..2588624d4c 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -116,18 +116,119 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st } std::string UTF16ToUTF8(std::u16string_view input) { - std::wstring_convert, char16_t> convert; - return convert.to_bytes(input.data(), input.data() + input.size()); + std::string result; + result.reserve(input.size()); + for (size_t i = 0; i < input.size(); ++i) { + uint32_t codepoint = input[i]; + // Handle surrogate pairs + if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { + if (i + 1 < input.size()) { + uint32_t low = input[i + 1]; + if (low >= 0xDC00 && low <= 0xDFFF) { + codepoint = ((codepoint - 0xD800) << 10) + (low - 0xDC00) + 0x10000; + ++i; + } + } + } + if (codepoint <= 0x7F) { + result.push_back(static_cast(codepoint)); + } else if (codepoint <= 0x7FF) { + result.push_back(static_cast(0xC0 | (codepoint >> 6))); + result.push_back(static_cast(0x80 | (codepoint & 0x3F))); + } else if (codepoint <= 0xFFFF) { + result.push_back(static_cast(0xE0 | (codepoint >> 12))); + result.push_back(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + result.push_back(static_cast(0x80 | (codepoint & 0x3F))); + } else { + result.push_back(static_cast(0xF0 | (codepoint >> 18))); + result.push_back(static_cast(0x80 | ((codepoint >> 12) & 0x3F))); + result.push_back(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + result.push_back(static_cast(0x80 | (codepoint & 0x3F))); + } + } + return result; } std::u16string UTF8ToUTF16(std::string_view input) { - std::wstring_convert, char16_t> convert; - return convert.from_bytes(input.data(), input.data() + input.size()); + std::u16string result; + size_t i = 0; + while (i < input.size()) { + uint32_t codepoint = 0; + unsigned char c = input[i]; + size_t extra = 0; + if ((c & 0x80) == 0) { + codepoint = c; + extra = 0; + } else if ((c & 0xE0) == 0xC0) { + codepoint = c & 0x1F; + extra = 1; + } else if ((c & 0xF0) == 0xE0) { + codepoint = c & 0x0F; + extra = 2; + } else if ((c & 0xF8) == 0xF0) { + codepoint = c & 0x07; + extra = 3; + } else { + // Invalid UTF-8 + ++i; + continue; + } + if (i + extra >= input.size()) break; + for (size_t j = 1; j <= extra; ++j) { + if ((input[i + j] & 0xC0) != 0x80) { + codepoint = 0xFFFD; + break; + } + codepoint = (codepoint << 6) | (input[i + j] & 0x3F); + } + if (codepoint <= 0xFFFF) { + result.push_back(static_cast(codepoint)); + } else { + codepoint -= 0x10000; + result.push_back(static_cast(0xD800 + (codepoint >> 10))); + result.push_back(static_cast(0xDC00 + (codepoint & 0x3FF))); + } + i += extra + 1; + } + return result; } std::u32string UTF8ToUTF32(std::string_view input) { - std::wstring_convert, char32_t> convert; - return convert.from_bytes(input.data(), input.data() + input.size()); + std::u32string result; + size_t i = 0; + while (i < input.size()) { + uint32_t codepoint = 0; + unsigned char c = input[i]; + size_t extra = 0; + if ((c & 0x80) == 0) { + codepoint = c; + extra = 0; + } else if ((c & 0xE0) == 0xC0) { + codepoint = c & 0x1F; + extra = 1; + } else if ((c & 0xF0) == 0xE0) { + codepoint = c & 0x0F; + extra = 2; + } else if ((c & 0xF8) == 0xF0) { + codepoint = c & 0x07; + extra = 3; + } else { + // Invalid UTF-8 + ++i; + continue; + } + if (i + extra >= input.size()) break; + for (size_t j = 1; j <= extra; ++j) { + if ((input[i + j] & 0xC0) != 0x80) { + codepoint = 0xFFFD; + break; + } + codepoint = (codepoint << 6) | (input[i + j] & 0x3F); + } + result.push_back(codepoint); + i += extra + 1; + } + return result; } #ifdef _WIN32 diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 3ff901abf3..a2f595540d 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1273,7 +1273,9 @@ endif() target_sources(core PRIVATE hle/service/ssl/ssl_backend_openssl.cpp) target_link_libraries(core PRIVATE OpenSSL::SSL OpenSSL::Crypto) -target_compile_definitions(core PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT) +if (NOT IOS) + target_compile_definitions(core PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT) +endif() # TODO diff --git a/src/core/hle/service/bcat/news/builtin_news.cpp b/src/core/hle/service/bcat/news/builtin_news.cpp index ed001b056b..f7cc6c5a23 100644 --- a/src/core/hle/service/bcat/news/builtin_news.cpp +++ b/src/core/hle/service/bcat/news/builtin_news.cpp @@ -37,7 +37,7 @@ namespace Service::News { namespace { -constexpr const char* GitHubAPI_EdenReleases = "/repos/eden-emulator/Releases/releases"; +[[maybe_unused]] constexpr const char* GitHubAPI_EdenReleases = "/repos/eden-emulator/Releases/releases"; // Cached logo data std::vector default_logo_small; diff --git a/src/frontend_common/CMakeLists.txt b/src/frontend_common/CMakeLists.txt index a6d580cb18..b1554d7dba 100644 --- a/src/frontend_common/CMakeLists.txt +++ b/src/frontend_common/CMakeLists.txt @@ -22,9 +22,10 @@ if (ENABLE_UPDATE_CHECKER) target_sources(frontend_common PRIVATE update_checker.cpp update_checker.h) - - target_compile_definitions(frontend_common PUBLIC CPPHTTPLIB_OPENSSL_SUPPORT) target_link_libraries(frontend_common PRIVATE OpenSSL::SSL OpenSSL::Crypto) + if (NOT IOS) + target_compile_definitions(frontend_common PUBLIC CPPHTTPLIB_OPENSSL_SUPPORT) + endif() endif() create_target_directory_groups(frontend_common) diff --git a/src/ios/CMakeLists.txt b/src/ios/CMakeLists.txt index dc2f8b53fc..8d91aa9590 100644 --- a/src/ios/CMakeLists.txt +++ b/src/ios/CMakeLists.txt @@ -18,6 +18,10 @@ add_executable(eden-ios EmulationWindow.mm ) +# Keep identifier as-is, for compatibility sake +set_property(TARGET eden-ios PROPERTY XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.yuzu-emu.yuzu") +set_property(TARGET eden-ios PROPERTY XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "YUZU1234") + target_link_libraries(eden-ios PRIVATE common core input_common frontend_common video_core glad) target_link_libraries(eden-ios PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) target_link_libraries(eden-ios PRIVATE SDL2::SDL2) diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index 904b03d288..f7614c506a 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -50,7 +50,9 @@ if (USE_DISCORD_PRESENCE) if (YUZU_USE_BUNDLED_OPENSSL) target_link_libraries(qt_common PUBLIC OpenSSL::SSL OpenSSL::Crypto) - target_compile_definitions(qt_common PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT) + if (NOT IOS) + target_compile_definitions(qt_common PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT) + endif() endif() target_compile_definitions(qt_common PUBLIC USE_DISCORD_PRESENCE) diff --git a/src/web_service/CMakeLists.txt b/src/web_service/CMakeLists.txt index 0dedad16f7..957b935f37 100644 --- a/src/web_service/CMakeLists.txt +++ b/src/web_service/CMakeLists.txt @@ -17,6 +17,27 @@ create_target_directory_groups(web_service) target_include_directories(web_service PUBLIC ${cpp-jwt_SOURCE_DIR}/include) target_link_libraries(web_service PRIVATE common network nlohmann_json::nlohmann_json httplib::httplib cpp-jwt::cpp-jwt) -find_package(OpenSSL REQUIRED) -target_link_libraries(web_service PRIVATE OpenSSL::SSL OpenSSL::Crypto) -target_compile_definitions(web_service PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT) +if (IOS) + # TODO: this is horrific + find_package(OpenSSL 3 QUIET) + if (OpenSSL_FOUND) + target_link_libraries(web_service PRIVATE OpenSSL::SSL OpenSSL::Crypto) + if (NOT IOS) + target_compile_definitions(web_service PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT) + endif() + else() + find_package(OpenSSL 3 QUIET PATHS /usr/local/opt/openssl /opt/homebrew/opt/openssl NO_DEFAULT_PATH) + if (OpenSSL_FOUND) + target_link_libraries(web_service PRIVATE OpenSSL::SSL OpenSSL::Crypto) + if (NOT IOS) + target_compile_definitions(web_service PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT) + endif() + else() + message(WARNING "OpenSSL not found or version is less than 3. Some features in web_service may be disabled.") + endif() + endif() +else() + find_package(OpenSSL REQUIRED) + target_link_libraries(web_service PRIVATE OpenSSL::SSL OpenSSL::Crypto) + target_compile_definitions(web_service PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT) +endif() From fdc42e7e1abd40e3777611926ee7381282ce24a5 Mon Sep 17 00:00:00 2001 From: lizzie Date: Tue, 24 Mar 2026 22:43:02 +0000 Subject: [PATCH 33/54] [temporary c++ shit] --- externals/stb/stb_image_write.h | 707 +----------------- src/core/arm/dynarmic/arm_dynarmic.h | 2 +- src/core/arm/dynarmic/arm_dynarmic_32.h | 4 +- src/core/arm/dynarmic/arm_dynarmic_64.h | 12 +- .../arm/dynarmic/dynarmic_exclusive_monitor.h | 2 +- src/dynarmic/src/dynarmic/interface/A32/a32.h | 4 +- .../src/dynarmic/interface/A32/config.h | 6 +- src/dynarmic/src/dynarmic/interface/A64/a64.h | 4 +- .../src/dynarmic/interface/A64/config.h | 2 +- .../dynarmic/interface/exclusive_monitor.h | 2 +- 10 files changed, 20 insertions(+), 725 deletions(-) diff --git a/externals/stb/stb_image_write.h b/externals/stb/stb_image_write.h index e4b32ed1bc..badacf6c5f 100644 --- a/externals/stb/stb_image_write.h +++ b/externals/stb/stb_image_write.h @@ -391,11 +391,6 @@ static void stbiw__write_flush(stbi__write_context *s) } } -static void stbiw__putc(stbi__write_context *s, unsigned char c) -{ - s->func(s->context, &c, 1); -} - static void stbiw__write1(stbi__write_context *s, unsigned char a) { if ((size_t)s->buf_used + 1 > sizeof(s->buffer)) @@ -773,7 +768,7 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f #ifdef __STDC_LIB_EXT1__ len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #else - len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); + len = 0; // #endif s->func(s->context, buffer, len); @@ -1021,704 +1016,4 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i #endif // STBIW_ZLIB_COMPRESS } -static unsigned int stbiw__crc32(unsigned char *buffer, int len) -{ -#ifdef STBIW_CRC32 - return STBIW_CRC32(buffer, len); -#else - static unsigned int crc_table[256] = - { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D - }; - - unsigned int crc = ~0u; - int i; - for (i=0; i < len; ++i) - crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; - return ~crc; -#endif -} - -#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) -#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); -#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) - -static void stbiw__wpcrc(unsigned char **data, int len) -{ - unsigned int crc = stbiw__crc32(*data - len - 4, len+4); - stbiw__wp32(*data, crc); -} - -static unsigned char stbiw__paeth(int a, int b, int c) -{ - int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); - if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); - if (pb <= pc) return STBIW_UCHAR(b); - return STBIW_UCHAR(c); -} - -// @OPTIMIZE: provide an option that always forces left-predict or paeth predict -static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer) -{ - static int mapping[] = { 0,1,2,3,4 }; - static int firstmap[] = { 0,1,0,5,6 }; - int *mymap = (y != 0) ? mapping : firstmap; - int i; - int type = mymap[filter_type]; - unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); - int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; - - if (type==0) { - memcpy(line_buffer, z, width*n); - return; - } - - // first loop isn't optimized since it's just one pixel - for (i = 0; i < n; ++i) { - switch (type) { - case 1: line_buffer[i] = z[i]; break; - case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; - case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; - case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; - case 5: line_buffer[i] = z[i]; break; - case 6: line_buffer[i] = z[i]; break; - } - } - switch (type) { - case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; - case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; - case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; - case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; - case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; - case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; - } -} - -STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) -{ - int force_filter = stbi_write_force_png_filter; - int ctype[5] = { -1, 0, 4, 2, 6 }; - unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; - unsigned char *out,*o, *filt, *zlib; - signed char *line_buffer; - int j,zlen; - - if (stride_bytes == 0) - stride_bytes = x * n; - - if (force_filter >= 5) { - force_filter = -1; - } - - filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; - line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } - for (j=0; j < y; ++j) { - int filter_type; - if (force_filter > -1) { - filter_type = force_filter; - stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); - } else { // Estimate the best filter by running through all of them: - int best_filter = 0, best_filter_val = 0x7fffffff, est, i; - for (filter_type = 0; filter_type < 5; filter_type++) { - stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); - - // Estimate the entropy of the line using this filter; the less, the better. - est = 0; - for (i = 0; i < x*n; ++i) { - est += abs((signed char) line_buffer[i]); - } - if (est < best_filter_val) { - best_filter_val = est; - best_filter = filter_type; - } - } - if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it - stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); - filter_type = best_filter; - } - } - // when we get here, filter_type contains the filter type, and line_buffer contains the data - filt[j*(x*n+1)] = (unsigned char) filter_type; - STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); - } - STBIW_FREE(line_buffer); - zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); - STBIW_FREE(filt); - if (!zlib) return 0; - - // each tag requires 12 bytes of overhead - out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); - if (!out) return 0; - *out_len = 8 + 12+13 + 12+zlen + 12; - - o=out; - STBIW_MEMMOVE(o,sig,8); o+= 8; - stbiw__wp32(o, 13); // header length - stbiw__wptag(o, "IHDR"); - stbiw__wp32(o, x); - stbiw__wp32(o, y); - *o++ = 8; - *o++ = STBIW_UCHAR(ctype[n]); - *o++ = 0; - *o++ = 0; - *o++ = 0; - stbiw__wpcrc(&o,13); - - stbiw__wp32(o, zlen); - stbiw__wptag(o, "IDAT"); - STBIW_MEMMOVE(o, zlib, zlen); - o += zlen; - STBIW_FREE(zlib); - stbiw__wpcrc(&o, zlen); - - stbiw__wp32(o,0); - stbiw__wptag(o, "IEND"); - stbiw__wpcrc(&o,0); - - STBIW_ASSERT(o == out + *out_len); - - return out; -} - -#ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) -{ - FILE *f; - int len; - unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); - if (png == NULL) return 0; - - f = stbiw__fopen(filename, "wb"); - if (!f) { STBIW_FREE(png); return 0; } - fwrite(png, 1, len, f); - fclose(f); - STBIW_FREE(png); - return 1; -} -#endif - -STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) -{ - int len; - unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); - if (png == NULL) return 0; - func(context, png, len); - STBIW_FREE(png); - return 1; -} - - -/* *************************************************************************** - * - * JPEG writer - * - * This is based on Jon Olick's jo_jpeg.cpp: - * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html - */ - -static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18, - 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; - -static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) { - int bitBuf = *bitBufP, bitCnt = *bitCntP; - bitCnt += bs[1]; - bitBuf |= bs[0] << (24 - bitCnt); - while(bitCnt >= 8) { - unsigned char c = (bitBuf >> 16) & 255; - stbiw__putc(s, c); - if(c == 255) { - stbiw__putc(s, 0); - } - bitBuf <<= 8; - bitCnt -= 8; - } - *bitBufP = bitBuf; - *bitCntP = bitCnt; -} - -static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) { - float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; - float z1, z2, z3, z4, z5, z11, z13; - - float tmp0 = d0 + d7; - float tmp7 = d0 - d7; - float tmp1 = d1 + d6; - float tmp6 = d1 - d6; - float tmp2 = d2 + d5; - float tmp5 = d2 - d5; - float tmp3 = d3 + d4; - float tmp4 = d3 - d4; - - // Even part - float tmp10 = tmp0 + tmp3; // phase 2 - float tmp13 = tmp0 - tmp3; - float tmp11 = tmp1 + tmp2; - float tmp12 = tmp1 - tmp2; - - d0 = tmp10 + tmp11; // phase 3 - d4 = tmp10 - tmp11; - - z1 = (tmp12 + tmp13) * 0.707106781f; // c4 - d2 = tmp13 + z1; // phase 5 - d6 = tmp13 - z1; - - // Odd part - tmp10 = tmp4 + tmp5; // phase 2 - tmp11 = tmp5 + tmp6; - tmp12 = tmp6 + tmp7; - - // The rotator is modified from fig 4-8 to avoid extra negations. - z5 = (tmp10 - tmp12) * 0.382683433f; // c6 - z2 = tmp10 * 0.541196100f + z5; // c2-c6 - z4 = tmp12 * 1.306562965f + z5; // c2+c6 - z3 = tmp11 * 0.707106781f; // c4 - - z11 = tmp7 + z3; // phase 5 - z13 = tmp7 - z3; - - *d5p = z13 + z2; // phase 6 - *d3p = z13 - z2; - *d1p = z11 + z4; - *d7p = z11 - z4; - - *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6; -} - -static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { - int tmp1 = val < 0 ? -val : val; - val = val < 0 ? val-1 : val; - bits[1] = 1; - while(tmp1 >>= 1) { - ++bits[1]; - } - bits[0] = val & ((1<0)&&(DU[end0pos]==0); --end0pos) { - } - // end0pos = first element in reverse order !=0 - if(end0pos == 0) { - stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); - return DU[0]; - } - for(i = 1; i <= end0pos; ++i) { - int startpos = i; - int nrzeroes; - unsigned short bits[2]; - for (; DU[i]==0 && i<=end0pos; ++i) { - } - nrzeroes = i-startpos; - if ( nrzeroes >= 16 ) { - int lng = nrzeroes>>4; - int nrmarker; - for (nrmarker=1; nrmarker <= lng; ++nrmarker) - stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); - nrzeroes &= 15; - } - stbiw__jpg_calcBits(DU[i], bits); - stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); - stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); - } - if(end0pos != 63) { - stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); - } - return DU[0]; -} - -static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) { - // Constants that don't pollute global namespace - static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; - static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; - static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; - static const unsigned char std_ac_luminance_values[] = { - 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, - 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, - 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, - 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, - 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, - 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, - 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa - }; - static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; - static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; - static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; - static const unsigned char std_ac_chrominance_values[] = { - 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, - 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, - 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, - 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, - 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, - 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, - 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa - }; - // Huffman tables - static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; - static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; - static const unsigned short YAC_HT[256][2] = { - {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, - {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} - }; - static const unsigned short UVAC_HT[256][2] = { - {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, - {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} - }; - static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22, - 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; - static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, - 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; - static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, - 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; - - int row, col, i, k, subsample; - float fdtbl_Y[64], fdtbl_UV[64]; - unsigned char YTable[64], UVTable[64]; - - if(!data || !width || !height || comp > 4 || comp < 1) { - return 0; - } - - quality = quality ? quality : 90; - subsample = quality <= 90 ? 1 : 0; - quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; - quality = quality < 50 ? 5000 / quality : 200 - quality * 2; - - for(i = 0; i < 64; ++i) { - int uvti, yti = (YQT[i]*quality+50)/100; - YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti); - uvti = (UVQT[i]*quality+50)/100; - UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); - } - - for(row = 0, k = 0; row < 8; ++row) { - for(col = 0; col < 8; ++col, ++k) { - fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); - fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); - } - } - - // Write Headers - { - static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; - static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; - const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), - 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; - s->func(s->context, (void*)head0, sizeof(head0)); - s->func(s->context, (void*)YTable, sizeof(YTable)); - stbiw__putc(s, 1); - s->func(s->context, UVTable, sizeof(UVTable)); - s->func(s->context, (void*)head1, sizeof(head1)); - s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1); - s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values)); - stbiw__putc(s, 0x10); // HTYACinfo - s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1); - s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values)); - stbiw__putc(s, 1); // HTUDCinfo - s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1); - s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); - stbiw__putc(s, 0x11); // HTUACinfo - s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1); - s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); - s->func(s->context, (void*)head2, sizeof(head2)); - } - - // Encode 8x8 macroblocks - { - static const unsigned short fillBits[] = {0x7F, 7}; - int DCY=0, DCU=0, DCV=0; - int bitBuf=0, bitCnt=0; - // comp == 2 is grey+alpha (alpha is ignored) - int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; - const unsigned char *dataR = (const unsigned char *)data; - const unsigned char *dataG = dataR + ofsG; - const unsigned char *dataB = dataR + ofsB; - int x, y, pos; - if(subsample) { - for(y = 0; y < height; y += 16) { - for(x = 0; x < width; x += 16) { - float Y[256], U[256], V[256]; - for(row = y, pos = 0; row < y+16; ++row) { - // row >= height => use last input row - int clamped_row = (row < height) ? row : height - 1; - int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; - for(col = x; col < x+16; ++col, ++pos) { - // if col >= width => use pixel from last input column - int p = base_p + ((col < width) ? col : (width-1))*comp; - float r = dataR[p], g = dataG[p], b = dataB[p]; - Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; - U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; - V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; - } - } - DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); - DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); - DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); - DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); - - // subsample U,V - { - float subU[64], subV[64]; - int yy, xx; - for(yy = 0, pos = 0; yy < 8; ++yy) { - for(xx = 0; xx < 8; ++xx, ++pos) { - int j = yy*32+xx*2; - subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; - subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; - } - } - DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); - DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); - } - } - } - } else { - for(y = 0; y < height; y += 8) { - for(x = 0; x < width; x += 8) { - float Y[64], U[64], V[64]; - for(row = y, pos = 0; row < y+8; ++row) { - // row >= height => use last input row - int clamped_row = (row < height) ? row : height - 1; - int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; - for(col = x; col < x+8; ++col, ++pos) { - // if col >= width => use pixel from last input column - int p = base_p + ((col < width) ? col : (width-1))*comp; - float r = dataR[p], g = dataG[p], b = dataB[p]; - Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; - U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; - V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; - } - } - - DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT); - DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); - DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); - } - } - } - - // Do the bit alignment of the EOI marker - stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); - } - - // EOI - stbiw__putc(s, 0xFF); - stbiw__putc(s, 0xD9); - - return 1; -} - -STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) -{ - stbi__write_context s = { 0 }; - stbi__start_write_callbacks(&s, func, context); - return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); -} - - -#ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) -{ - stbi__write_context s = { 0 }; - if (stbi__start_write_file(&s,filename)) { - int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); - stbi__end_write_file(&s); - return r; - } else - return 0; -} -#endif - #endif // STB_IMAGE_WRITE_IMPLEMENTATION - -/* Revision history - 1.16 (2021-07-11) - make Deflate code emit uncompressed blocks when it would otherwise expand - support writing BMPs with alpha channel - 1.15 (2020-07-13) unknown - 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels - 1.13 - 1.12 - 1.11 (2019-08-11) - - 1.10 (2019-02-07) - support utf8 filenames in Windows; fix warnings and platform ifdefs - 1.09 (2018-02-11) - fix typo in zlib quality API, improve STB_I_W_STATIC in C++ - 1.08 (2018-01-29) - add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter - 1.07 (2017-07-24) - doc fix - 1.06 (2017-07-23) - writing JPEG (using Jon Olick's code) - 1.05 ??? - 1.04 (2017-03-03) - monochrome BMP expansion - 1.03 ??? - 1.02 (2016-04-02) - avoid allocating large structures on the stack - 1.01 (2016-01-16) - STBIW_REALLOC_SIZED: support allocators with no realloc support - avoid race-condition in crc initialization - minor compile issues - 1.00 (2015-09-14) - installable file IO function - 0.99 (2015-09-13) - warning fixes; TGA rle support - 0.98 (2015-04-08) - added STBIW_MALLOC, STBIW_ASSERT etc - 0.97 (2015-01-18) - fixed HDR asserts, rewrote HDR rle logic - 0.96 (2015-01-17) - add HDR output - fix monochrome BMP - 0.95 (2014-08-17) - add monochrome TGA output - 0.94 (2014-05-31) - rename private functions to avoid conflicts with stb_image.h - 0.93 (2014-05-27) - warning fixes - 0.92 (2010-08-01) - casts to unsigned char to fix warnings - 0.91 (2010-07-17) - first public release - 0.90 first internal release -*/ - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, -commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to -this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------- -*/ diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index 0fb4e9701d..fbf46b1268 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h @@ -4,7 +4,7 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "dynarmic/interface/halt_reason.h" +#include "dynarmic/src/dynarmic/interface/halt_reason.h" #include "core/arm/arm_interface.h" diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index 011751c53d..9e55d8c27a 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -6,8 +6,8 @@ #pragma once -#include "dynarmic/interface/A32/a32.h" -#include "dynarmic/interface/code_page.h" +#include "dynarmic/src/dynarmic/interface/A32/a32.h" +#include "dynarmic/src/dynarmic/interface/code_page.h" #include "core/arm/arm_interface.h" #include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index b95462be15..14b28a237b 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -10,12 +10,12 @@ #include #include -#include "dynarmic/interface/A64/a64.h" -#include "dynarmic/interface/code_page.h" -#include "common/common_types.h" -#include "common/hash.h" -#include "core/arm/arm_interface.h" -#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" +#include "../../../dynarmic/src/dynarmic/interface/A64/a64.h" +#include "../../../dynarmic/src/dynarmic/interface/code_page.h" +#include "../../../common/common_types.h" +#include "../../../common/hash.h" +#include "../arm_interface.h" +#include "dynarmic_exclusive_monitor.h" namespace Core::Memory { class Memory; diff --git a/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h index 2362dad90e..d7c960307c 100644 --- a/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h +++ b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h @@ -3,7 +3,7 @@ #pragma once -#include "dynarmic/interface/exclusive_monitor.h" +#include "dynarmic/src/dynarmic/interface/exclusive_monitor.h" #include "common/common_types.h" #include "core/arm/exclusive_monitor.h" diff --git a/src/dynarmic/src/dynarmic/interface/A32/a32.h b/src/dynarmic/src/dynarmic/interface/A32/a32.h index bc30b59c1e..200163bf65 100644 --- a/src/dynarmic/src/dynarmic/interface/A32/a32.h +++ b/src/dynarmic/src/dynarmic/interface/A32/a32.h @@ -14,8 +14,8 @@ #include #include -#include "dynarmic/interface/A32/config.h" -#include "dynarmic/interface/halt_reason.h" +#include "config.h" +#include "dynarmic/src/dynarmic/interface/halt_reason.h" namespace Dynarmic { namespace A32 { diff --git a/src/dynarmic/src/dynarmic/interface/A32/config.h b/src/dynarmic/src/dynarmic/interface/A32/config.h index 5a97fb69f3..9f1f5cc0cd 100644 --- a/src/dynarmic/src/dynarmic/interface/A32/config.h +++ b/src/dynarmic/src/dynarmic/interface/A32/config.h @@ -14,9 +14,9 @@ #include #include -#include "dynarmic/frontend/A32/translate/translate_callbacks.h" -#include "dynarmic/interface/A32/arch_version.h" -#include "dynarmic/interface/optimization_flags.h" +#include "../../frontend/A32/translate/translate_callbacks.h" +#include "arch_version.h" +#include "../optimization_flags.h" namespace Dynarmic { class ExclusiveMonitor; diff --git a/src/dynarmic/src/dynarmic/interface/A64/a64.h b/src/dynarmic/src/dynarmic/interface/A64/a64.h index e8d2352702..3674d74867 100644 --- a/src/dynarmic/src/dynarmic/interface/A64/a64.h +++ b/src/dynarmic/src/dynarmic/interface/A64/a64.h @@ -15,8 +15,8 @@ #include #include -#include "dynarmic/interface/A64/config.h" -#include "dynarmic/interface/halt_reason.h" +#include "config.h" +#include "../halt_reason.h" namespace Dynarmic { namespace A64 { diff --git a/src/dynarmic/src/dynarmic/interface/A64/config.h b/src/dynarmic/src/dynarmic/interface/A64/config.h index 83c1593fd8..f6d340c47f 100644 --- a/src/dynarmic/src/dynarmic/interface/A64/config.h +++ b/src/dynarmic/src/dynarmic/interface/A64/config.h @@ -14,7 +14,7 @@ #include #include -#include "dynarmic/interface/optimization_flags.h" +#include "../optimization_flags.h" namespace Dynarmic { class ExclusiveMonitor; diff --git a/src/dynarmic/src/dynarmic/interface/exclusive_monitor.h b/src/dynarmic/src/dynarmic/interface/exclusive_monitor.h index 0d35716c4c..7549dbb26d 100644 --- a/src/dynarmic/src/dynarmic/interface/exclusive_monitor.h +++ b/src/dynarmic/src/dynarmic/interface/exclusive_monitor.h @@ -11,7 +11,7 @@ #include #include -#include "dynarmic/common/spin_lock.h" +#include "dynarmic/src/dynarmic/common/spin_lock.h" namespace Dynarmic { From 353839cfeff56f0b8b5316c204fcc1ee6e51d63c Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 25 Mar 2026 00:30:56 +0000 Subject: [PATCH 34/54] license --- CMakeLists.txt | 3 +++ src/common/string_util.cpp | 2 +- src/core/arm/dynarmic/arm_dynarmic.h | 2 +- src/core/arm/dynarmic/dynarmic_cp15.h | 3 +++ src/core/arm/dynarmic/dynarmic_exclusive_monitor.h | 3 +++ src/core/arm/nce/visitor_base.h | 3 +++ src/dynarmic/src/dynarmic/interface/A32/a32.h | 2 +- src/dynarmic/src/dynarmic/interface/A64/a64.h | 2 +- src/dynarmic/src/dynarmic/interface/exclusive_monitor.h | 3 +++ src/web_service/CMakeLists.txt | 3 +++ 10 files changed, 22 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 80b0e59b14..2e8b822e4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + cmake_minimum_required(VERSION 3.22) project(yuzu) diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 2588624d4c..a209ac3600 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: 2013 Dolphin Emulator Project diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index fbf46b1268..abae046d3c 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project diff --git a/src/core/arm/dynarmic/dynarmic_cp15.h b/src/core/arm/dynarmic/dynarmic_cp15.h index e4de20d578..5cec5d0060 100644 --- a/src/core/arm/dynarmic/dynarmic_cp15.h +++ b/src/core/arm/dynarmic/dynarmic_cp15.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2017 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h index d7c960307c..5beb40c325 100644 --- a/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h +++ b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/core/arm/nce/visitor_base.h b/src/core/arm/nce/visitor_base.h index 1feae327c0..65741bedac 100644 --- a/src/core/arm/nce/visitor_base.h +++ b/src/core/arm/nce/visitor_base.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 merryhime // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/dynarmic/src/dynarmic/interface/A32/a32.h b/src/dynarmic/src/dynarmic/interface/A32/a32.h index 200163bf65..00e9e045ef 100644 --- a/src/dynarmic/src/dynarmic/interface/A32/a32.h +++ b/src/dynarmic/src/dynarmic/interface/A32/a32.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. diff --git a/src/dynarmic/src/dynarmic/interface/A64/a64.h b/src/dynarmic/src/dynarmic/interface/A64/a64.h index 3674d74867..86c24b02a1 100644 --- a/src/dynarmic/src/dynarmic/interface/A64/a64.h +++ b/src/dynarmic/src/dynarmic/interface/A64/a64.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later /* This file is part of the dynarmic project. diff --git a/src/dynarmic/src/dynarmic/interface/exclusive_monitor.h b/src/dynarmic/src/dynarmic/interface/exclusive_monitor.h index 7549dbb26d..9315563888 100644 --- a/src/dynarmic/src/dynarmic/interface/exclusive_monitor.h +++ b/src/dynarmic/src/dynarmic/interface/exclusive_monitor.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + /* This file is part of the dynarmic project. * Copyright (c) 2018 MerryMage * SPDX-License-Identifier: 0BSD diff --git a/src/web_service/CMakeLists.txt b/src/web_service/CMakeLists.txt index 957b935f37..0b749bb216 100644 --- a/src/web_service/CMakeLists.txt +++ b/src/web_service/CMakeLists.txt @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # SPDX-FileCopyrightText: 2018 yuzu Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later From 5296cdf75e22db9801655e075b4548165244c4da Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 25 Mar 2026 00:31:57 +0000 Subject: [PATCH 35/54] fix swift driver I HOPE --- src/ios/CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ios/CMakeLists.txt b/src/ios/CMakeLists.txt index 8d91aa9590..ede2211f46 100644 --- a/src/ios/CMakeLists.txt +++ b/src/ios/CMakeLists.txt @@ -27,7 +27,8 @@ target_link_libraries(eden-ios PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) target_link_libraries(eden-ios PRIVATE SDL2::SDL2) create_target_directory_groups(eden-ios) target_compile_options(eden-ios PRIVATE - -Wno-conversion - -Wno-unused-variable - -Wno-unused-parameter - -Wno-missing-field-initializers) + $<$:-Wno-conversion> + $<$:-Wno-unused-variable> + $<$:-Wno-unused-parameter> + $<$:-Wno-missing-field-initializers> +) From c5a3fade43059efe95fdecf862f6e2350642116f Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 25 Mar 2026 00:54:31 +0000 Subject: [PATCH 36/54] properly use bridging header, fix headers --- src/ios/AppUI-Bridging-Header.h | 7 ++----- src/ios/AppUI.swift | 8 +++----- src/ios/AppUIGameInformation.h | 7 ++----- src/ios/AppUIGameInformation.mm | 7 ++----- src/ios/AppUIObjC.h | 7 ++----- src/ios/AppUIObjC.mm | 7 ++----- src/ios/CMakeLists.txt | 9 ++++++--- src/ios/EmulationSession.h | 7 ++----- src/ios/EmulationSession.mm | 7 ++----- src/ios/EmulationWindow.h | 7 ++----- src/ios/EmulationWindow.mm | 7 ++----- 11 files changed, 27 insertions(+), 53 deletions(-) diff --git a/src/ios/AppUI-Bridging-Header.h b/src/ios/AppUI-Bridging-Header.h index d3bc77082f..00fadaa6dc 100644 --- a/src/ios/AppUI-Bridging-Header.h +++ b/src/ios/AppUI-Bridging-Header.h @@ -1,10 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later - -// -// AppUI-Bridging-Header.h - Sudachi -// Created by Jarrod Norwell on 4/3/2024. -// +// SPDX-FileCopyrightText: Copyright 2024 Jarrod Norwell +// SPDX-License-Identifier: GPL-2.0-or-later #ifndef AppUI_Bridging_Header_h #define AppUI_Bridging_Header_h diff --git a/src/ios/AppUI.swift b/src/ios/AppUI.swift index 0dd7ac4dd8..b1d95324cc 100644 --- a/src/ios/AppUI.swift +++ b/src/ios/AppUI.swift @@ -1,11 +1,9 @@ // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Jarrod Norwell +// SPDX-License-Identifier: GPL-2.0-or-later -// -// AppUI.swift - Sudachi -// Created by Jarrod Norwell on 4/3/2024. -// - +import UIKit import Foundation import QuartzCore.CAMetalLayer diff --git a/src/ios/AppUIGameInformation.h b/src/ios/AppUIGameInformation.h index ef8537faee..1a602956c3 100644 --- a/src/ios/AppUIGameInformation.h +++ b/src/ios/AppUIGameInformation.h @@ -1,10 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later - -// -// AppUIGameInformation.h - Sudachi -// Created by Jarrod Norwell on 1/20/24. -// +// SPDX-FileCopyrightText: Copyright 2024 Jarrod Norwell +// SPDX-License-Identifier: GPL-2.0-or-later #import diff --git a/src/ios/AppUIGameInformation.mm b/src/ios/AppUIGameInformation.mm index 4b69324420..713494dfac 100644 --- a/src/ios/AppUIGameInformation.mm +++ b/src/ios/AppUIGameInformation.mm @@ -1,10 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later - -// -// AppUIGameInformation.mm - Sudachi -// Created by Jarrod Norwell on 1/20/24. -// +// SPDX-FileCopyrightText: Copyright 2024 Jarrod Norwell +// SPDX-License-Identifier: GPL-2.0-or-later #import #import "AppUIGameInformation.h" diff --git a/src/ios/AppUIObjC.h b/src/ios/AppUIObjC.h index ec5a5f1e8c..921f333199 100644 --- a/src/ios/AppUIObjC.h +++ b/src/ios/AppUIObjC.h @@ -1,10 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later - -// -// AppUIObjC.h - Sudachi -// Created by Jarrod Norwell on 1/8/24. -// +// SPDX-FileCopyrightText: Copyright 2024 Jarrod Norwell +// SPDX-License-Identifier: GPL-2.0-or-later #import #import diff --git a/src/ios/AppUIObjC.mm b/src/ios/AppUIObjC.mm index c03a20c530..5cd7f72b21 100644 --- a/src/ios/AppUIObjC.mm +++ b/src/ios/AppUIObjC.mm @@ -1,10 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later - -// -// AppUIObjC.mm - Sudachi -// Created by Jarrod Norwell on 1/8/24. -// +// SPDX-FileCopyrightText: Copyright 2024 Jarrod Norwell +// SPDX-License-Identifier: GPL-2.0-or-later #import "AppUIObjC.h" diff --git a/src/ios/CMakeLists.txt b/src/ios/CMakeLists.txt index ede2211f46..9c16277609 100644 --- a/src/ios/CMakeLists.txt +++ b/src/ios/CMakeLists.txt @@ -18,9 +18,12 @@ add_executable(eden-ios EmulationWindow.mm ) -# Keep identifier as-is, for compatibility sake -set_property(TARGET eden-ios PROPERTY XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.yuzu-emu.yuzu") -set_property(TARGET eden-ios PROPERTY XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "YUZU1234") +# Keep bundle identifier as-is, for compatibility sake +set_target_properties(eden-ios PROPERTIES + XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.yuzu-emu.yuzu" + XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "YUZU1234" + SWIFT_OBJC_BRIDGING_HEADER "AppUI-Bridging-Header.h" +) target_link_libraries(eden-ios PRIVATE common core input_common frontend_common video_core glad) target_link_libraries(eden-ios PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) diff --git a/src/ios/EmulationSession.h b/src/ios/EmulationSession.h index 287a65839d..c6bce5e4dd 100644 --- a/src/ios/EmulationSession.h +++ b/src/ios/EmulationSession.h @@ -1,10 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later - -// -// EmulationSession.h - Sudachi -// Created by Jarrod Norwell on 1/20/24. -// +// SPDX-FileCopyrightText: Copyright 2024 Jarrod Norwell +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/ios/EmulationSession.mm b/src/ios/EmulationSession.mm index 9b4171e082..16f0709d8a 100644 --- a/src/ios/EmulationSession.mm +++ b/src/ios/EmulationSession.mm @@ -1,10 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later - -// -// EmulationSession.m - Sudachi -// Created by Jarrod Norwell on 1/20/24. -// +// SPDX-FileCopyrightText: Copyright 2024 Jarrod Norwell +// SPDX-License-Identifier: GPL-2.0-or-later #import "EmulationSession.h" diff --git a/src/ios/EmulationWindow.h b/src/ios/EmulationWindow.h index 53162a7f58..8d285ab33e 100644 --- a/src/ios/EmulationWindow.h +++ b/src/ios/EmulationWindow.h @@ -1,10 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later - -// -// EmulationWindow.h - Sudachi -// Created by Jarrod Norwell on 1/18/24. -// +// SPDX-FileCopyrightText: Copyright 2024 Jarrod Norwell +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/ios/EmulationWindow.mm b/src/ios/EmulationWindow.mm index 638db800a8..4ed6f84c81 100644 --- a/src/ios/EmulationWindow.mm +++ b/src/ios/EmulationWindow.mm @@ -1,10 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later - -// -// EmulationWindow.mm - Sudachi -// Created by Jarrod Norwell on 1/18/24. -// +// SPDX-FileCopyrightText: Copyright 2024 Jarrod Norwell +// SPDX-License-Identifier: GPL-2.0-or-later #import "EmulationWindow.h" #import "EmulationSession.h" From ebed7a720409eb5e349a4ccdba620523e2b3af2f Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 25 Mar 2026 01:29:58 +0000 Subject: [PATCH 37/54] fix? --- src/ios/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ios/CMakeLists.txt b/src/ios/CMakeLists.txt index 9c16277609..0fb0cbbc2b 100644 --- a/src/ios/CMakeLists.txt +++ b/src/ios/CMakeLists.txt @@ -22,7 +22,7 @@ add_executable(eden-ios set_target_properties(eden-ios PROPERTIES XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.yuzu-emu.yuzu" XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "YUZU1234" - SWIFT_OBJC_BRIDGING_HEADER "AppUI-Bridging-Header.h" + XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "AppUI-Bridging-Header.h" ) target_link_libraries(eden-ios PRIVATE common core input_common frontend_common video_core glad) From 75a04e8aa37548f469bc02fbd08b8cd909fd45a3 Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 25 Mar 2026 01:34:15 +0000 Subject: [PATCH 38/54] fix IOS again fucking objc bridge --- src/ios/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ios/CMakeLists.txt b/src/ios/CMakeLists.txt index 0fb0cbbc2b..6322e3ec69 100644 --- a/src/ios/CMakeLists.txt +++ b/src/ios/CMakeLists.txt @@ -22,7 +22,7 @@ add_executable(eden-ios set_target_properties(eden-ios PROPERTIES XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.yuzu-emu.yuzu" XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "YUZU1234" - XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "AppUI-Bridging-Header.h" + XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/AppUI-Bridging-Header.h" ) target_link_libraries(eden-ios PRIVATE common core input_common frontend_common video_core glad) From 080c3590486caac84f0146619c235e125a58f169 Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 25 Mar 2026 02:31:21 +0000 Subject: [PATCH 39/54] fix #include "common/logging.h" --- .ci/ios/build.sh | 2 +- src/ios/AppUIGameInformation.mm | 2 +- src/ios/AppUIObjC.mm | 3 +-- src/ios/EmulationSession.mm | 3 +-- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.ci/ios/build.sh b/.ci/ios/build.sh index fa850f3931..a21e116d66 100755 --- a/.ci/ios/build.sh +++ b/.ci/ios/build.sh @@ -35,4 +35,4 @@ cmake -G Xcode -B build \ -DCPMUTIL_FORCE_BUNDLED=ON \ -DCMAKE_BUILD_TYPE=Release -cmake --build build +cmake --build build -t eden-ios diff --git a/src/ios/AppUIGameInformation.mm b/src/ios/AppUIGameInformation.mm index 713494dfac..5c0e603348 100644 --- a/src/ios/AppUIGameInformation.mm +++ b/src/ios/AppUIGameInformation.mm @@ -73,7 +73,7 @@ public: #define SDL_MAIN_HANDLED #include -#include "common/logging/log.h" +#include "common/logging.h" #include "input_common/main.h" const std::array SdlConfig::default_buttons = { diff --git a/src/ios/AppUIObjC.mm b/src/ios/AppUIObjC.mm index 5cd7f72b21..32bffd43ca 100644 --- a/src/ios/AppUIObjC.mm +++ b/src/ios/AppUIObjC.mm @@ -24,8 +24,7 @@ #include "common/detached_tasks.h" #include "common/dynamic_library.h" #include "common/fs/path_util.h" -#include "common/logging/backend.h" -#include "common/logging/log.h" +#include "common/logging.h" #include "common/scope_exit.h" #include "common/settings.h" #include "common/string_util.h" diff --git a/src/ios/EmulationSession.mm b/src/ios/EmulationSession.mm index 16f0709d8a..9861e0a544 100644 --- a/src/ios/EmulationSession.mm +++ b/src/ios/EmulationSession.mm @@ -22,8 +22,7 @@ #include "common/detached_tasks.h" #include "common/dynamic_library.h" #include "common/fs/path_util.h" -#include "common/logging/backend.h" -#include "common/logging/log.h" +#include "common/logging.h" #include "common/scm_rev.h" #include "common/scope_exit.h" #include "common/settings.h" From ff4bceb2f314a02ef1835d1c9194614d87d40641 Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 25 Mar 2026 03:01:48 +0000 Subject: [PATCH 40/54] fix shit? --- src/ios/CMakeLists.txt | 4 ++-- src/ios/EmulationWindow.mm | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ios/CMakeLists.txt b/src/ios/CMakeLists.txt index 6322e3ec69..f8ec00959d 100644 --- a/src/ios/CMakeLists.txt +++ b/src/ios/CMakeLists.txt @@ -25,9 +25,9 @@ set_target_properties(eden-ios PROPERTIES XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/AppUI-Bridging-Header.h" ) -target_link_libraries(eden-ios PRIVATE common core input_common frontend_common video_core glad) +target_link_libraries(eden-ios PRIVATE common core input_common frontend_common shader_recompiler video_core glad) target_link_libraries(eden-ios PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) -target_link_libraries(eden-ios PRIVATE SDL2::SDL2) +target_link_libraries(eden-ios PRIVATE SDL2::SDL2 sirit::sirit) create_target_directory_groups(eden-ios) target_compile_options(eden-ios PRIVATE $<$:-Wno-conversion> diff --git a/src/ios/EmulationWindow.mm b/src/ios/EmulationWindow.mm index 4ed6f84c81..b917929c2c 100644 --- a/src/ios/EmulationWindow.mm +++ b/src/ios/EmulationWindow.mm @@ -8,7 +8,7 @@ #include -#include "common/logging/log.h" +#include "common/logging.h" #include "input_common/drivers/touch_screen.h" #include "input_common/drivers/virtual_amiibo.h" #include "input_common/drivers/virtual_gamepad.h" From 635785c017c998af81988cb0d7ad85a4a59d634d Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 25 Mar 2026 23:44:56 +0000 Subject: [PATCH 41/54] changes? --- src/ios/CMakeLists.txt | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/ios/CMakeLists.txt b/src/ios/CMakeLists.txt index f8ec00959d..c8f15df3f8 100644 --- a/src/ios/CMakeLists.txt +++ b/src/ios/CMakeLists.txt @@ -2,7 +2,6 @@ # SPDX-License-Identifier: GPL-3.0-or-later enable_language(Swift OBJCXX) - add_executable(eden-ios AppUI-Bridging-Header.h AppUI.swift @@ -17,21 +16,13 @@ add_executable(eden-ios EmulationWindow.h EmulationWindow.mm ) - # Keep bundle identifier as-is, for compatibility sake set_target_properties(eden-ios PROPERTIES XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.yuzu-emu.yuzu" XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "YUZU1234" XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/AppUI-Bridging-Header.h" ) - -target_link_libraries(eden-ios PRIVATE common core input_common frontend_common shader_recompiler video_core glad) +target_link_libraries(eden-ios PRIVATE common core input_common frontend_common video_core) target_link_libraries(eden-ios PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) -target_link_libraries(eden-ios PRIVATE SDL2::SDL2 sirit::sirit) +target_link_libraries(eden-ios PRIVATE SDL2::SDL2 glad sirit::sirit) create_target_directory_groups(eden-ios) -target_compile_options(eden-ios PRIVATE - $<$:-Wno-conversion> - $<$:-Wno-unused-variable> - $<$:-Wno-unused-parameter> - $<$:-Wno-missing-field-initializers> -) From 9a99bed0179f3234f2d6b4feb391a42ea647a01a Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 26 Mar 2026 01:34:32 +0000 Subject: [PATCH 42/54] fix sirit i think, add ios-aarch64 --- CMakeModules/CPMUtil.cmake | 4 +++- externals/cpmfile.json | 5 ++++- src/ios/CMakeLists.txt | 6 ++++-- tools/cpm/package/fetch.sh | 1 + tools/cpm/package/util/interactive.sh | 1 + 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CMakeModules/CPMUtil.cmake b/CMakeModules/CPMUtil.cmake index b992f24083..4892db0626 100644 --- a/CMakeModules/CPMUtil.cmake +++ b/CMakeModules/CPMUtil.cmake @@ -690,8 +690,10 @@ function(AddCIPackage) set(pkgname linux-amd64) elseif(PLATFORM_LINUX AND ARCHITECTURE_arm64) set(pkgname linux-aarch64) - elseif(APPLE) + elseif(APPLE AND NOT IOS) set(pkgname macos-universal) + elseif(APPLE AND IOS AND ARCHITECTURE_arm64) + set(pkgname ios-aarch64) endif() if (DEFINED pkgname AND NOT "${pkgname}" IN_LIST DISABLED_PLATFORMS) diff --git a/externals/cpmfile.json b/externals/cpmfile.json index 66f5ee8a5a..f9f538e866 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -23,7 +23,10 @@ "package": "sirit", "name": "sirit", "repo": "eden-emulator/sirit", - "version": "1.0.4" + "version": "1.0.4", + "disabled_platforms": [ + "ios-aarch64" + ] }, "httplib": { "repo": "yhirose/cpp-httplib", diff --git a/src/ios/CMakeLists.txt b/src/ios/CMakeLists.txt index c8f15df3f8..54ff956a36 100644 --- a/src/ios/CMakeLists.txt +++ b/src/ios/CMakeLists.txt @@ -21,8 +21,10 @@ set_target_properties(eden-ios PROPERTIES XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.yuzu-emu.yuzu" XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "YUZU1234" XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/AppUI-Bridging-Header.h" + XCODE_ATTRIBUTE_SWIFT_OBJC_INTERFACE_HEADER_NAME "eden-ios-Swift.h" + XCODE_ATTRIBUTE_DERIVED_FILE_DIR "${CMAKE_CURRENT_BINARY_DIR}" ) -target_link_libraries(eden-ios PRIVATE common core input_common frontend_common video_core) +target_link_libraries(eden-ios PRIVATE common core input_common frontend_common video_core sirit::sirit) target_link_libraries(eden-ios PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) -target_link_libraries(eden-ios PRIVATE SDL2::SDL2 glad sirit::sirit) +target_link_libraries(eden-ios PRIVATE SDL2::SDL2 glad) create_target_directory_groups(eden-ios) diff --git a/tools/cpm/package/fetch.sh b/tools/cpm/package/fetch.sh index b03a824146..3baf35c079 100755 --- a/tools/cpm/package/fetch.sh +++ b/tools/cpm/package/fetch.sh @@ -83,6 +83,7 @@ ci_package() { android-aarch64 android-x86_64 \ solaris-amd64 freebsd-amd64 openbsd-amd64 \ linux-amd64 linux-aarch64 \ + ios-aarch64 \ macos-universal; do echo "-- * platform $platform" diff --git a/tools/cpm/package/util/interactive.sh b/tools/cpm/package/util/interactive.sh index 99db77e20d..80a3685cc6 100755 --- a/tools/cpm/package/util/interactive.sh +++ b/tools/cpm/package/util/interactive.sh @@ -151,6 +151,7 @@ mingw-amd64 mingw-arm64 android-aarch64 android-x86_64 solaris-amd64 freebsd-amd64 openbsd-amd64 linux-amd64 linux-aarch64 +ios-aarch64 macos-universal" DISABLED_PLATFORMS="$reply" From 559bc87cdd5880bce1faaa2897308425f0bc9635 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 26 Mar 2026 01:51:53 +0000 Subject: [PATCH 43/54] fix life --- .ci/ios/build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci/ios/build.sh b/.ci/ios/build.sh index a21e116d66..afbd8e3e4f 100755 --- a/.ci/ios/build.sh +++ b/.ci/ios/build.sh @@ -33,6 +33,7 @@ cmake -G Xcode -B build \ -DYUZU_USE_EXTERNAL_FFMPEG=ON \ -DYUZU_USE_EXTERNAL_SDL2=ON \ -DCPMUTIL_FORCE_BUNDLED=ON \ + -DYUZU_USE_BUNDLED_SIRIT=OFF \ -DCMAKE_BUILD_TYPE=Release cmake --build build -t eden-ios From 65c32d9f72f80b0767f76e8dd26c382a3187d23d Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 26 Mar 2026 01:54:56 +0000 Subject: [PATCH 44/54] DISABLE BY DEFAULT ON IOS FFS --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e8b822e4c..f923105dec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,7 +187,7 @@ cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from external sour # sirit set(BUNDLED_SIRIT_DEFAULT OFF) -if (MSVC AND NOT (CMAKE_BUILD_TYPE MATCHES "Deb") OR ANDROID) +if (((MSVC AND NOT (CMAKE_BUILD_TYPE MATCHES "Deb")) OR ANDROID) AND NOT IOS) set(BUNDLED_SIRIT_DEFAULT ON) endif() From cdcb0febc13133ee792dcb793ba22fa3f0473e19 Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 26 Mar 2026 00:14:29 -0400 Subject: [PATCH 45/54] Update CPMUtil, and fix script Signed-off-by: crueter --- .ci/ios/build.sh | 21 +++----------- CMakeLists.txt | 40 ++++----------------------- CMakeModules/CPMUtil.cmake | 4 +-- docs/CPMUtil/AddCIPackage.md | 1 + docs/CPMUtil/AddJsonPackage.md | 3 +- tools/cpm/package/fetch.sh | 3 +- tools/cpm/package/util/interactive.sh | 3 +- 7 files changed, 17 insertions(+), 58 deletions(-) diff --git a/.ci/ios/build.sh b/.ci/ios/build.sh index afbd8e3e4f..f199b66582 100755 --- a/.ci/ios/build.sh +++ b/.ci/ios/build.sh @@ -4,36 +4,23 @@ # SPDX-License-Identifier: GPL-3.0-or-later WORK_DIR="$PWD" -export IOS_SDK="$(xcrun --sdk iphoneos --show-sdk-path)" +xcrun --sdk iphoneos --show-sdk-path -[ ! -z "$IOS_SDK" ] +# TODO(crueter): FFmpeg for iOS cmake -G Xcode -B build \ -DCMAKE_TOOLCHAIN_FILE="$WORK_DIR/.ci/ios/ios-toolchain.cmake" \ -DPLATFORM=OS64 \ -DARCHS="arm64" \ -DDEPLOYMENT_TARGET=16.0 \ - -DCOCOA_LIBRARY="$IOS_SDK/System/Library/Frameworks/Cocoa.framework" \ - -DCMAKE_C_COMPILER="$(xcrun --sdk iphoneos clang -arch arm64)" \ - -DCMAKE_CXX_COMPILER="$(xcrun --sdk iphoneos clang++ -arch arm64)" \ + -DCMAKE_C_COMPILER="$(xcrun --sdk iphoneos --find clang)" \ + -DCMAKE_CXX_COMPILER="$(xcrun --sdk iphoneos --find clang++)" \ -DENABLE_LIBUSB=OFF \ - -DENABLE_UPDATE_CHECKER=OFF \ -DENABLE_QT=OFF \ - -DENABLE_OPENSSL=OFF \ - -DHTTPLIB_USE_OPENSSL=OFF \ - -DCPPHTTPLIB_USE_OPENSSL=OFF \ - -DHTTPLIB_USE_OPENSSL_IF_AVAILABLE=OFF \ -DENABLE_WEB_SERVICE=OFF \ -DENABLE_CUBEB=OFF \ - -DYUZU_ROOM=OFF \ - -DYUZU_ROOM_STANDALONE=OFF \ - -DYUZU_STATIC_ROOM=OFF \ - -DYUZU_CMD=OFF \ - -DUSE_DISCORD_PRESENCE=OFF \ -DYUZU_USE_EXTERNAL_FFMPEG=ON \ -DYUZU_USE_EXTERNAL_SDL2=ON \ - -DCPMUTIL_FORCE_BUNDLED=ON \ - -DYUZU_USE_BUNDLED_SIRIT=OFF \ -DCMAKE_BUILD_TYPE=Release cmake --build build -t eden-ios diff --git a/CMakeLists.txt b/CMakeLists.txt index f923105dec..aad977ae60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,7 +42,7 @@ if (PLATFORM_NETBSD) set(ENV{PKG_CONFIG_PATH} "${PKG_CONFIG_PATH}:${CMAKE_SYSROOT}/usr/pkg/lib/ffmpeg7/pkgconfig") endif() -cmake_dependent_option(YUZU_STATIC_ROOM "Build a static room executable only (CI only)" OFF "PLATFORM_LINUX" OFF) +cmake_dependent_option(YUZU_STATIC_ROOM "Build a static room executable only (CI only)" OFF "PLATFORM_LINUX OR WIN32 OR (APPLE AND NOT IOS)" OFF) if (YUZU_STATIC_ROOM) set(YUZU_ROOM ON) set(YUZU_ROOM_STANDALONE ON) @@ -69,7 +69,7 @@ endif() # qt stuff option(ENABLE_QT "Enable the Qt frontend" ON) option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF) -option(ENABLE_UPDATE_CHECKER "Enable update checker (for Qt and Android)" OFF) +cmake_dependent_option(ENABLE_UPDATE_CHECKER "Enable update checker (for Qt and Android)" OFF "ENABLE_QT OR ANDROID" OFF) cmake_dependent_option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF "NOT YUZU_USE_BUNDLED_QT" OFF) cmake_dependent_option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF "NOT YUZU_USE_BUNDLED_QT" OFF) set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundled Qt libraries") @@ -177,7 +177,7 @@ cmake_dependent_option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MS option(ENABLE_CUBEB "Enables the cubeb audio backend" ON) set(EXT_DEFAULT OFF) -if (MSVC OR ANDROID) +if (MSVC OR ANDROID OR IOS) set(EXT_DEFAULT ON) endif() @@ -187,7 +187,7 @@ cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from external sour # sirit set(BUNDLED_SIRIT_DEFAULT OFF) -if (((MSVC AND NOT (CMAKE_BUILD_TYPE MATCHES "Deb")) OR ANDROID) AND NOT IOS) +if ((MSVC AND NOT (CMAKE_BUILD_TYPE MATCHES "Deb")) OR ANDROID) set(BUNDLED_SIRIT_DEFAULT ON) endif() @@ -215,7 +215,7 @@ option(NIGHTLY_BUILD "Use Nightly qualifiers in the update checker and build met cmake_dependent_option(YUZU_ROOM "Enable dedicated room functionality" ON "NOT ANDROID AND NOT IOS" OFF) cmake_dependent_option(YUZU_ROOM_STANDALONE "Enable standalone room executable" ON "YUZU_ROOM" OFF) -cmake_dependent_option(YUZU_CMD "Compile the eden-cli executable" ON "NOT ANDROID" OFF) +cmake_dependent_option(YUZU_CMD "Compile the eden-cli executable" ON "NOT ANDROID AND NOT IOS" OFF) cmake_dependent_option(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR PLATFORM_LINUX" OFF) @@ -373,35 +373,7 @@ if (YUZU_USE_BUNDLED_OPENSSL) endif() endif() -if (IOS) - # TODO: this is horrific wtf - # Modify OpenSSL configuration to dynamically locate OpenSSL - if (NOT OPENSSL_ROOT_DIR) - find_program(HOMEBREW_EXECUTABLE brew) - if (HOMEBREW_EXECUTABLE) - execute_process( - COMMAND ${HOMEBREW_EXECUTABLE} --prefix openssl - OUTPUT_VARIABLE HOMEBREW_OPENSSL_PREFIX - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - set(OPENSSL_ROOT_DIR "${HOMEBREW_OPENSSL_PREFIX}") - endif() - endif() - # Adjust OpenSSL find_package to fallback to default paths - find_package(OpenSSL 3 QUIET PATHS ${OPENSSL_ROOT_DIR} PATHS /usr/local/opt/openssl /opt/homebrew/opt/openssl NO_DEFAULT_PATH) - if (NOT OpenSSL_FOUND) - find_package(OpenSSL 3 QUIET) - if (NOT OpenSSL_FOUND) - message(WARNING "OpenSSL not found. Some features may be disabled.") - endif() - endif() - # Ensure OpenSSL version 3 is correctly located - set(OPENSSL_ROOT_DIR "/opt/homebrew/opt/openssl@3") - set(OPENSSL_LIBRARIES "/opt/homebrew/opt/openssl@3/lib") - set(OPENSSL_INCLUDE_DIR "/opt/homebrew/opt/openssl@3/include") -else() - find_package(OpenSSL 3 REQUIRED) -endif() +find_package(OpenSSL 3 REQUIRED) message(STATUS "Fetching needed dependencies with CPM") diff --git a/CMakeModules/CPMUtil.cmake b/CMakeModules/CPMUtil.cmake index 4892db0626..ca39a50331 100644 --- a/CMakeModules/CPMUtil.cmake +++ b/CMakeModules/CPMUtil.cmake @@ -3,7 +3,7 @@ set(CPM_SOURCE_CACHE "${PROJECT_SOURCE_DIR}/.cache/cpm" CACHE STRING "" FORCE) -if(MSVC OR ANDROID) +if(MSVC OR ANDROID OR IOS) set(BUNDLED_DEFAULT ON) else() set(BUNDLED_DEFAULT OFF) @@ -692,7 +692,7 @@ function(AddCIPackage) set(pkgname linux-aarch64) elseif(APPLE AND NOT IOS) set(pkgname macos-universal) - elseif(APPLE AND IOS AND ARCHITECTURE_arm64) + elseif(IOS AND ARCHITECTURE_arm64) set(pkgname ios-aarch64) endif() diff --git a/docs/CPMUtil/AddCIPackage.md b/docs/CPMUtil/AddCIPackage.md index bc7c1ccfad..7319b514ff 100644 --- a/docs/CPMUtil/AddCIPackage.md +++ b/docs/CPMUtil/AddCIPackage.md @@ -18,3 +18,4 @@ - `linux-amd64` - `linux-aarch64` - `macos-universal` + - `ios-aarch64` diff --git a/docs/CPMUtil/AddJsonPackage.md b/docs/CPMUtil/AddJsonPackage.md index 464cd1731b..e655d794f5 100644 --- a/docs/CPMUtil/AddJsonPackage.md +++ b/docs/CPMUtil/AddJsonPackage.md @@ -61,7 +61,8 @@ In order: OpenSSL CI, Boost (tag + artifact), Opus (options + find_args), discor "version": "3.6.0", "min_version": "1.1.1", "disabled_platforms": [ - "macos-universal" + "macos-universal", + "ios-aarch64" ] }, "boost": { diff --git a/tools/cpm/package/fetch.sh b/tools/cpm/package/fetch.sh index 3baf35c079..54ea8c64c4 100755 --- a/tools/cpm/package/fetch.sh +++ b/tools/cpm/package/fetch.sh @@ -83,8 +83,7 @@ ci_package() { android-aarch64 android-x86_64 \ solaris-amd64 freebsd-amd64 openbsd-amd64 \ linux-amd64 linux-aarch64 \ - ios-aarch64 \ - macos-universal; do + macos-universal ios-aarch64; do echo "-- * platform $platform" case $DISABLED in diff --git a/tools/cpm/package/util/interactive.sh b/tools/cpm/package/util/interactive.sh index 80a3685cc6..07087e5d10 100755 --- a/tools/cpm/package/util/interactive.sh +++ b/tools/cpm/package/util/interactive.sh @@ -151,8 +151,7 @@ mingw-amd64 mingw-arm64 android-aarch64 android-x86_64 solaris-amd64 freebsd-amd64 openbsd-amd64 linux-amd64 linux-aarch64 -ios-aarch64 -macos-universal" +macos-universal ios-aarch64" DISABLED_PLATFORMS="$reply" fi From 3f90add01f21910e4333c7ff1f4369a64d69a049 Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 26 Mar 2026 02:53:43 -0400 Subject: [PATCH 46/54] Fix most build errors Signed-off-by: crueter --- .ci/ios/build.sh | 11 ++++---- .ci/ios/ios-toolchain.cmake | 2 +- CMakeLists.txt | 14 +++++----- externals/CMakeLists.txt | 4 +++ .../cmake-modules/DetectArchitecture.cmake | 8 +++--- externals/cpmfile.json | 8 +++--- src/common/CMakeLists.txt | 5 ++-- src/common/httplib.h | 9 +++++++ src/core/CMakeLists.txt | 3 --- .../hle/service/bcat/news/builtin_news.cpp | 9 ++----- src/frontend_common/CMakeLists.txt | 3 --- src/frontend_common/update_checker.cpp | 2 +- src/ios/CMakeLists.txt | 3 ++- src/ios/VMA.cpp | 5 ++++ src/qt_common/CMakeLists.txt | 3 --- src/qt_common/discord/discord_impl.cpp | 2 +- src/video_core/vulkan_common/vma.h | 7 ++++- src/web_service/CMakeLists.txt | 27 +++---------------- src/web_service/web_backend.cpp | 2 +- 19 files changed, 57 insertions(+), 70 deletions(-) create mode 100644 src/common/httplib.h create mode 100644 src/ios/VMA.cpp diff --git a/.ci/ios/build.sh b/.ci/ios/build.sh index f199b66582..5537214cf9 100755 --- a/.ci/ios/build.sh +++ b/.ci/ios/build.sh @@ -6,9 +6,9 @@ WORK_DIR="$PWD" xcrun --sdk iphoneos --show-sdk-path -# TODO(crueter): FFmpeg for iOS +# TODO: support iphonesimulator sdk -cmake -G Xcode -B build \ +cmake -G Xcode -B build/ios \ -DCMAKE_TOOLCHAIN_FILE="$WORK_DIR/.ci/ios/ios-toolchain.cmake" \ -DPLATFORM=OS64 \ -DARCHS="arm64" \ @@ -19,8 +19,7 @@ cmake -G Xcode -B build \ -DENABLE_QT=OFF \ -DENABLE_WEB_SERVICE=OFF \ -DENABLE_CUBEB=OFF \ - -DYUZU_USE_EXTERNAL_FFMPEG=ON \ - -DYUZU_USE_EXTERNAL_SDL2=ON \ - -DCMAKE_BUILD_TYPE=Release + -DCMAKE_BUILD_TYPE=Release \ + "$@" -cmake --build build -t eden-ios +cmake --build build/ios -t eden-ios --config Release diff --git a/.ci/ios/ios-toolchain.cmake b/.ci/ios/ios-toolchain.cmake index b0defa25aa..5eed07b32f 100644 --- a/.ci/ios/ios-toolchain.cmake +++ b/.ci/ios/ios-toolchain.cmake @@ -157,7 +157,7 @@ # command. # -cmake_minimum_required(VERSION 3.8.0) +cmake_minimum_required(VERSION 3.10) # CMake invokes the toolchain file twice during the first build, but only once during subsequent rebuilds. # NOTE: To improve single-library build-times, provide the flag "OS_SINGLE_BUILD" as a build argument. diff --git a/CMakeLists.txt b/CMakeLists.txt index aad977ae60..82f8d8aec1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,24 +170,24 @@ if (MSVC AND NOT CXX_CLANG) set(CMAKE_CXX_FLAGS_INIT "${CMAKE_CXX_FLAGS_INIT} /W3 /WX-") endif() -# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system -cmake_dependent_option(YUZU_USE_EXTERNAL_SDL2 "Build SDL2 from external source" OFF "NOT MSVC;NOT ANDROID" OFF) -cmake_dependent_option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MSVC}" "NOT ANDROID" OFF) - -option(ENABLE_CUBEB "Enables the cubeb audio backend" ON) - set(EXT_DEFAULT OFF) if (MSVC OR ANDROID OR IOS) set(EXT_DEFAULT ON) endif() +# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system +cmake_dependent_option(YUZU_USE_EXTERNAL_SDL2 "Build SDL2 from external source" OFF "NOT MSVC;NOT ANDROID" OFF) +cmake_dependent_option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${EXT_DEFAULT}" "NOT ANDROID" OFF) + +option(ENABLE_CUBEB "Enables the cubeb audio backend" ON) + # ffmpeg option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT}) cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from external source" "${PLATFORM_SUN}" "NOT WIN32 AND NOT ANDROID" OFF) # sirit set(BUNDLED_SIRIT_DEFAULT OFF) -if ((MSVC AND NOT (CMAKE_BUILD_TYPE MATCHES "Deb")) OR ANDROID) +if ((MSVC AND NOT (CMAKE_BUILD_TYPE MATCHES "Deb")) OR ANDROID OR IOS) set(BUNDLED_SIRIT_DEFAULT ON) endif() diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 00bdf10a4f..2ebc09113b 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -228,6 +228,10 @@ if (VulkanMemoryAllocator_ADDED) endif() # httplib +if (IOS) + set(HTTPLIB_USE_BROTLI_IF_AVAILABLE OFF) +endif() + AddJsonPackage(httplib) # cpp-jwt diff --git a/externals/cmake-modules/DetectArchitecture.cmake b/externals/cmake-modules/DetectArchitecture.cmake index a2f78b86de..c4fd9e1ec3 100644 --- a/externals/cmake-modules/DetectArchitecture.cmake +++ b/externals/cmake-modules/DetectArchitecture.cmake @@ -41,12 +41,12 @@ if (CMAKE_OSX_ARCHITECTURES) if (IOS) # TODO: Right... the toolchain file won't properly accomodate OSX_ARCHITECTURE # they aren't defining it as a list properly I assume? - set(ARCHITECTURE_arm64 1 PARENT_SCOPE) + set(ARCHITECTURE_arm64 1) add_definitions(-DARCHITECTURE_arm64=1) else () # hope and pray the architecture names match - foreach(ARCH IN ${CMAKE_OSX_ARCHITECTURES}) - set(ARCHITECTURE_${ARCH} 1 PARENT_SCOPE) + foreach(ARCH ${CMAKE_OSX_ARCHITECTURES}) + set(ARCHITECTURE_${ARCH} 1) add_definitions(-DARCHITECTURE_${ARCH}=1) endforeach() endif() @@ -223,4 +223,4 @@ if (NOT DEFINED ARCHITECTURE) add_definitions(-DARCHITECTURE_GENERIC=1) endif() -message(STATUS "[DetectArchitecture] Target architecture: ${ARCHITECTURE}") \ No newline at end of file +message(STATUS "[DetectArchitecture] Target architecture: ${ARCHITECTURE}") diff --git a/externals/cpmfile.json b/externals/cpmfile.json index f9f538e866..45400f0801 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -23,10 +23,7 @@ "package": "sirit", "name": "sirit", "repo": "eden-emulator/sirit", - "version": "1.0.4", - "disabled_platforms": [ - "ios-aarch64" - ] + "version": "1.0.5" }, "httplib": { "repo": "yhirose/cpp-httplib", @@ -39,7 +36,8 @@ "0002-fix-zstd.patch" ], "options": [ - "HTTPLIB_REQUIRE_OPENSSL ON" + "HTTPLIB_REQUIRE_OPENSSL ON", + "HTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES ON" ] }, "cpp-jwt": { diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 1ee4794272..00a25a5744 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -144,7 +144,8 @@ add_library( zstd_compression.cpp zstd_compression.h fs/ryujinx_compat.h fs/ryujinx_compat.cpp - fs/symlink.h fs/symlink.cpp) + fs/symlink.h fs/symlink.cpp + httplib.h) if(WIN32) target_sources(common PRIVATE windows/timer_resolution.cpp @@ -242,7 +243,7 @@ else() target_link_libraries(common PUBLIC Boost::headers) endif() -target_link_libraries(common PUBLIC Boost::filesystem Boost::context) +target_link_libraries(common PUBLIC Boost::filesystem Boost::context httplib::httplib) if (lz4_ADDED) target_include_directories(common PRIVATE ${lz4_SOURCE_DIR}/lib) diff --git a/src/common/httplib.h b/src/common/httplib.h new file mode 100644 index 0000000000..2f971bd5f3 --- /dev/null +++ b/src/common/httplib.h @@ -0,0 +1,9 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#define CPPHTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES +#define CPPHTTPLIB_OPENSSL_SUPPORT + +#include diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a2f595540d..aad42b883b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1273,9 +1273,6 @@ endif() target_sources(core PRIVATE hle/service/ssl/ssl_backend_openssl.cpp) target_link_libraries(core PRIVATE OpenSSL::SSL OpenSSL::Crypto) -if (NOT IOS) - target_compile_definitions(core PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT) -endif() # TODO diff --git a/src/core/hle/service/bcat/news/builtin_news.cpp b/src/core/hle/service/bcat/news/builtin_news.cpp index f7cc6c5a23..ad7aafa4e3 100644 --- a/src/core/hle/service/bcat/news/builtin_news.cpp +++ b/src/core/hle/service/bcat/news/builtin_news.cpp @@ -15,9 +15,7 @@ #include #include -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT -#include -#endif +#include "common/httplib.h" #include #include @@ -104,7 +102,6 @@ std::vector TryLoadFromDisk(const std::filesystem::path& path) { std::vector DownloadImage(const std::string& url_path, const std::filesystem::path& cache_path) { LOG_INFO(Service_BCAT, "Downloading image: https://eden-emu.dev{}", url_path); -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT try { httplib::Client cli("https://eden-emu.dev"); cli.set_follow_location(true); @@ -128,7 +125,6 @@ std::vector DownloadImage(const std::string& url_path, const std::filesystem } catch (...) { LOG_WARNING(Service_BCAT, "Failed to download: {}", url_path); } -#endif return {}; } @@ -233,7 +229,6 @@ void WriteCachedJson(std::string_view json) { std::optional DownloadReleasesJson() { -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT try { httplib::SSLClient cli{"api.github.com", 443}; cli.set_connection_timeout(10); @@ -255,7 +250,7 @@ std::optional DownloadReleasesJson() { } catch (...) { LOG_WARNING(Service_BCAT, " failed to download releases"); } -#endif + return std::nullopt; } diff --git a/src/frontend_common/CMakeLists.txt b/src/frontend_common/CMakeLists.txt index b1554d7dba..f9b3805939 100644 --- a/src/frontend_common/CMakeLists.txt +++ b/src/frontend_common/CMakeLists.txt @@ -23,9 +23,6 @@ if (ENABLE_UPDATE_CHECKER) update_checker.cpp update_checker.h) target_link_libraries(frontend_common PRIVATE OpenSSL::SSL OpenSSL::Crypto) - if (NOT IOS) - target_compile_definitions(frontend_common PUBLIC CPPHTTPLIB_OPENSSL_SUPPORT) - endif() endif() create_target_directory_groups(frontend_common) diff --git a/src/frontend_common/update_checker.cpp b/src/frontend_common/update_checker.cpp index 75b1dc00cc..3e5a832ba0 100644 --- a/src/frontend_common/update_checker.cpp +++ b/src/frontend_common/update_checker.cpp @@ -13,7 +13,7 @@ #include "common/scm_rev.h" #include "update_checker.h" -#include +#include "common/httplib.h" #ifdef YUZU_BUNDLED_OPENSSL #include diff --git a/src/ios/CMakeLists.txt b/src/ios/CMakeLists.txt index 54ff956a36..6e6c13db2d 100644 --- a/src/ios/CMakeLists.txt +++ b/src/ios/CMakeLists.txt @@ -15,6 +15,7 @@ add_executable(eden-ios EmulationSession.mm EmulationWindow.h EmulationWindow.mm + VMA.cpp ) # Keep bundle identifier as-is, for compatibility sake set_target_properties(eden-ios PROPERTIES @@ -26,5 +27,5 @@ set_target_properties(eden-ios PROPERTIES ) target_link_libraries(eden-ios PRIVATE common core input_common frontend_common video_core sirit::sirit) target_link_libraries(eden-ios PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) -target_link_libraries(eden-ios PRIVATE SDL2::SDL2 glad) +target_link_libraries(eden-ios PRIVATE SDL2::SDL2 glad stb::headers) create_target_directory_groups(eden-ios) diff --git a/src/ios/VMA.cpp b/src/ios/VMA.cpp new file mode 100644 index 0000000000..7e2ea49c28 --- /dev/null +++ b/src/ios/VMA.cpp @@ -0,0 +1,5 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#define VMA_IMPLEMENTATION +#include "video_core/vulkan_common/vma.h" diff --git a/src/qt_common/CMakeLists.txt b/src/qt_common/CMakeLists.txt index f7614c506a..399fbe67a0 100644 --- a/src/qt_common/CMakeLists.txt +++ b/src/qt_common/CMakeLists.txt @@ -50,9 +50,6 @@ if (USE_DISCORD_PRESENCE) if (YUZU_USE_BUNDLED_OPENSSL) target_link_libraries(qt_common PUBLIC OpenSSL::SSL OpenSSL::Crypto) - if (NOT IOS) - target_compile_definitions(qt_common PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT) - endif() endif() target_compile_definitions(qt_common PUBLIC USE_DISCORD_PRESENCE) diff --git a/src/qt_common/discord/discord_impl.cpp b/src/qt_common/discord/discord_impl.cpp index 37b24cdd57..c1cb5319dc 100644 --- a/src/qt_common/discord/discord_impl.cpp +++ b/src/qt_common/discord/discord_impl.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include "common/httplib.h" #include #include diff --git a/src/video_core/vulkan_common/vma.h b/src/video_core/vulkan_common/vma.h index e022b2bf7d..514ff4501c 100644 --- a/src/video_core/vulkan_common/vma.h +++ b/src/video_core/vulkan_common/vma.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -13,9 +13,14 @@ #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable : 4189 ) +#elif defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-variable" #endif #include "vk_mem_alloc.h" #ifdef _MSC_VER #pragma warning( pop ) +#elif defined(__clang__) +#pragma clang diagnostic pop #endif diff --git a/src/web_service/CMakeLists.txt b/src/web_service/CMakeLists.txt index 0b749bb216..a3acdfcf0f 100644 --- a/src/web_service/CMakeLists.txt +++ b/src/web_service/CMakeLists.txt @@ -20,27 +20,6 @@ create_target_directory_groups(web_service) target_include_directories(web_service PUBLIC ${cpp-jwt_SOURCE_DIR}/include) target_link_libraries(web_service PRIVATE common network nlohmann_json::nlohmann_json httplib::httplib cpp-jwt::cpp-jwt) -if (IOS) - # TODO: this is horrific - find_package(OpenSSL 3 QUIET) - if (OpenSSL_FOUND) - target_link_libraries(web_service PRIVATE OpenSSL::SSL OpenSSL::Crypto) - if (NOT IOS) - target_compile_definitions(web_service PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT) - endif() - else() - find_package(OpenSSL 3 QUIET PATHS /usr/local/opt/openssl /opt/homebrew/opt/openssl NO_DEFAULT_PATH) - if (OpenSSL_FOUND) - target_link_libraries(web_service PRIVATE OpenSSL::SSL OpenSSL::Crypto) - if (NOT IOS) - target_compile_definitions(web_service PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT) - endif() - else() - message(WARNING "OpenSSL not found or version is less than 3. Some features in web_service may be disabled.") - endif() - endif() -else() - find_package(OpenSSL REQUIRED) - target_link_libraries(web_service PRIVATE OpenSSL::SSL OpenSSL::Crypto) - target_compile_definitions(web_service PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT) -endif() +find_package(OpenSSL REQUIRED) +target_link_libraries(web_service PRIVATE OpenSSL::SSL OpenSSL::Crypto) +target_compile_definitions(web_service PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT) diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp index 60b11fff5a..1e71406989 100644 --- a/src/web_service/web_backend.cpp +++ b/src/web_service/web_backend.cpp @@ -16,7 +16,7 @@ #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif #endif -#include +#include "common/httplib.h" #ifdef __GNUC__ #pragma GCC diagnostic pop #endif From fc5eb3a3dedef6831a2cc809f305a0225c9cf967 Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 26 Mar 2026 03:02:28 -0400 Subject: [PATCH 47/54] fix libs Signed-off-by: crueter --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 82f8d8aec1..dd3349113b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -488,9 +488,11 @@ endfunction() # Put these BEFORE EXTERNALS or Boost WILL die # ============================================= if (APPLE) - set(_libs Carbon Metal Cocoa IOKit CoreVideo CoreMedia) + set(_libs Metal IOKit CoreVideo CoreMedia) if (IOS) list(APPEND _libs objc) + else() + list(APPEND _libs Carbon Cocoa) endif() foreach(fw ${_libs}) From 028e8f667623c4902cab0ed4549588c9de525434 Mon Sep 17 00:00:00 2001 From: crueter Date: Thu, 26 Mar 2026 12:46:07 -0400 Subject: [PATCH 48/54] Revert stbi Signed-off-by: crueter --- externals/stb/stb_image_write.h | 707 +++++++++++++++++++++++++++++++- 1 file changed, 706 insertions(+), 1 deletion(-) diff --git a/externals/stb/stb_image_write.h b/externals/stb/stb_image_write.h index badacf6c5f..e4b32ed1bc 100644 --- a/externals/stb/stb_image_write.h +++ b/externals/stb/stb_image_write.h @@ -391,6 +391,11 @@ static void stbiw__write_flush(stbi__write_context *s) } } +static void stbiw__putc(stbi__write_context *s, unsigned char c) +{ + s->func(s->context, &c, 1); +} + static void stbiw__write1(stbi__write_context *s, unsigned char a) { if ((size_t)s->buf_used + 1 > sizeof(s->buffer)) @@ -768,7 +773,7 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f #ifdef __STDC_LIB_EXT1__ len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #else - len = 0; // + len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #endif s->func(s->context, buffer, len); @@ -1016,4 +1021,704 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i #endif // STBIW_ZLIB_COMPRESS } +static unsigned int stbiw__crc32(unsigned char *buffer, int len) +{ +#ifdef STBIW_CRC32 + return STBIW_CRC32(buffer, len); +#else + static unsigned int crc_table[256] = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D + }; + + unsigned int crc = ~0u; + int i; + for (i=0; i < len; ++i) + crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; + return ~crc; +#endif +} + +#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) +#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); +#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) + +static void stbiw__wpcrc(unsigned char **data, int len) +{ + unsigned int crc = stbiw__crc32(*data - len - 4, len+4); + stbiw__wp32(*data, crc); +} + +static unsigned char stbiw__paeth(int a, int b, int c) +{ + int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); + if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); + if (pb <= pc) return STBIW_UCHAR(b); + return STBIW_UCHAR(c); +} + +// @OPTIMIZE: provide an option that always forces left-predict or paeth predict +static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer) +{ + static int mapping[] = { 0,1,2,3,4 }; + static int firstmap[] = { 0,1,0,5,6 }; + int *mymap = (y != 0) ? mapping : firstmap; + int i; + int type = mymap[filter_type]; + unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); + int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; + + if (type==0) { + memcpy(line_buffer, z, width*n); + return; + } + + // first loop isn't optimized since it's just one pixel + for (i = 0; i < n; ++i) { + switch (type) { + case 1: line_buffer[i] = z[i]; break; + case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; + case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; + case 5: line_buffer[i] = z[i]; break; + case 6: line_buffer[i] = z[i]; break; + } + } + switch (type) { + case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; + case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; + case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; + case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; + case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; + case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; + } +} + +STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) +{ + int force_filter = stbi_write_force_png_filter; + int ctype[5] = { -1, 0, 4, 2, 6 }; + unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; + unsigned char *out,*o, *filt, *zlib; + signed char *line_buffer; + int j,zlen; + + if (stride_bytes == 0) + stride_bytes = x * n; + + if (force_filter >= 5) { + force_filter = -1; + } + + filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; + line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } + for (j=0; j < y; ++j) { + int filter_type; + if (force_filter > -1) { + filter_type = force_filter; + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); + } else { // Estimate the best filter by running through all of them: + int best_filter = 0, best_filter_val = 0x7fffffff, est, i; + for (filter_type = 0; filter_type < 5; filter_type++) { + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); + + // Estimate the entropy of the line using this filter; the less, the better. + est = 0; + for (i = 0; i < x*n; ++i) { + est += abs((signed char) line_buffer[i]); + } + if (est < best_filter_val) { + best_filter_val = est; + best_filter = filter_type; + } + } + if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it + stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); + filter_type = best_filter; + } + } + // when we get here, filter_type contains the filter type, and line_buffer contains the data + filt[j*(x*n+1)] = (unsigned char) filter_type; + STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); + } + STBIW_FREE(line_buffer); + zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); + STBIW_FREE(filt); + if (!zlib) return 0; + + // each tag requires 12 bytes of overhead + out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); + if (!out) return 0; + *out_len = 8 + 12+13 + 12+zlen + 12; + + o=out; + STBIW_MEMMOVE(o,sig,8); o+= 8; + stbiw__wp32(o, 13); // header length + stbiw__wptag(o, "IHDR"); + stbiw__wp32(o, x); + stbiw__wp32(o, y); + *o++ = 8; + *o++ = STBIW_UCHAR(ctype[n]); + *o++ = 0; + *o++ = 0; + *o++ = 0; + stbiw__wpcrc(&o,13); + + stbiw__wp32(o, zlen); + stbiw__wptag(o, "IDAT"); + STBIW_MEMMOVE(o, zlib, zlen); + o += zlen; + STBIW_FREE(zlib); + stbiw__wpcrc(&o, zlen); + + stbiw__wp32(o,0); + stbiw__wptag(o, "IEND"); + stbiw__wpcrc(&o,0); + + STBIW_ASSERT(o == out + *out_len); + + return out; +} + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) +{ + FILE *f; + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + + f = stbiw__fopen(filename, "wb"); + if (!f) { STBIW_FREE(png); return 0; } + fwrite(png, 1, len, f); + fclose(f); + STBIW_FREE(png); + return 1; +} +#endif + +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) +{ + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); + if (png == NULL) return 0; + func(context, png, len); + STBIW_FREE(png); + return 1; +} + + +/* *************************************************************************** + * + * JPEG writer + * + * This is based on Jon Olick's jo_jpeg.cpp: + * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html + */ + +static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18, + 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; + +static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) { + int bitBuf = *bitBufP, bitCnt = *bitCntP; + bitCnt += bs[1]; + bitBuf |= bs[0] << (24 - bitCnt); + while(bitCnt >= 8) { + unsigned char c = (bitBuf >> 16) & 255; + stbiw__putc(s, c); + if(c == 255) { + stbiw__putc(s, 0); + } + bitBuf <<= 8; + bitCnt -= 8; + } + *bitBufP = bitBuf; + *bitCntP = bitCnt; +} + +static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) { + float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; + float z1, z2, z3, z4, z5, z11, z13; + + float tmp0 = d0 + d7; + float tmp7 = d0 - d7; + float tmp1 = d1 + d6; + float tmp6 = d1 - d6; + float tmp2 = d2 + d5; + float tmp5 = d2 - d5; + float tmp3 = d3 + d4; + float tmp4 = d3 - d4; + + // Even part + float tmp10 = tmp0 + tmp3; // phase 2 + float tmp13 = tmp0 - tmp3; + float tmp11 = tmp1 + tmp2; + float tmp12 = tmp1 - tmp2; + + d0 = tmp10 + tmp11; // phase 3 + d4 = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * 0.707106781f; // c4 + d2 = tmp13 + z1; // phase 5 + d6 = tmp13 - z1; + + // Odd part + tmp10 = tmp4 + tmp5; // phase 2 + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + // The rotator is modified from fig 4-8 to avoid extra negations. + z5 = (tmp10 - tmp12) * 0.382683433f; // c6 + z2 = tmp10 * 0.541196100f + z5; // c2-c6 + z4 = tmp12 * 1.306562965f + z5; // c2+c6 + z3 = tmp11 * 0.707106781f; // c4 + + z11 = tmp7 + z3; // phase 5 + z13 = tmp7 - z3; + + *d5p = z13 + z2; // phase 6 + *d3p = z13 - z2; + *d1p = z11 + z4; + *d7p = z11 - z4; + + *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6; +} + +static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { + int tmp1 = val < 0 ? -val : val; + val = val < 0 ? val-1 : val; + bits[1] = 1; + while(tmp1 >>= 1) { + ++bits[1]; + } + bits[0] = val & ((1<0)&&(DU[end0pos]==0); --end0pos) { + } + // end0pos = first element in reverse order !=0 + if(end0pos == 0) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + return DU[0]; + } + for(i = 1; i <= end0pos; ++i) { + int startpos = i; + int nrzeroes; + unsigned short bits[2]; + for (; DU[i]==0 && i<=end0pos; ++i) { + } + nrzeroes = i-startpos; + if ( nrzeroes >= 16 ) { + int lng = nrzeroes>>4; + int nrmarker; + for (nrmarker=1; nrmarker <= lng; ++nrmarker) + stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); + nrzeroes &= 15; + } + stbiw__jpg_calcBits(DU[i], bits); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); + } + if(end0pos != 63) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + } + return DU[0]; +} + +static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) { + // Constants that don't pollute global namespace + static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; + static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; + static const unsigned char std_ac_luminance_values[] = { + 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, + 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, + 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, + 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, + 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, + 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, + 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; + static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; + static const unsigned char std_ac_chrominance_values[] = { + 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, + 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, + 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, + 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, + 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, + 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa + }; + // Huffman tables + static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; + static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; + static const unsigned short YAC_HT[256][2] = { + {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const unsigned short UVAC_HT[256][2] = { + {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, + {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, + {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} + }; + static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22, + 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; + static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, + 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; + static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, + 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; + + int row, col, i, k, subsample; + float fdtbl_Y[64], fdtbl_UV[64]; + unsigned char YTable[64], UVTable[64]; + + if(!data || !width || !height || comp > 4 || comp < 1) { + return 0; + } + + quality = quality ? quality : 90; + subsample = quality <= 90 ? 1 : 0; + quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; + quality = quality < 50 ? 5000 / quality : 200 - quality * 2; + + for(i = 0; i < 64; ++i) { + int uvti, yti = (YQT[i]*quality+50)/100; + YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti); + uvti = (UVQT[i]*quality+50)/100; + UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); + } + + for(row = 0, k = 0; row < 8; ++row) { + for(col = 0; col < 8; ++col, ++k) { + fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + } + } + + // Write Headers + { + static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; + static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; + const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), + 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; + s->func(s->context, (void*)head0, sizeof(head0)); + s->func(s->context, (void*)YTable, sizeof(YTable)); + stbiw__putc(s, 1); + s->func(s->context, UVTable, sizeof(UVTable)); + s->func(s->context, (void*)head1, sizeof(head1)); + s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1); + s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values)); + stbiw__putc(s, 0x10); // HTYACinfo + s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1); + s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values)); + stbiw__putc(s, 1); // HTUDCinfo + s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); + stbiw__putc(s, 0x11); // HTUACinfo + s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1); + s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); + s->func(s->context, (void*)head2, sizeof(head2)); + } + + // Encode 8x8 macroblocks + { + static const unsigned short fillBits[] = {0x7F, 7}; + int DCY=0, DCU=0, DCV=0; + int bitBuf=0, bitCnt=0; + // comp == 2 is grey+alpha (alpha is ignored) + int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; + const unsigned char *dataR = (const unsigned char *)data; + const unsigned char *dataG = dataR + ofsG; + const unsigned char *dataB = dataR + ofsB; + int x, y, pos; + if(subsample) { + for(y = 0; y < height; y += 16) { + for(x = 0; x < width; x += 16) { + float Y[256], U[256], V[256]; + for(row = y, pos = 0; row < y+16; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+16; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); + + // subsample U,V + { + float subU[64], subV[64]; + int yy, xx; + for(yy = 0, pos = 0; yy < 8; ++yy) { + for(xx = 0; xx < 8; ++xx, ++pos) { + int j = yy*32+xx*2; + subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; + subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; + } + } + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + } + } else { + for(y = 0; y < height; y += 8) { + for(x = 0; x < width; x += 8) { + float Y[64], U[64], V[64]; + for(row = y, pos = 0; row < y+8; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; + for(col = x; col < x+8; ++col, ++pos) { + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width-1))*comp; + float r = dataR[p], g = dataG[p], b = dataB[p]; + Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; + U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; + V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; + } + } + + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } + } + + // Do the bit alignment of the EOI marker + stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); + } + + // EOI + stbiw__putc(s, 0xFF); + stbiw__putc(s, 0xD9); + + return 1; +} + +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s = { 0 }; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); +} + + +#ifndef STBI_WRITE_NO_STDIO +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) +{ + stbi__write_context s = { 0 }; + if (stbi__start_write_file(&s,filename)) { + int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); + stbi__end_write_file(&s); + return r; + } else + return 0; +} +#endif + #endif // STB_IMAGE_WRITE_IMPLEMENTATION + +/* Revision history + 1.16 (2021-07-11) + make Deflate code emit uncompressed blocks when it would otherwise expand + support writing BMPs with alpha channel + 1.15 (2020-07-13) unknown + 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels + 1.13 + 1.12 + 1.11 (2019-08-11) + + 1.10 (2019-02-07) + support utf8 filenames in Windows; fix warnings and platform ifdefs + 1.09 (2018-02-11) + fix typo in zlib quality API, improve STB_I_W_STATIC in C++ + 1.08 (2018-01-29) + add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter + 1.07 (2017-07-24) + doc fix + 1.06 (2017-07-23) + writing JPEG (using Jon Olick's code) + 1.05 ??? + 1.04 (2017-03-03) + monochrome BMP expansion + 1.03 ??? + 1.02 (2016-04-02) + avoid allocating large structures on the stack + 1.01 (2016-01-16) + STBIW_REALLOC_SIZED: support allocators with no realloc support + avoid race-condition in crc initialization + minor compile issues + 1.00 (2015-09-14) + installable file IO function + 0.99 (2015-09-13) + warning fixes; TGA rle support + 0.98 (2015-04-08) + added STBIW_MALLOC, STBIW_ASSERT etc + 0.97 (2015-01-18) + fixed HDR asserts, rewrote HDR rle logic + 0.96 (2015-01-17) + add HDR output + fix monochrome BMP + 0.95 (2014-08-17) + add monochrome TGA output + 0.94 (2014-05-31) + rename private functions to avoid conflicts with stb_image.h + 0.93 (2014-05-27) + warning fixes + 0.92 (2010-08-01) + casts to unsigned char to fix warnings + 0.91 (2010-07-17) + first public release + 0.90 first internal release +*/ + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ From 5a2fc19c0f4325a958c2612bdcdc9e0931339370 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 26 Mar 2026 17:18:30 +0000 Subject: [PATCH 49/54] add basic ios shit --- src/ios/AppUI.swift | 1 + src/ios/CMakeLists.txt | 3 +++ src/ios/ContentView.swift | 19 +++++++++++++++++++ src/ios/PomeloApp.swift | 19 +++++++++++++++++++ 4 files changed, 42 insertions(+) create mode 100644 src/ios/ContentView.swift create mode 100644 src/ios/PomeloApp.swift diff --git a/src/ios/AppUI.swift b/src/ios/AppUI.swift index b1d95324cc..dd1706ae23 100644 --- a/src/ios/AppUI.swift +++ b/src/ios/AppUI.swift @@ -7,6 +7,7 @@ import UIKit import Foundation import QuartzCore.CAMetalLayer +@main public struct AppUI { public static let shared = AppUI() diff --git a/src/ios/CMakeLists.txt b/src/ios/CMakeLists.txt index 6e6c13db2d..525c182261 100644 --- a/src/ios/CMakeLists.txt +++ b/src/ios/CMakeLists.txt @@ -16,6 +16,9 @@ add_executable(eden-ios EmulationWindow.h EmulationWindow.mm VMA.cpp + + PomeloApp.swift + ContentView.swift ) # Keep bundle identifier as-is, for compatibility sake set_target_properties(eden-ios PROPERTIES diff --git a/src/ios/ContentView.swift b/src/ios/ContentView.swift new file mode 100644 index 0000000000..9ebe0622d7 --- /dev/null +++ b/src/ios/ContentView.swift @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI +import Sudachi + +struct ContentView: View { + @State var core = Core(games: [], root: FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]) + var body: some View { + HomeView(core: core).onAppear() { + Air.play(AnyView( + Text("Select Game").font(.system(size: 100)) + )) + // rest of death + } + } +} diff --git a/src/ios/PomeloApp.swift b/src/ios/PomeloApp.swift new file mode 100644 index 0000000000..4a48939f54 --- /dev/null +++ b/src/ios/PomeloApp.swift @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI + +infix operator --: LogicalDisjunctionPrecedence + +func --(lhs: Bool, rhs: Bool) -> Bool { + return lhs || rhs +} + +@main +struct PomeloApp: App { + var body: some Scene { + WindowGroup { ContentView() } + } +} From d7b9c9638e9c20f0ee2837adec6cf8857c5d53e3 Mon Sep 17 00:00:00 2001 From: crueter Date: Fri, 27 Mar 2026 16:57:26 -0400 Subject: [PATCH 50/54] Build fixes Signed-off-by: crueter --- .ci/ios/build.sh | 4 -- CMakeLists.txt | 36 ++++++++++++-- .../cmake-modules/DetectArchitecture.cmake | 2 +- externals/libusb/CMakeLists.txt | 3 +- src/ios/AppUI.swift | 1 - src/ios/CMakeLists.txt | 47 +++++++++++++++++-- src/ios/ContentView.swift | 16 +++---- src/yuzu/CMakeLists.txt | 2 +- 8 files changed, 88 insertions(+), 23 deletions(-) diff --git a/.ci/ios/build.sh b/.ci/ios/build.sh index 5537214cf9..cd3a57ec32 100755 --- a/.ci/ios/build.sh +++ b/.ci/ios/build.sh @@ -15,10 +15,6 @@ cmake -G Xcode -B build/ios \ -DDEPLOYMENT_TARGET=16.0 \ -DCMAKE_C_COMPILER="$(xcrun --sdk iphoneos --find clang)" \ -DCMAKE_CXX_COMPILER="$(xcrun --sdk iphoneos --find clang++)" \ - -DENABLE_LIBUSB=OFF \ - -DENABLE_QT=OFF \ - -DENABLE_WEB_SERVICE=OFF \ - -DENABLE_CUBEB=OFF \ -DCMAKE_BUILD_TYPE=Release \ "$@" diff --git a/CMakeLists.txt b/CMakeLists.txt index dd3349113b..4afadff0a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,29 @@ include(CMakeDependentOption) include(CTest) include(CPMUtil) +# TODO(crueter): Make this more automatic. +if (IOS) + list(APPEND CMAKE_FIND_ROOT_PATH "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") + list(APPEND CMAKE_PROGRAM_PATH "/opt/homebrew/bin" CACHE INTERNAL "") + + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH CACHE INTERNAL "") + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH CACHE INTERNAL "") + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH CACHE INTERNAL "") + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH CACHE INTERNAL "") + + list(LENGTH CMAKE_OSX_ARCHITECTURES _arch_len) + if (NOT _arch_len EQUAL 1) + message(FATAL_ERROR "CMAKE_OSX_ARCHITECTURES must contain exactly one architecture.") + endif() + + # TODO(crueter): Proper handling for this. + if (CMAKE_OSX_ARCHITECTURES STREQUAL arm64) + set(CMAKE_SYSTEM_PROCESSOR aarch64) + else() + set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_OSX_ARCHITECTURES}) + endif() +endif() + if (NOT DEFINED ARCHITECTURE) message(FATAL_ERROR "Architecture didn't make it out of scope, did you delete DetectArchitecture.cmake?") endif() @@ -67,7 +90,13 @@ if (YUZU_STATIC_ROOM) endif() # qt stuff -option(ENABLE_QT "Enable the Qt frontend" ON) +if (IOS OR ANDROID) + set(_default_qt OFF) +else() + set(_default_qt ON) +endif() + +option(ENABLE_QT "Enable the Qt frontend" ${_default_qt}) option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF) cmake_dependent_option(ENABLE_UPDATE_CHECKER "Enable update checker (for Qt and Android)" OFF "ENABLE_QT OR ANDROID" OFF) cmake_dependent_option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF "NOT YUZU_USE_BUNDLED_QT" OFF) @@ -179,7 +208,8 @@ endif() cmake_dependent_option(YUZU_USE_EXTERNAL_SDL2 "Build SDL2 from external source" OFF "NOT MSVC;NOT ANDROID" OFF) cmake_dependent_option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${EXT_DEFAULT}" "NOT ANDROID" OFF) -option(ENABLE_CUBEB "Enables the cubeb audio backend" ON) +# TODO(crueter): did not find header 'AudioHardware.h' in framework 'CoreAudio' +cmake_dependent_option(ENABLE_CUBEB "Enables the cubeb audio backend" ON "NOT IOS" OFF) # ffmpeg option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT}) @@ -194,7 +224,7 @@ endif() option(YUZU_USE_BUNDLED_SIRIT "Download bundled sirit" ${BUNDLED_SIRIT_DEFAULT}) # FreeBSD 15+ has libusb, versions below should disable it -cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR PLATFORM_LINUX OR PLATFORM_FREEBSD OR APPLE" OFF) +cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR PLATFORM_LINUX OR PLATFORM_FREEBSD OR (APPLE AND NOT IOS)" OFF) cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT (WIN32 AND ARCHITECTURE_arm64) AND NOT APPLE" OFF) mark_as_advanced(FORCE ENABLE_OPENGL) diff --git a/externals/cmake-modules/DetectArchitecture.cmake b/externals/cmake-modules/DetectArchitecture.cmake index c4fd9e1ec3..a7e60eba30 100644 --- a/externals/cmake-modules/DetectArchitecture.cmake +++ b/externals/cmake-modules/DetectArchitecture.cmake @@ -35,7 +35,7 @@ This file is based off of Yuzu and Dynarmic. # Do note that situations where multiple architectures are defined # should NOT be too dependent on the architecture # otherwise, you may end up with duplicate code -if (CMAKE_OSX_ARCHITECTURES) +if (DEFINED CMAKE_OSX_ARCHITECTURES) set(MULTIARCH_BUILD 1) set(ARCHITECTURE "${CMAKE_OSX_ARCHITECTURES}") if (IOS) diff --git a/externals/libusb/CMakeLists.txt b/externals/libusb/CMakeLists.txt index 47b54f43cc..361e43a832 100644 --- a/externals/libusb/CMakeLists.txt +++ b/externals/libusb/CMakeLists.txt @@ -24,7 +24,8 @@ if (MINGW OR PLATFORM_LINUX OR APPLE) message(FATAL_ERROR "Required program `autoconf` not found.") endif() - find_program(LIBTOOLIZE libtoolize) + find_program(LIBTOOLIZE + NAMES libtoolize glibtoolize) if ("${LIBTOOLIZE}" STREQUAL "LIBTOOLIZE-NOTFOUND") message(FATAL_ERROR "Required program `libtoolize` not found.") endif() diff --git a/src/ios/AppUI.swift b/src/ios/AppUI.swift index dd1706ae23..b1d95324cc 100644 --- a/src/ios/AppUI.swift +++ b/src/ios/AppUI.swift @@ -7,7 +7,6 @@ import UIKit import Foundation import QuartzCore.CAMetalLayer -@main public struct AppUI { public static let shared = AppUI() diff --git a/src/ios/CMakeLists.txt b/src/ios/CMakeLists.txt index 525c182261..98b2585a5b 100644 --- a/src/ios/CMakeLists.txt +++ b/src/ios/CMakeLists.txt @@ -20,15 +20,54 @@ add_executable(eden-ios PomeloApp.swift ContentView.swift ) + +set(MACOSX_BUNDLE_GUI_IDENTIFIER "dev.eden-emu.eden") +set(MACOSX_BUNDLE_BUNDLE_NAME "Eden") +set(MACOSX_BUNDLE_INFO_STRING "Eden: A high-performance Nintendo Switch emulator") + +# TODO(crueter): Copyright, and versioning + # Keep bundle identifier as-is, for compatibility sake set_target_properties(eden-ios PROPERTIES - XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.yuzu-emu.yuzu" - XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "YUZU1234" XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/AppUI-Bridging-Header.h" XCODE_ATTRIBUTE_SWIFT_OBJC_INTERFACE_HEADER_NAME "eden-ios-Swift.h" - XCODE_ATTRIBUTE_DERIVED_FILE_DIR "${CMAKE_CURRENT_BINARY_DIR}" -) + XCODE_ATTRIBUTE_DERIVED_FILE_DIR "${CMAKE_CURRENT_BINARY_DIR}") + target_link_libraries(eden-ios PRIVATE common core input_common frontend_common video_core sirit::sirit) target_link_libraries(eden-ios PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) target_link_libraries(eden-ios PRIVATE SDL2::SDL2 glad stb::headers) create_target_directory_groups(eden-ios) + +# FIXME(crueter): This should /all/ be in a module of some kind! + +# Xcode will automatically generate the Assets.car and icns file for us. +set(_dist "${CMAKE_SOURCE_DIR}/dist") +if (CMAKE_GENERATOR MATCHES "Xcode") + set(_icons "${_dist}/eden.icon") + + set_target_properties(eden-ios PROPERTIES + XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME eden + MACOSX_BUNDLE_ICON_FILE eden + # Also force xcode to manage signing for us. + XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED ON + XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED ON + XCODE_ATTRIBUTE_CODE_SIGN_STYLE Automatic) +# Otherwise, we'll use our own. +else() + set(_icons "${_dist}/eden.icns" "${_dist}/Assets.car") +endif() + +set_source_files_properties(${_icons} PROPERTIES + MACOSX_PACKAGE_LOCATION Resources) +target_sources(eden-ios PRIVATE ${_icons}) + +set_target_properties(eden-ios PROPERTIES MACOSX_BUNDLE TRUE) + +set(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib") +find_library(MOLTENVK_LIBRARY MoltenVK REQUIRED) +message(STATUS "Using MoltenVK at ${MOLTENVK_LIBRARY}.") + +set_source_files_properties(${MOLTENVK_LIBRARY} PROPERTIES + MACOSX_PACKAGE_LOCATION Frameworks + XCODE_FILE_ATTRIBUTES "CodeSignOnCopy") +target_sources(eden-ios PRIVATE ${MOLTENVK_LIBRARY}) diff --git a/src/ios/ContentView.swift b/src/ios/ContentView.swift index 9ebe0622d7..877af33fcb 100644 --- a/src/ios/ContentView.swift +++ b/src/ios/ContentView.swift @@ -4,16 +4,16 @@ // SPDX-License-Identifier: GPL-3.0-or-later import SwiftUI -import Sudachi +//import AppUI struct ContentView: View { - @State var core = Core(games: [], root: FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]) +// @State var core = Core(games: [], root: FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]) var body: some View { - HomeView(core: core).onAppear() { - Air.play(AnyView( - Text("Select Game").font(.system(size: 100)) - )) - // rest of death - } +// HomeView(core: core).onAppear() { +// Air.play(AnyView( +// Text("Select Game").font(.system(size: 100)) +// )) +// // rest of death +// } } } diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 1ed1fdff2a..d94487ec79 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -369,7 +369,7 @@ if (APPLE) if (CMAKE_GENERATOR MATCHES "Xcode") set(_icons "${_dist}/eden.icon") - set_target_properties(eden PROPERTIES + set_target_properties(yuzu PROPERTIES XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME eden MACOSX_BUNDLE_ICON_FILE eden # Also force xcode to manage signing for us. From 7624914c35a31b9ef8d34133d001f2ff076be07c Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 28 Mar 2026 06:17:48 +0000 Subject: [PATCH 51/54] AAAAAA --- src/ios/AppUIObjC.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ios/AppUIObjC.h b/src/ios/AppUIObjC.h index 921f333199..942cd111a7 100644 --- a/src/ios/AppUIObjC.h +++ b/src/ios/AppUIObjC.h @@ -5,6 +5,7 @@ #import #import +#import #import "AppUIGameInformation.h" From 1a5ca6f4aa50ea7cf53cc65283185aaa442f6b27 Mon Sep 17 00:00:00 2001 From: crueter Date: Sat, 28 Mar 2026 16:47:52 -0400 Subject: [PATCH 52/54] Fix build script Signed-off-by: crueter --- .ci/ios/build.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.ci/ios/build.sh b/.ci/ios/build.sh index cd3a57ec32..f0d6147993 100755 --- a/.ci/ios/build.sh +++ b/.ci/ios/build.sh @@ -9,12 +9,10 @@ xcrun --sdk iphoneos --show-sdk-path # TODO: support iphonesimulator sdk cmake -G Xcode -B build/ios \ - -DCMAKE_TOOLCHAIN_FILE="$WORK_DIR/.ci/ios/ios-toolchain.cmake" \ - -DPLATFORM=OS64 \ - -DARCHS="arm64" \ - -DDEPLOYMENT_TARGET=16.0 \ - -DCMAKE_C_COMPILER="$(xcrun --sdk iphoneos --find clang)" \ - -DCMAKE_CXX_COMPILER="$(xcrun --sdk iphoneos --find clang++)" \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=16.0 \ + -DCMAKE_OSX_SYSROOT=iphoneos \ + -DCMAKE_SYSTEM_NAME=iOS \ + -DCMAKE_OSX_ARCHITECTURES="arm64" \ -DCMAKE_BUILD_TYPE=Release \ "$@" From 6986084ef4ed87933309d24ff73230760afebb7b Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 30 Mar 2026 06:43:12 +0000 Subject: [PATCH 53/54] remove toolchain file + remove multibuild thingy --- .ci/ios/ios-toolchain.cmake | 1180 ----------------- externals/ffmpeg/CMakeLists.txt | 1 + .../TargetArchitectureSpecificSources.cmake | 29 - src/dynarmic/src/dynarmic/CMakeLists.txt | 5 +- src/dynarmic/tests/CMakeLists.txt | 3 +- 5 files changed, 4 insertions(+), 1214 deletions(-) delete mode 100644 .ci/ios/ios-toolchain.cmake delete mode 100644 src/dynarmic/CMakeModules/TargetArchitectureSpecificSources.cmake diff --git a/.ci/ios/ios-toolchain.cmake b/.ci/ios/ios-toolchain.cmake deleted file mode 100644 index 5eed07b32f..0000000000 --- a/.ci/ios/ios-toolchain.cmake +++ /dev/null @@ -1,1180 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -# SPDX-License-Identifier: GPL-3.0-or-later - -# This file is part of the ios-cmake project. It was retrieved from -# https://github.com/leetal/ios-cmake.git, which is a fork of -# https://github.com/gerstrong/ios-cmake.git, which is a fork of -# https://github.com/cristeab/ios-cmake.git, which is a fork of -# https://code.google.com/p/ios-cmake/. Which in turn is based off of -# the Platform/Darwin.cmake and Platform/UnixPaths.cmake files which -# are included with CMake 2.8.4 -# -# The ios-cmake project is licensed under the new BSD license. -# -# Copyright (c) 2014, Bogdan Cristea and LTE Engineering Software, -# Kitware, Inc., Insight Software Consortium. All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -# This file is based on the Platform/Darwin.cmake and -# Platform/UnixPaths.cmake files which are included with CMake 2.8.4 -# It has been altered for iOS development. -# -# Updated by Alex Stewart (alexs.mac@gmail.com) -# -# ***************************************************************************** -# Now maintained by Alexander Widerberg (widerbergaren [at] gmail.com) -# under the BSD-3-Clause license -# https://github.com/leetal/ios-cmake -# ***************************************************************************** -# -# INFORMATION / HELP -# -############################################################################### -# OPTIONS # -############################################################################### -# -# PLATFORM: (default "OS64") -# OS = Build for iPhoneOS. -# OS64 = Build for arm64 iphoneOS. -# OS64COMBINED = Build for arm64 x86_64 iphoneOS + iphoneOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) -# SIMULATOR = Build for x86 i386 iphoneOS Simulator. -# SIMULATOR64 = Build for x86_64 iphoneOS Simulator. -# SIMULATORARM64 = Build for arm64 iphoneOS Simulator. -# SIMULATOR64COMBINED = Build for arm64 x86_64 iphoneOS Simulator. Combined into FAT STATIC lib (supported on 3.14+ of CMakewith "-G Xcode" argument ONLY) -# TVOS = Build for arm64 tvOS. -# TVOSCOMBINED = Build for arm64 x86_64 tvOS + tvOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) -# SIMULATOR_TVOS = Build for x86_64 tvOS Simulator. -# SIMULATORARM64_TVOS = Build for arm64 tvOS Simulator. -# VISIONOSCOMBINED = Build for arm64 visionOS + visionOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) -# VISIONOS = Build for arm64 visionOS. -# SIMULATOR_VISIONOS = Build for arm64 visionOS Simulator. -# WATCHOS = Build for armv7k arm64_32 for watchOS. -# WATCHOSCOMBINED = Build for armv7k arm64_32 x86_64 watchOS + watchOS Simulator. Combined into FAT STATIC lib (only supported on 3.14+ of CMake with "-G Xcode" argument in combination with the "cmake --install" CMake build step) -# SIMULATOR_WATCHOS = Build for x86_64 for watchOS Simulator. -# SIMULATORARM64_WATCHOS = Build for arm64 for watchOS Simulator. -# SIMULATOR_WATCHOSCOMBINED = Build for arm64 x86_64 for watchOS Simulator. Combined into FAT STATIC lib (supported on 3.14+ of CMakewith "-G Xcode" argument ONLY) -# MAC = Build for x86_64 macOS. -# MAC_ARM64 = Build for Apple Silicon macOS. -# MAC_UNIVERSAL = Combined build for x86_64 and Apple Silicon on macOS. -# MAC_CATALYST = Build for x86_64 macOS with Catalyst support (iOS toolchain on macOS). -# Note: The build argument "MACOSX_DEPLOYMENT_TARGET" can be used to control min-version of macOS -# MAC_CATALYST_ARM64 = Build for Apple Silicon macOS with Catalyst support (iOS toolchain on macOS). -# Note: The build argument "MACOSX_DEPLOYMENT_TARGET" can be used to control min-version of macOS -# MAC_CATALYST_UNIVERSAL = Combined build for x86_64 and Apple Silicon on Catalyst. -# -# CMAKE_OSX_SYSROOT: Path to the SDK to use. By default this is -# automatically determined from PLATFORM and xcodebuild, but -# can also be manually specified (although this should not be required). -# -# CMAKE_DEVELOPER_ROOT: Path to the Developer directory for the platform -# being compiled for. By default, this is automatically determined from -# CMAKE_OSX_SYSROOT, but can also be manually specified (although this should -# not be required). -# -# DEPLOYMENT_TARGET: Minimum SDK version to target. Default 6.0 on watchOS, 13.0 on tvOS+iOS/iPadOS, 11.0 on macOS, 1.0 on visionOS -# -# NAMED_LANGUAGE_SUPPORT: -# ON (default) = Will require "enable_language(OBJC) and/or enable_language(OBJCXX)" for full OBJC|OBJCXX support -# OFF = Will embed the OBJC and OBJCXX flags into the CMAKE_C_FLAGS and CMAKE_CXX_FLAGS (legacy behavior, CMake version < 3.16) -# -# ENABLE_BITCODE: (ON|OFF) Enables or disables bitcode support. Default OFF -# -# ENABLE_ARC: (ON|OFF) Enables or disables ARC support. Default ON (ARC enabled by default) -# -# ENABLE_VISIBILITY: (ON|OFF) Enables or disables symbol visibility support. Default OFF (visibility hidden by default) -# -# ENABLE_STRICT_TRY_COMPILE: (ON|OFF) Enables or disables strict try_compile() on all Check* directives (will run linker -# to actually check if linking is possible). Default OFF (will set CMAKE_TRY_COMPILE_TARGET_TYPE to STATIC_LIBRARY) -# -# ARCHS: (armv7 armv7s armv7k arm64 arm64_32 i386 x86_64) If specified, will override the default architectures for the given PLATFORM -# OS = armv7 armv7s arm64 (if applicable) -# OS64 = arm64 (if applicable) -# SIMULATOR = i386 -# SIMULATOR64 = x86_64 -# SIMULATORARM64 = arm64 -# TVOS = arm64 -# SIMULATOR_TVOS = x86_64 (i386 has since long been deprecated) -# SIMULATORARM64_TVOS = arm64 -# WATCHOS = armv7k arm64_32 (if applicable) -# SIMULATOR_WATCHOS = x86_64 (i386 has since long been deprecated) -# SIMULATORARM64_WATCHOS = arm64 -# MAC = x86_64 -# MAC_ARM64 = arm64 -# MAC_UNIVERSAL = x86_64 arm64 -# MAC_CATALYST = x86_64 -# MAC_CATALYST_ARM64 = arm64 -# MAC_CATALYST_UNIVERSAL = x86_64 arm64 -# -# NOTE: When manually specifying ARCHS, put a semi-colon between the entries. E.g., -DARCHS="armv7;arm64" -# -############################################################################### -# END OPTIONS # -############################################################################### -# -# This toolchain defines the following properties (available via get_property()) for use externally: -# -# PLATFORM: The currently targeted platform. -# XCODE_VERSION: Version number (not including Build version) of Xcode detected. -# SDK_VERSION: Version of SDK being used. -# OSX_ARCHITECTURES: Architectures being compiled for (generated from PLATFORM). -# APPLE_TARGET_TRIPLE: Used by autoconf build systems. NOTE: If "ARCHS" is overridden, this will *NOT* be set! -# -# This toolchain defines the following macros for use externally: -# -# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE XCODE_VARIANT) -# A convenience macro for setting xcode specific properties on targets. -# Available variants are: All, Release, RelWithDebInfo, Debug, MinSizeRel -# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1" "all"). -# -# find_host_package (PROGRAM ARGS) -# A macro used to find executable programs on the host system, not within the -# environment. Thanks to the android-cmake project for providing the -# command. -# - -cmake_minimum_required(VERSION 3.10) - -# CMake invokes the toolchain file twice during the first build, but only once during subsequent rebuilds. -# NOTE: To improve single-library build-times, provide the flag "OS_SINGLE_BUILD" as a build argument. -if(DEFINED OS_SINGLE_BUILD AND DEFINED ENV{_IOS_TOOLCHAIN_HAS_RUN}) - return() -endif() -set(ENV{_IOS_TOOLCHAIN_HAS_RUN} true) - -# List of supported platform values -list(APPEND _supported_platforms - "OS" "OS64" "OS64COMBINED" "SIMULATOR" "SIMULATOR64" "SIMULATORARM64" "SIMULATOR64COMBINED" - "TVOS" "TVOSCOMBINED" "SIMULATOR_TVOS" "SIMULATORARM64_TVOS" - "WATCHOS" "WATCHOSCOMBINED" "SIMULATOR_WATCHOS" "SIMULATORARM64_WATCHOS" "SIMULATOR_WATCHOSCOMBINED" - "MAC" "MAC_ARM64" "MAC_UNIVERSAL" - "VISIONOS" "SIMULATOR_VISIONOS" "VISIONOSCOMBINED" - "MAC_CATALYST" "MAC_CATALYST_ARM64" "MAC_CATALYST_UNIVERSAL") - -# Cache what generator is used -set(USED_CMAKE_GENERATOR "${CMAKE_GENERATOR}") - -# Check if using a CMake version capable of building combined FAT builds (simulator and target slices combined in one static lib) -if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14") - set(MODERN_CMAKE YES) -endif() - -# Get the Xcode version being used. -# Problem: CMake runs toolchain files multiple times, but can't read cache variables on some runs. -# Workaround: On the first run (in which cache variables are always accessible), set an intermediary environment variable. -# -# NOTE: This pattern is used in many places in this toolchain to speed up checks of all sorts -if(DEFINED XCODE_VERSION_INT) - # Environment variables are always preserved. - set(ENV{_XCODE_VERSION_INT} "${XCODE_VERSION_INT}") -elseif(DEFINED ENV{_XCODE_VERSION_INT}) - set(XCODE_VERSION_INT "$ENV{_XCODE_VERSION_INT}") -elseif(NOT DEFINED XCODE_VERSION_INT) - find_program(XCODEBUILD_EXECUTABLE xcodebuild) - if(NOT XCODEBUILD_EXECUTABLE) - message(FATAL_ERROR "xcodebuild not found. Please install either the standalone commandline tools or Xcode.") - endif() - execute_process(COMMAND ${XCODEBUILD_EXECUTABLE} -version - OUTPUT_VARIABLE XCODE_VERSION_INT - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - string(REGEX MATCH "Xcode [0-9\\.]+" XCODE_VERSION_INT "${XCODE_VERSION_INT}") - string(REGEX REPLACE "Xcode ([0-9\\.]+)" "\\1" XCODE_VERSION_INT "${XCODE_VERSION_INT}") - set(XCODE_VERSION_INT "${XCODE_VERSION_INT}" CACHE INTERNAL "") -endif() - -# Assuming that xcode 12.0 is installed you most probably have ios sdk 14.0 or later installed (tested on Big Sur) -# if you don't set a deployment target it will be set the way you only get 64-bit builds -#if(NOT DEFINED DEPLOYMENT_TARGET AND XCODE_VERSION_INT VERSION_GREATER 12.0) -# Temporarily fix the arm64 issues in CMake install-combined by excluding arm64 for simulator builds (needed for Apple Silicon...) -# set(CMAKE_XCODE_ATTRIBUTE_EXCLUDED_ARCHS[sdk=iphonesimulator*] "arm64") -#endif() - -# Check if the platform variable is set -if(DEFINED PLATFORM) - # Environment variables are always preserved. - set(ENV{_PLATFORM} "${PLATFORM}") -elseif(DEFINED ENV{_PLATFORM}) - set(PLATFORM "$ENV{_PLATFORM}") -elseif(NOT DEFINED PLATFORM) - message(FATAL_ERROR "PLATFORM argument not set. Bailing configure since I don't know what target you want to build for!") -endif () - -if(PLATFORM MATCHES ".*COMBINED" AND NOT CMAKE_GENERATOR MATCHES "Xcode") - message(FATAL_ERROR "The combined builds support requires Xcode to be used as a generator via '-G Xcode' command-line argument in CMake") -endif() - -# Safeguard that the platform value is set and is one of the supported values -list(FIND _supported_platforms ${PLATFORM} contains_PLATFORM) -if("${contains_PLATFORM}" EQUAL "-1") - string(REPLACE ";" "\n * " _supported_platforms_formatted "${_supported_platforms}") - message(FATAL_ERROR " Invalid PLATFORM specified! Current value: ${PLATFORM}.\n" - " Supported PLATFORM values: \n * ${_supported_platforms_formatted}") -endif() - -# Check if Apple Silicon is supported -if(PLATFORM MATCHES "^(MAC_ARM64)$|^(MAC_CATALYST_ARM64)$|^(MAC_UNIVERSAL)$|^(MAC_CATALYST_UNIVERSAL)$" AND ${CMAKE_VERSION} VERSION_LESS "3.19.5") - message(FATAL_ERROR "Apple Silicon builds requires a minimum of CMake 3.19.5") -endif() - -# Touch the toolchain variable to suppress the "unused variable" warning. -# This happens if CMake is invoked with the same command line the second time. -if(CMAKE_TOOLCHAIN_FILE) -endif() - -# Fix for PThread library not in path -set(CMAKE_THREAD_LIBS_INIT "-lpthread") -set(CMAKE_HAVE_THREADS_LIBRARY 1) -set(CMAKE_USE_WIN32_THREADS_INIT 0) -set(CMAKE_USE_PTHREADS_INIT 1) - -# Specify named language support defaults. -if(NOT DEFINED NAMED_LANGUAGE_SUPPORT AND ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16") - set(NAMED_LANGUAGE_SUPPORT ON) - message(STATUS "[DEFAULTS] Using explicit named language support! E.g., enable_language(CXX) is needed in the project files.") -elseif(NOT DEFINED NAMED_LANGUAGE_SUPPORT AND ${CMAKE_VERSION} VERSION_LESS "3.16") - set(NAMED_LANGUAGE_SUPPORT OFF) - message(STATUS "[DEFAULTS] Disabling explicit named language support. Falling back to legacy behavior.") -elseif(DEFINED NAMED_LANGUAGE_SUPPORT AND ${CMAKE_VERSION} VERSION_LESS "3.16") - message(FATAL_ERROR "CMake named language support for OBJC and OBJCXX was added in CMake 3.16.") -endif() -set(NAMED_LANGUAGE_SUPPORT_INT ${NAMED_LANGUAGE_SUPPORT} CACHE BOOL - "Whether or not to enable explicit named language support" FORCE) - -# Specify the minimum version of the deployment target. -if(NOT DEFINED DEPLOYMENT_TARGET) - if (PLATFORM MATCHES "WATCHOS") - # Unless specified, SDK version 6.0 is used by default as minimum target version (watchOS). - set(DEPLOYMENT_TARGET "6.0") - elseif(PLATFORM STREQUAL "MAC") - # Unless specified, SDK version 11.0 (Big Sur) is used by default as the minimum target version (macOS on x86). - set(DEPLOYMENT_TARGET "11.0") - elseif(PLATFORM STREQUAL "VISIONOS" OR PLATFORM STREQUAL "SIMULATOR_VISIONOS" OR PLATFORM STREQUAL "VISIONOSCOMBINED") - # Unless specified, SDK version 1.0 is used by default as minimum target version (visionOS). - set(DEPLOYMENT_TARGET "1.0") - elseif(PLATFORM STREQUAL "MAC_ARM64") - # Unless specified, SDK version 11.0 (Big Sur) is used by default as the minimum target version (macOS on arm). - set(DEPLOYMENT_TARGET "11.0") - elseif(PLATFORM STREQUAL "MAC_UNIVERSAL") - # Unless specified, SDK version 11.0 (Big Sur) is used by default as minimum target version for universal builds. - set(DEPLOYMENT_TARGET "11.0") - elseif(PLATFORM STREQUAL "MAC_CATALYST" OR PLATFORM STREQUAL "MAC_CATALYST_ARM64" OR PLATFORM STREQUAL "MAC_CATALYST_UNIVERSAL") - # Unless specified, SDK version 13.1 is used by default as the minimum target version (mac catalyst minimum requirement). - set(DEPLOYMENT_TARGET "13.1") - else() - # Unless specified, SDK version 13.0 is used by default as the minimum target version (iOS, tvOS). - set(DEPLOYMENT_TARGET "13.0") - endif() - message(STATUS "[DEFAULTS] Using the default min-version since DEPLOYMENT_TARGET not provided!") -elseif(DEFINED DEPLOYMENT_TARGET AND PLATFORM MATCHES "^MAC_CATALYST" AND ${DEPLOYMENT_TARGET} VERSION_LESS "13.1") - message(FATAL_ERROR "Mac Catalyst builds requires a minimum deployment target of 13.1!") -endif() - -# Store the DEPLOYMENT_TARGET in the cache -set(DEPLOYMENT_TARGET "${DEPLOYMENT_TARGET}" CACHE INTERNAL "") - -# Handle the case where we are targeting iOS and a version above 10.3.4 (32-bit support dropped officially) -if(PLATFORM STREQUAL "OS" AND DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.3.4) - set(PLATFORM "OS64") - message(STATUS "Targeting minimum SDK version ${DEPLOYMENT_TARGET}. Dropping 32-bit support.") -elseif(PLATFORM STREQUAL "SIMULATOR" AND DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.3.4) - set(PLATFORM "SIMULATOR64") - message(STATUS "Targeting minimum SDK version ${DEPLOYMENT_TARGET}. Dropping 32-bit support.") -endif() - -set(PLATFORM_INT "${PLATFORM}") - -if(DEFINED ARCHS) - string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") -endif() - -# Determine the platform name and architectures for use in xcodebuild commands -# from the specified PLATFORM_INT name. -if(PLATFORM_INT STREQUAL "OS") - set(SDK_NAME iphoneos) - if(NOT ARCHS) - set(ARCHS armv7 armv7s arm64) - set(APPLE_TARGET_TRIPLE_INT arm-apple-ios${DEPLOYMENT_TARGET}) - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}) - endif() -elseif(PLATFORM_INT STREQUAL "OS64") - set(SDK_NAME iphoneos) - if(NOT ARCHS) - if (XCODE_VERSION_INT VERSION_GREATER 10.0) - set(ARCHS arm64) # FIXME: Add arm64e when Apple has fixed the integration issues with it, libarclite_iphoneos.a is currently missing bitcode markers for example - else() - set(ARCHS arm64) - endif() - set(APPLE_TARGET_TRIPLE_INT arm64-apple-ios${DEPLOYMENT_TARGET}) - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}) - endif() -elseif(PLATFORM_INT STREQUAL "OS64COMBINED") - set(SDK_NAME iphoneos) - if(MODERN_CMAKE) - if(NOT ARCHS) - if (XCODE_VERSION_INT VERSION_GREATER 12.0) - set(ARCHS arm64 x86_64) - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "arm64") - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "arm64") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") - else() - set(ARCHS arm64 x86_64) - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "arm64") - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "arm64") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64") - endif() - set(APPLE_TARGET_TRIPLE_INT arm64-x86_64-apple-ios${DEPLOYMENT_TARGET}) - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}) - endif() - else() - message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the OS64COMBINED setting work") - endif() -elseif(PLATFORM_INT STREQUAL "SIMULATOR64COMBINED") - set(SDK_NAME iphonesimulator) - if(MODERN_CMAKE) - if(NOT ARCHS) - if (XCODE_VERSION_INT VERSION_GREATER 12.0) - set(ARCHS arm64 x86_64) # FIXME: Add arm64e when Apple have fixed the integration issues with it, libarclite_iphoneos.a is currently missing bitcode markers for example - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "") - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64 arm64") - else() - set(ARCHS arm64 x86_64) - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "") - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64") - endif() - set(APPLE_TARGET_TRIPLE_INT aarch64-x86_64-apple-ios${DEPLOYMENT_TARGET}-simulator) - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) - endif() - else() - message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the SIMULATOR64COMBINED setting work") - endif() -elseif(PLATFORM_INT STREQUAL "SIMULATOR") - set(SDK_NAME iphonesimulator) - if(NOT ARCHS) - set(ARCHS i386) - set(APPLE_TARGET_TRIPLE_INT i386-apple-ios${DEPLOYMENT_TARGET}-simulator) - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) - endif() - message(DEPRECATION "SIMULATOR IS DEPRECATED. Consider using SIMULATOR64 instead.") -elseif(PLATFORM_INT STREQUAL "SIMULATOR64") - set(SDK_NAME iphonesimulator) - if(NOT ARCHS) - set(ARCHS x86_64) - set(APPLE_TARGET_TRIPLE_INT x86_64-apple-ios${DEPLOYMENT_TARGET}-simulator) - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) - endif() -elseif(PLATFORM_INT STREQUAL "SIMULATORARM64") - set(SDK_NAME iphonesimulator) - if(NOT ARCHS) - set(ARCHS arm64) - set(APPLE_TARGET_TRIPLE_INT arm64-apple-ios${DEPLOYMENT_TARGET}-simulator) - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) - endif() -elseif(PLATFORM_INT STREQUAL "TVOS") - set(SDK_NAME appletvos) - if(NOT ARCHS) - set(ARCHS arm64) - set(APPLE_TARGET_TRIPLE_INT arm64-apple-tvos${DEPLOYMENT_TARGET}) - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}) - endif() -elseif (PLATFORM_INT STREQUAL "TVOSCOMBINED") - set(SDK_NAME appletvos) - if(MODERN_CMAKE) - if(NOT ARCHS) - set(ARCHS arm64 x86_64) - set(APPLE_TARGET_TRIPLE_INT arm64-x86_64-apple-tvos${DEPLOYMENT_TARGET}) - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=appletvos*] "arm64") - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=appletvsimulator*] "x86_64 arm64") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=appletvos*] "arm64") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=appletvsimulator*] "x86_64 arm64") - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}) - endif() - else() - message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the TVOSCOMBINED setting work") - endif() -elseif(PLATFORM_INT STREQUAL "SIMULATOR_TVOS") - set(SDK_NAME appletvsimulator) - if(NOT ARCHS) - set(ARCHS x86_64) - set(APPLE_TARGET_TRIPLE_INT x86_64-apple-tvos${DEPLOYMENT_TARGET}-simulator) - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}-simulator) - endif() -elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_TVOS") - set(SDK_NAME appletvsimulator) - if(NOT ARCHS) - set(ARCHS arm64) - set(APPLE_TARGET_TRIPLE_INT arm64-apple-tvos${DEPLOYMENT_TARGET}-simulator) - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}-simulator) - endif() -elseif(PLATFORM_INT STREQUAL "WATCHOS") - set(SDK_NAME watchos) - if(NOT ARCHS) - if (XCODE_VERSION_INT VERSION_GREATER 10.0) - set(ARCHS armv7k arm64_32) - set(APPLE_TARGET_TRIPLE_INT arm64_32-apple-watchos${DEPLOYMENT_TARGET}) - else() - set(ARCHS armv7k) - set(APPLE_TARGET_TRIPLE_INT arm-apple-watchos${DEPLOYMENT_TARGET}) - endif() - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}) - endif() -elseif(PLATFORM_INT STREQUAL "WATCHOSCOMBINED") - set(SDK_NAME watchos) - if(MODERN_CMAKE) - if(NOT ARCHS) - if (XCODE_VERSION_INT VERSION_GREATER 10.0) - set(ARCHS armv7k arm64_32 x86_64) - set(APPLE_TARGET_TRIPLE_INT arm64_32-x86_64-apple-watchos${DEPLOYMENT_TARGET}) - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchos*] "armv7k arm64_32") - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchsimulator*] "x86_64") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchos*] "armv7k arm64_32") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchsimulator*] "x86_64") - else() - set(ARCHS armv7k i386) - set(APPLE_TARGET_TRIPLE_INT arm-i386-apple-watchos${DEPLOYMENT_TARGET}) - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchos*] "armv7k") - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchsimulator*] "i386") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchos*] "armv7k") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchsimulator*] "i386") - endif() - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}) - endif() - else() - message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the WATCHOSCOMBINED setting work") - endif() -elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOS") - set(SDK_NAME watchsimulator) - if(NOT ARCHS) - if (XCODE_VERSION_INT VERSION_GREATER 10.0) - set(ARCHS x86_64) - set(APPLE_TARGET_TRIPLE_INT x86_64-apple-watchos${DEPLOYMENT_TARGET}-simulator) - else() - set(ARCHS i386) - set(APPLE_TARGET_TRIPLE_INT i386-apple-watchos${DEPLOYMENT_TARGET}-simulator) - endif() - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}-simulator) - endif() -elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_WATCHOS") - set(SDK_NAME watchsimulator) - if(NOT ARCHS) - set(ARCHS arm64) - set(APPLE_TARGET_TRIPLE_INT arm64-apple-watchos${DEPLOYMENT_TARGET}-simulator) - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}-simulator) - endif() -elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOSCOMBINED") - set(SDK_NAME watchsimulator) - if(MODERN_CMAKE) - if(NOT ARCHS) - if (XCODE_VERSION_INT VERSION_GREATER 12.0) - set(ARCHS arm64 x86_64) - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchos*] "") - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchsimulator*] "arm64 x86_64") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchos*] "") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchsimulator*] "arm64 x86_64") - set(APPLE_TARGET_TRIPLE_INT arm64_x86_64-apple-watchos${DEPLOYMENT_TARGET}-simulator) - else() - set(ARCHS arm64 i386) - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchos*] "") - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchsimulator*] "i386") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchos*] "") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchsimulator*] "i386") - set(APPLE_TARGET_TRIPLE_INT arm64_i386-apple-watchos${DEPLOYMENT_TARGET}-simulator) - endif() - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}-simulator) - endif() - else() - message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the SIMULATOR_WATCHOSCOMBINED setting work") - endif() -elseif(PLATFORM_INT STREQUAL "SIMULATOR_VISIONOS") - set(SDK_NAME xrsimulator) - if(NOT ARCHS) - set(ARCHS arm64) - set(APPLE_TARGET_TRIPLE_INT arm64-apple-xros${DEPLOYMENT_TARGET}-simulator) - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-xros${DEPLOYMENT_TARGET}-simulator) - endif() -elseif(PLATFORM_INT STREQUAL "VISIONOS") - set(SDK_NAME xros) - if(NOT ARCHS) - set(ARCHS arm64) - set(APPLE_TARGET_TRIPLE_INT arm64-apple-xros${DEPLOYMENT_TARGET}) - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-xros${DEPLOYMENT_TARGET}) - endif() -elseif(PLATFORM_INT STREQUAL "VISIONOSCOMBINED") - set(SDK_NAME xros) - if(MODERN_CMAKE) - if(NOT ARCHS) - set(ARCHS arm64) - set(APPLE_TARGET_TRIPLE_INT arm64-apple-xros${DEPLOYMENT_TARGET}) - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=xros*] "arm64") - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=xrsimulator*] "arm64") - else() - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-xros${DEPLOYMENT_TARGET}) - endif() - else() - message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the VISIONOSCOMBINED setting work") - endif() -elseif(PLATFORM_INT STREQUAL "MAC" OR PLATFORM_INT STREQUAL "MAC_CATALYST") - set(SDK_NAME macosx) - if(NOT ARCHS) - set(ARCHS x86_64) - endif() - string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") - if(PLATFORM_INT STREQUAL "MAC") - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-macosx${DEPLOYMENT_TARGET}) - elseif(PLATFORM_INT STREQUAL "MAC_CATALYST") - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-macabi) - endif() -elseif(PLATFORM_INT MATCHES "^(MAC_ARM64)$|^(MAC_CATALYST_ARM64)$") - set(SDK_NAME macosx) - if(NOT ARCHS) - set(ARCHS arm64) - endif() - string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") - if(PLATFORM_INT STREQUAL "MAC_ARM64") - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-macosx${DEPLOYMENT_TARGET}) - elseif(PLATFORM_INT STREQUAL "MAC_CATALYST_ARM64") - set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-macabi) - endif() -elseif(PLATFORM_INT STREQUAL "MAC_UNIVERSAL") - set(SDK_NAME macosx) - if(NOT ARCHS) - set(ARCHS "x86_64;arm64") - endif() - # For universal builds, don't set target triple - let CMake handle it - # string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") - # set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-macosx${DEPLOYMENT_TARGET}) -elseif(PLATFORM_INT STREQUAL "MAC_CATALYST_UNIVERSAL") - set(SDK_NAME macosx) - if(NOT ARCHS) - set(ARCHS "x86_64;arm64") - endif() - string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") - set(APPLE_TARGET_TRIPLE_INT apple-ios${DEPLOYMENT_TARGET}-macabi) -else() - message(FATAL_ERROR "Invalid PLATFORM: ${PLATFORM_INT}") -endif() - -string(REPLACE ";" " " ARCHS_SPACED "${ARCHS}") - -if(MODERN_CMAKE AND PLATFORM_INT MATCHES ".*COMBINED" AND NOT CMAKE_GENERATOR MATCHES "Xcode") - message(FATAL_ERROR "The COMBINED options only work with Xcode generator, -G Xcode") -endif() - -if(CMAKE_GENERATOR MATCHES "Xcode" AND PLATFORM_INT MATCHES "^MAC_CATALYST") - set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") - set(CMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS "macosx") - set(CMAKE_XCODE_ATTRIBUTE_SUPPORTS_MACCATALYST "YES") - if(NOT DEFINED MACOSX_DEPLOYMENT_TARGET) - set(CMAKE_XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "10.15") - else() - set(CMAKE_XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "${MACOSX_DEPLOYMENT_TARGET}") - endif() -elseif(CMAKE_GENERATOR MATCHES "Xcode") - set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") - set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "${DEPLOYMENT_TARGET}") - if(NOT PLATFORM_INT MATCHES ".*COMBINED") - set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=${SDK_NAME}*] "${ARCHS_SPACED}") - set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=${SDK_NAME}*] "${ARCHS_SPACED}") - endif() -endif() - -# If the user did not specify the SDK root to use, then query xcodebuild for it. -if(DEFINED CMAKE_OSX_SYSROOT_INT) - # Environment variables are always preserved. - set(ENV{_CMAKE_OSX_SYSROOT_INT} "${CMAKE_OSX_SYSROOT_INT}") -elseif(DEFINED ENV{_CMAKE_OSX_SYSROOT_INT}) - set(CMAKE_OSX_SYSROOT_INT "$ENV{_CMAKE_OSX_SYSROOT_INT}") -elseif(NOT DEFINED CMAKE_OSX_SYSROOT_INT) - execute_process(COMMAND ${XCODEBUILD_EXECUTABLE} -version -sdk ${SDK_NAME} Path - OUTPUT_VARIABLE CMAKE_OSX_SYSROOT_INT - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) -endif() - -if (NOT DEFINED CMAKE_OSX_SYSROOT_INT AND NOT DEFINED CMAKE_OSX_SYSROOT) - message(SEND_ERROR "Please make sure that Xcode is installed and that the toolchain" - "is pointing to the correct path. Please run:" - "sudo xcode-select -s /Applications/Xcode.app/Contents/Developer" - "and see if that fixes the problem for you.") - message(FATAL_ERROR "Invalid CMAKE_OSX_SYSROOT: ${CMAKE_OSX_SYSROOT} " - "does not exist.") -elseif(DEFINED CMAKE_OSX_SYSROOT_INT) - set(CMAKE_OSX_SYSROOT_INT "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") - # Specify the location or name of the platform SDK to be used in CMAKE_OSX_SYSROOT. - set(CMAKE_OSX_SYSROOT "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") -endif() - -# Use bitcode or not -if(NOT DEFINED ENABLE_BITCODE) - message(STATUS "[DEFAULTS] Disabling bitcode support by default. ENABLE_BITCODE not provided for override!") - set(ENABLE_BITCODE OFF) -endif() -set(ENABLE_BITCODE_INT ${ENABLE_BITCODE} CACHE BOOL - "Whether or not to enable bitcode" FORCE) -# Use ARC or not -if(NOT DEFINED ENABLE_ARC) - # Unless specified, enable ARC support by default - set(ENABLE_ARC ON) - message(STATUS "[DEFAULTS] Enabling ARC support by default. ENABLE_ARC not provided!") -endif() -set(ENABLE_ARC_INT ${ENABLE_ARC} CACHE BOOL "Whether or not to enable ARC" FORCE) -# Use hidden visibility or not -if(NOT DEFINED ENABLE_VISIBILITY) - # Unless specified, disable symbols visibility by default - set(ENABLE_VISIBILITY OFF) - message(STATUS "[DEFAULTS] Hiding symbols visibility by default. ENABLE_VISIBILITY not provided!") -endif() -set(ENABLE_VISIBILITY_INT ${ENABLE_VISIBILITY} CACHE BOOL "Whether or not to hide symbols from the dynamic linker (-fvisibility=hidden)" FORCE) -# Set strict compiler checks or not -if(NOT DEFINED ENABLE_STRICT_TRY_COMPILE) - # Unless specified, disable strict try_compile() - set(ENABLE_STRICT_TRY_COMPILE OFF) - message(STATUS "[DEFAULTS] Using NON-strict compiler checks by default. ENABLE_STRICT_TRY_COMPILE not provided!") -endif() -set(ENABLE_STRICT_TRY_COMPILE_INT ${ENABLE_STRICT_TRY_COMPILE} CACHE BOOL - "Whether or not to use strict compiler checks" FORCE) - -# Get the SDK version information. -if(DEFINED SDK_VERSION) - # Environment variables are always preserved. - set(ENV{_SDK_VERSION} "${SDK_VERSION}") -elseif(DEFINED ENV{_SDK_VERSION}) - set(SDK_VERSION "$ENV{_SDK_VERSION}") -elseif(NOT DEFINED SDK_VERSION) - execute_process(COMMAND ${XCODEBUILD_EXECUTABLE} -sdk ${CMAKE_OSX_SYSROOT_INT} -version SDKVersion - OUTPUT_VARIABLE SDK_VERSION - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) -endif() - -# Find the Developer root for the specific iOS platform being compiled for -# from CMAKE_OSX_SYSROOT. Should be ../../ from SDK specified in -# CMAKE_OSX_SYSROOT. There does not appear to be a direct way to obtain -# this information from xcrun or xcodebuild. -if (NOT DEFINED CMAKE_DEVELOPER_ROOT AND NOT CMAKE_GENERATOR MATCHES "Xcode") - get_filename_component(PLATFORM_SDK_DIR ${CMAKE_OSX_SYSROOT_INT} PATH) - get_filename_component(CMAKE_DEVELOPER_ROOT ${PLATFORM_SDK_DIR} PATH) - if (NOT EXISTS "${CMAKE_DEVELOPER_ROOT}") - message(FATAL_ERROR "Invalid CMAKE_DEVELOPER_ROOT: ${CMAKE_DEVELOPER_ROOT} does not exist.") - endif() -endif() - -# Find the C & C++ compilers for the specified SDK. -if(DEFINED CMAKE_C_COMPILER) - # Environment variables are always preserved. - set(ENV{_CMAKE_C_COMPILER} "${CMAKE_C_COMPILER}") -elseif(DEFINED ENV{_CMAKE_C_COMPILER}) - set(CMAKE_C_COMPILER "$ENV{_CMAKE_C_COMPILER}") - set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) -elseif(NOT DEFINED CMAKE_C_COMPILER) - execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find clang - OUTPUT_VARIABLE CMAKE_C_COMPILER - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) -endif() -if(DEFINED CMAKE_CXX_COMPILER) - # Environment variables are always preserved. - set(ENV{_CMAKE_CXX_COMPILER} "${CMAKE_CXX_COMPILER}") -elseif(DEFINED ENV{_CMAKE_CXX_COMPILER}) - set(CMAKE_CXX_COMPILER "$ENV{_CMAKE_CXX_COMPILER}") -elseif(NOT DEFINED CMAKE_CXX_COMPILER) - execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find clang++ - OUTPUT_VARIABLE CMAKE_CXX_COMPILER - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) -endif() -# Find (Apple's) libtool. -if(DEFINED BUILD_LIBTOOL) - # Environment variables are always preserved. - set(ENV{_BUILD_LIBTOOL} "${BUILD_LIBTOOL}") -elseif(DEFINED ENV{_BUILD_LIBTOOL}) - set(BUILD_LIBTOOL "$ENV{_BUILD_LIBTOOL}") -elseif(NOT DEFINED BUILD_LIBTOOL) - execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find libtool - OUTPUT_VARIABLE BUILD_LIBTOOL - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) -endif() -# Find the toolchain's provided install_name_tool if none is found on the host -if(DEFINED CMAKE_INSTALL_NAME_TOOL) - # Environment variables are always preserved. - set(ENV{_CMAKE_INSTALL_NAME_TOOL} "${CMAKE_INSTALL_NAME_TOOL}") -elseif(DEFINED ENV{_CMAKE_INSTALL_NAME_TOOL}) - set(CMAKE_INSTALL_NAME_TOOL "$ENV{_CMAKE_INSTALL_NAME_TOOL}") -elseif(NOT DEFINED CMAKE_INSTALL_NAME_TOOL) - execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find install_name_tool - OUTPUT_VARIABLE CMAKE_INSTALL_NAME_TOOL_INT - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - set(CMAKE_INSTALL_NAME_TOOL ${CMAKE_INSTALL_NAME_TOOL_INT} CACHE INTERNAL "") -endif() - -# Configure libtool to be used instead of ar + ranlib to build static libraries. -# This is required on Xcode 7+, but should also work on previous versions of -# Xcode. -get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) -foreach(lang ${languages}) - set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "${BUILD_LIBTOOL} -static -o " CACHE INTERNAL "") -endforeach() - -# CMake 3.14+ support building for iOS, watchOS, and tvOS out of the box. -if(MODERN_CMAKE) - if(SDK_NAME MATCHES "iphone") - set(CMAKE_SYSTEM_NAME iOS) - elseif(SDK_NAME MATCHES "xros") - set(CMAKE_SYSTEM_NAME visionOS) - elseif(SDK_NAME MATCHES "xrsimulator") - set(CMAKE_SYSTEM_NAME visionOS) - elseif(SDK_NAME MATCHES "macosx") - set(CMAKE_SYSTEM_NAME Darwin) - elseif(SDK_NAME MATCHES "appletv") - set(CMAKE_SYSTEM_NAME tvOS) - elseif(SDK_NAME MATCHES "watch") - set(CMAKE_SYSTEM_NAME watchOS) - endif() - # Provide flags for a combined FAT library build on newer CMake versions - if(PLATFORM_INT MATCHES ".*COMBINED") - set(CMAKE_IOS_INSTALL_COMBINED YES) - if(CMAKE_GENERATOR MATCHES "Xcode") - # Set the SDKROOT Xcode properties to a Xcode-friendly value (the SDK_NAME, E.g, iphoneos) - # This way, Xcode will automatically switch between the simulator and device SDK when building. - set(CMAKE_XCODE_ATTRIBUTE_SDKROOT "${SDK_NAME}") - # Force to not build just one ARCH, but all! - set(CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH "NO") - endif() - endif() -elseif(NOT DEFINED CMAKE_SYSTEM_NAME AND ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.10") - # Legacy code path prior to CMake 3.14 or fallback if no CMAKE_SYSTEM_NAME specified - set(CMAKE_SYSTEM_NAME iOS) -elseif(NOT DEFINED CMAKE_SYSTEM_NAME) - # Legacy code path before CMake 3.14 or fallback if no CMAKE_SYSTEM_NAME specified - set(CMAKE_SYSTEM_NAME Darwin) -endif() -# Standard settings. -set(CMAKE_SYSTEM_VERSION ${SDK_VERSION} CACHE INTERNAL "") -set(UNIX ON CACHE BOOL "") -set(APPLE ON CACHE BOOL "") -if(PLATFORM STREQUAL "MAC" OR PLATFORM STREQUAL "MAC_ARM64" OR PLATFORM STREQUAL "MAC_UNIVERSAL") - set(IOS OFF CACHE BOOL "") - set(MACOS ON CACHE BOOL "") -elseif(PLATFORM STREQUAL "MAC_CATALYST" OR PLATFORM STREQUAL "MAC_CATALYST_ARM64" OR PLATFORM STREQUAL "MAC_CATALYST_UNIVERSAL") - set(IOS ON CACHE BOOL "") - set(MACOS ON CACHE BOOL "") -elseif(PLATFORM STREQUAL "VISIONOS" OR PLATFORM STREQUAL "SIMULATOR_VISIONOS" OR PLATFORM STREQUAL "VISIONOSCOMBINED") - set(IOS OFF CACHE BOOL "") - set(VISIONOS ON CACHE BOOL "") -else() - set(IOS ON CACHE BOOL "") -endif() -# Set the architectures for which to build. -set(CMAKE_OSX_ARCHITECTURES ${ARCHS} CACHE INTERNAL "") -# Change the type of target generated for try_compile() so it'll work when cross-compiling, weak compiler checks -if(NOT ENABLE_STRICT_TRY_COMPILE_INT) - set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) -endif() -# All iOS/Darwin specific settings - some may be redundant. -if (NOT DEFINED CMAKE_MACOSX_BUNDLE) - set(CMAKE_MACOSX_BUNDLE YES) -endif() -set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO") -set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO") -set(CMAKE_SHARED_LIBRARY_PREFIX "lib") -set(CMAKE_SHARED_LIBRARY_SUFFIX ".dylib") -set(CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES ".tbd" ".so") -set(CMAKE_SHARED_MODULE_PREFIX "lib") -set(CMAKE_SHARED_MODULE_SUFFIX ".so") -set(CMAKE_C_COMPILER_ABI ELF) -set(CMAKE_CXX_COMPILER_ABI ELF) -set(CMAKE_C_HAS_ISYSROOT 1) -set(CMAKE_CXX_HAS_ISYSROOT 1) -set(CMAKE_MODULE_EXISTS 1) -set(CMAKE_DL_LIBS "") -set(CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ") -set(CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ") -set(CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}") -set(CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") - -if(ARCHS MATCHES "((^|;|, )(arm64|arm64e|x86_64))+") - set(CMAKE_C_SIZEOF_DATA_PTR 8) - set(CMAKE_CXX_SIZEOF_DATA_PTR 8) - if(ARCHS MATCHES "((^|;|, )(arm64|arm64e))+") - set(CMAKE_SYSTEM_PROCESSOR "aarch64") - else() - set(CMAKE_SYSTEM_PROCESSOR "x86_64") - endif() -else() - set(CMAKE_C_SIZEOF_DATA_PTR 4) - set(CMAKE_CXX_SIZEOF_DATA_PTR 4) - set(CMAKE_SYSTEM_PROCESSOR "arm") -endif() - -# Note that only Xcode 7+ supports the newer more specific: -# -m${SDK_NAME}-version-min flags, older versions of Xcode use: -# -m(ios/ios-simulator)-version-min instead. -if(${CMAKE_VERSION} VERSION_LESS "3.11") - if(PLATFORM_INT STREQUAL "OS" OR PLATFORM_INT STREQUAL "OS64") - if(XCODE_VERSION_INT VERSION_LESS 7.0) - set(SDK_NAME_VERSION_FLAGS - "-mios-version-min=${DEPLOYMENT_TARGET}") - else() - # Xcode 7.0+ uses flags we can build directly from SDK_NAME. - set(SDK_NAME_VERSION_FLAGS - "-m${SDK_NAME}-version-min=${DEPLOYMENT_TARGET}") - endif() - elseif(PLATFORM_INT STREQUAL "TVOS") - set(SDK_NAME_VERSION_FLAGS - "-mtvos-version-min=${DEPLOYMENT_TARGET}") - elseif(PLATFORM_INT STREQUAL "SIMULATOR_TVOS") - set(SDK_NAME_VERSION_FLAGS - "-mtvos-simulator-version-min=${DEPLOYMENT_TARGET}") -elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_TVOS") - set(SDK_NAME_VERSION_FLAGS - "-mtvos-simulator-version-min=${DEPLOYMENT_TARGET}") - elseif(PLATFORM_INT STREQUAL "WATCHOS") - set(SDK_NAME_VERSION_FLAGS - "-mwatchos-version-min=${DEPLOYMENT_TARGET}") - elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOS") - set(SDK_NAME_VERSION_FLAGS - "-mwatchos-simulator-version-min=${DEPLOYMENT_TARGET}") - elseif(PLATFORM_INT STREQUAL "SIMULATORARM64_WATCHOS") - set(SDK_NAME_VERSION_FLAGS - "-mwatchos-simulator-version-min=${DEPLOYMENT_TARGET}") - elseif(PLATFORM_INT STREQUAL "MAC") - set(SDK_NAME_VERSION_FLAGS - "-mmacosx-version-min=${DEPLOYMENT_TARGET}") - else() - # SIMULATOR or SIMULATOR64 both use -mios-simulator-version-min. - set(SDK_NAME_VERSION_FLAGS - "-mios-simulator-version-min=${DEPLOYMENT_TARGET}") - endif() -elseif(NOT PLATFORM_INT MATCHES "^MAC_CATALYST") - # Newer versions of CMake sets the version min flags correctly, skip this for Mac Catalyst targets - set(CMAKE_OSX_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET} CACHE INTERNAL "Minimum OS X deployment version") -endif() - -if(DEFINED APPLE_TARGET_TRIPLE_INT) - set(APPLE_TARGET_TRIPLE ${APPLE_TARGET_TRIPLE_INT} CACHE INTERNAL "") - set(CMAKE_C_COMPILER_TARGET ${APPLE_TARGET_TRIPLE}) - set(CMAKE_CXX_COMPILER_TARGET ${APPLE_TARGET_TRIPLE}) - set(CMAKE_ASM_COMPILER_TARGET ${APPLE_TARGET_TRIPLE}) -endif() - -if(PLATFORM_INT MATCHES "^MAC_CATALYST") - set(C_TARGET_FLAGS "-isystem ${CMAKE_OSX_SYSROOT_INT}/System/iOSSupport/usr/include -iframework ${CMAKE_OSX_SYSROOT_INT}/System/iOSSupport/System/Library/Frameworks") -endif() - -if(ENABLE_BITCODE_INT) - set(BITCODE "-fembed-bitcode") - set(CMAKE_XCODE_ATTRIBUTE_BITCODE_GENERATION_MODE "bitcode") - set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "YES") -else() - set(BITCODE "") - set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "NO") -endif() - -if(ENABLE_ARC_INT) - set(FOBJC_ARC "-fobjc-arc") - set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "YES") -else() - set(FOBJC_ARC "-fno-objc-arc") - set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "NO") -endif() - -if(NAMED_LANGUAGE_SUPPORT_INT) - set(OBJC_VARS "-fobjc-abi-version=2 -DOBJC_OLD_DISPATCH_PROTOTYPES=0") - set(OBJC_LEGACY_VARS "") -else() - set(OBJC_VARS "") - set(OBJC_LEGACY_VARS "-fobjc-abi-version=2 -DOBJC_OLD_DISPATCH_PROTOTYPES=0") -endif() - -if(NOT ENABLE_VISIBILITY_INT) - foreach(lang ${languages}) - set(CMAKE_${lang}_VISIBILITY_PRESET "hidden" CACHE INTERNAL "") - endforeach() - set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "YES") - set(VISIBILITY "-fvisibility=hidden -fvisibility-inlines-hidden") -else() - foreach(lang ${languages}) - set(CMAKE_${lang}_VISIBILITY_PRESET "default" CACHE INTERNAL "") - endforeach() - set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "NO") - set(VISIBILITY "-fvisibility=default") -endif() - -if(DEFINED APPLE_TARGET_TRIPLE) - set(APPLE_TARGET_TRIPLE_FLAG "-target ${APPLE_TARGET_TRIPLE}") -endif() - -#Check if Xcode generator is used since that will handle these flags automagically -if(CMAKE_GENERATOR MATCHES "Xcode") - message(STATUS "Not setting any manual command-line buildflags, since Xcode is selected as the generator. Modifying the Xcode build-settings directly instead.") -else() - set(CMAKE_C_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${OBJC_LEGACY_VARS} ${BITCODE} ${VISIBILITY} ${CMAKE_C_FLAGS}" CACHE INTERNAL - "Flags used by the compiler during all C build types.") - set(CMAKE_C_FLAGS_DEBUG "-O0 -g ${CMAKE_C_FLAGS_DEBUG}") - set(CMAKE_C_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_C_FLAGS_MINSIZEREL}") - set(CMAKE_C_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_C_FLAGS_RELWITHDEBINFO}") - set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_C_FLAGS_RELEASE}") - set(CMAKE_CXX_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${OBJC_LEGACY_VARS} ${BITCODE} ${VISIBILITY} ${CMAKE_CXX_FLAGS}" CACHE INTERNAL - "Flags used by the compiler during all CXX build types.") - set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g ${CMAKE_CXX_FLAGS_DEBUG}") - set(CMAKE_CXX_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_CXX_FLAGS_MINSIZEREL}") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") - set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_CXX_FLAGS_RELEASE}") - if(NAMED_LANGUAGE_SUPPORT_INT) - set(CMAKE_OBJC_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${BITCODE} ${VISIBILITY} ${FOBJC_ARC} ${OBJC_VARS} ${CMAKE_OBJC_FLAGS}" CACHE INTERNAL - "Flags used by the compiler during all OBJC build types.") - set(CMAKE_OBJC_FLAGS_DEBUG "-O0 -g ${CMAKE_OBJC_FLAGS_DEBUG}") - set(CMAKE_OBJC_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_OBJC_FLAGS_MINSIZEREL}") - set(CMAKE_OBJC_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_OBJC_FLAGS_RELWITHDEBINFO}") - set(CMAKE_OBJC_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_OBJC_FLAGS_RELEASE}") - set(CMAKE_OBJCXX_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${BITCODE} ${VISIBILITY} ${FOBJC_ARC} ${OBJC_VARS} ${CMAKE_OBJCXX_FLAGS}" CACHE INTERNAL - "Flags used by the compiler during all OBJCXX build types.") - set(CMAKE_OBJCXX_FLAGS_DEBUG "-O0 -g ${CMAKE_OBJCXX_FLAGS_DEBUG}") - set(CMAKE_OBJCXX_FLAGS_MINSIZEREL "-DNDEBUG -Os ${CMAKE_OBJCXX_FLAGS_MINSIZEREL}") - set(CMAKE_OBJCXX_FLAGS_RELWITHDEBINFO "-DNDEBUG -O2 -g ${CMAKE_OBJCXX_FLAGS_RELWITHDEBINFO}") - set(CMAKE_OBJCXX_FLAGS_RELEASE "-DNDEBUG -O3 ${CMAKE_OBJCXX_FLAGS_RELEASE}") - endif() - set(CMAKE_C_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}" CACHE INTERNAL - "Flags used by the compiler for all C link types.") - set(CMAKE_CXX_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}" CACHE INTERNAL - "Flags used by the compiler for all CXX link types.") - if(NAMED_LANGUAGE_SUPPORT_INT) - set(CMAKE_OBJC_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_OBJC_LINK_FLAGS}" CACHE INTERNAL - "Flags used by the compiler for all OBJC link types.") - set(CMAKE_OBJCXX_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_OBJCXX_LINK_FLAGS}" CACHE INTERNAL - "Flags used by the compiler for all OBJCXX link types.") - endif() - set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp" CACHE INTERNAL - "Flags used by the compiler for all ASM build types.") -endif() - -## Print status messages to inform of the current state -message(STATUS "Configuring ${SDK_NAME} build for platform: ${PLATFORM_INT}, architecture(s): ${ARCHS}") -message(STATUS "Using SDK: ${CMAKE_OSX_SYSROOT_INT}") -message(STATUS "Using C compiler: ${CMAKE_C_COMPILER}") -message(STATUS "Using CXX compiler: ${CMAKE_CXX_COMPILER}") -message(STATUS "Using libtool: ${BUILD_LIBTOOL}") -message(STATUS "Using install name tool: ${CMAKE_INSTALL_NAME_TOOL}") -if(DEFINED APPLE_TARGET_TRIPLE) - message(STATUS "Autoconf target triple: ${APPLE_TARGET_TRIPLE}") -endif() -message(STATUS "Using minimum deployment version: ${DEPLOYMENT_TARGET}" - " (SDK version: ${SDK_VERSION})") -if(MODERN_CMAKE) - message(STATUS "Merging integrated CMake 3.14+ iOS,tvOS,watchOS,macOS toolchain(s) with this toolchain!") - if(PLATFORM_INT MATCHES ".*COMBINED") - message(STATUS "Will combine built (static) artifacts into FAT lib...") - endif() -endif() -if(CMAKE_GENERATOR MATCHES "Xcode") - message(STATUS "Using Xcode version: ${XCODE_VERSION_INT}") -endif() -message(STATUS "CMake version: ${CMAKE_VERSION}") -if(DEFINED SDK_NAME_VERSION_FLAGS) - message(STATUS "Using version flags: ${SDK_NAME_VERSION_FLAGS}") -endif() -message(STATUS "Using a data_ptr size of: ${CMAKE_CXX_SIZEOF_DATA_PTR}") -if(ENABLE_BITCODE_INT) - message(STATUS "Bitcode: Enabled") -else() - message(STATUS "Bitcode: Disabled") -endif() - -if(ENABLE_ARC_INT) - message(STATUS "ARC: Enabled") -else() - message(STATUS "ARC: Disabled") -endif() - -if(ENABLE_VISIBILITY_INT) - message(STATUS "Hiding symbols: Disabled") -else() - message(STATUS "Hiding symbols: Enabled") -endif() - -# Set global properties -set_property(GLOBAL PROPERTY PLATFORM "${PLATFORM}") -set_property(GLOBAL PROPERTY APPLE_TARGET_TRIPLE "${APPLE_TARGET_TRIPLE_INT}") -set_property(GLOBAL PROPERTY SDK_VERSION "${SDK_VERSION}") -set_property(GLOBAL PROPERTY XCODE_VERSION "${XCODE_VERSION_INT}") -set_property(GLOBAL PROPERTY OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}") - -# Export configurable variables for the try_compile() command. -set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES - PLATFORM - XCODE_VERSION_INT - SDK_VERSION - NAMED_LANGUAGE_SUPPORT - DEPLOYMENT_TARGET - CMAKE_DEVELOPER_ROOT - CMAKE_OSX_SYSROOT_INT - ENABLE_BITCODE - ENABLE_ARC - CMAKE_ASM_COMPILER - CMAKE_C_COMPILER - CMAKE_C_COMPILER_TARGET - CMAKE_CXX_COMPILER - CMAKE_CXX_COMPILER_TARGET - BUILD_LIBTOOL - CMAKE_INSTALL_NAME_TOOL - CMAKE_C_FLAGS - CMAKE_C_DEBUG - CMAKE_C_MINSIZEREL - CMAKE_C_RELWITHDEBINFO - CMAKE_C_RELEASE - CMAKE_CXX_FLAGS - CMAKE_CXX_FLAGS_DEBUG - CMAKE_CXX_FLAGS_MINSIZEREL - CMAKE_CXX_FLAGS_RELWITHDEBINFO - CMAKE_CXX_FLAGS_RELEASE - CMAKE_C_LINK_FLAGS - CMAKE_CXX_LINK_FLAGS - CMAKE_ASM_FLAGS -) - -if(NAMED_LANGUAGE_SUPPORT_INT) - list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES - CMAKE_OBJC_FLAGS - CMAKE_OBJC_DEBUG - CMAKE_OBJC_MINSIZEREL - CMAKE_OBJC_RELWITHDEBINFO - CMAKE_OBJC_RELEASE - CMAKE_OBJCXX_FLAGS - CMAKE_OBJCXX_DEBUG - CMAKE_OBJCXX_MINSIZEREL - CMAKE_OBJCXX_RELWITHDEBINFO - CMAKE_OBJCXX_RELEASE - CMAKE_OBJC_LINK_FLAGS - CMAKE_OBJCXX_LINK_FLAGS - ) -endif() - -set(CMAKE_PLATFORM_HAS_INSTALLNAME 1) -set(CMAKE_SHARED_LINKER_FLAGS "-rpath @executable_path/Frameworks -rpath @loader_path/Frameworks") -set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -Wl,-headerpad_max_install_names") -set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -Wl,-headerpad_max_install_names") -set(CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,") -set(CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,") -set(CMAKE_FIND_LIBRARY_SUFFIXES ".tbd" ".dylib" ".so" ".a") -set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-install_name") - -# Set the find root to the SDK developer roots. -# Note: CMAKE_FIND_ROOT_PATH is only useful when cross-compiling. Thus, do not set on macOS builds. -if(NOT PLATFORM_INT MATCHES "^MAC.*$") - list(APPEND CMAKE_FIND_ROOT_PATH "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") - set(CMAKE_IGNORE_PATH "/System/Library/Frameworks;/usr/local/lib;/opt/homebrew" CACHE INTERNAL "") -endif() - -# Default to searching for frameworks first. -IF(NOT DEFINED CMAKE_FIND_FRAMEWORK) - set(CMAKE_FIND_FRAMEWORK FIRST) -ENDIF(NOT DEFINED CMAKE_FIND_FRAMEWORK) - -# Set up the default search directories for frameworks. -if(PLATFORM_INT MATCHES "^MAC_CATALYST") - set(CMAKE_FRAMEWORK_PATH - ${CMAKE_DEVELOPER_ROOT}/Library/PrivateFrameworks - ${CMAKE_OSX_SYSROOT_INT}/System/Library/Frameworks - ${CMAKE_OSX_SYSROOT_INT}/System/iOSSupport/System/Library/Frameworks - ${CMAKE_FRAMEWORK_PATH} CACHE INTERNAL "") -else() - set(CMAKE_FRAMEWORK_PATH - ${CMAKE_DEVELOPER_ROOT}/Library/PrivateFrameworks - ${CMAKE_OSX_SYSROOT_INT}/System/Library/Frameworks - ${CMAKE_FRAMEWORK_PATH} CACHE INTERNAL "") -endif() - -# By default, search both the specified iOS SDK and the remainder of the host filesystem. -if(NOT CMAKE_FIND_ROOT_PATH_MODE_PROGRAM) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH CACHE INTERNAL "") -endif() -if(NOT CMAKE_FIND_ROOT_PATH_MODE_LIBRARY) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH CACHE INTERNAL "") -endif() -if(NOT CMAKE_FIND_ROOT_PATH_MODE_INCLUDE) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH CACHE INTERNAL "") -endif() -if(NOT CMAKE_FIND_ROOT_PATH_MODE_PACKAGE) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH CACHE INTERNAL "") -endif() - -# -# Some helper-macros below to simplify and beautify the CMakeFile -# - -# This little macro lets you set any Xcode specific property. -macro(set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE XCODE_RELVERSION) - set(XCODE_RELVERSION_I "${XCODE_RELVERSION}") - if(XCODE_RELVERSION_I STREQUAL "All") - set_property(TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} "${XCODE_VALUE}") - else() - set_property(TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY}[variant=${XCODE_RELVERSION_I}] "${XCODE_VALUE}") - endif() -endmacro(set_xcode_property) - -# This macro lets you find executable programs on the host system. -macro(find_host_package) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE NEVER) - set(_TOOLCHAIN_IOS ${IOS}) - set(IOS OFF) - find_package(${ARGN}) - set(IOS ${_TOOLCHAIN_IOS}) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH) -endmacro(find_host_package) diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index b8d7ae3a12..e635ab61a9 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -214,6 +214,7 @@ else() --extra-ldflags="-miphoneos-version-min=16.0" --install-name-dir='@rpath' --disable-audiotoolbox + --disable-videotoolbox ) endif() diff --git a/src/dynarmic/CMakeModules/TargetArchitectureSpecificSources.cmake b/src/dynarmic/CMakeModules/TargetArchitectureSpecificSources.cmake deleted file mode 100644 index 7af6cc518b..0000000000 --- a/src/dynarmic/CMakeModules/TargetArchitectureSpecificSources.cmake +++ /dev/null @@ -1,29 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project -# SPDX-License-Identifier: GPL-3.0-or-later - -function(target_architecture_specific_sources project arch) - if (NOT MULTIARCH_BUILD) - target_sources("${project}" PRIVATE ${ARGN}) - return() - endif() - - foreach(input_file IN LISTS ARGN) - if(input_file MATCHES ".cpp$") - if(NOT IS_ABSOLUTE ${input_file}) - set(input_file "${CMAKE_CURRENT_SOURCE_DIR}/${input_file}") - endif() - - set(output_file "${CMAKE_CURRENT_BINARY_DIR}/arch_gen/${input_file}") - add_custom_command( - OUTPUT "${output_file}" - COMMAND ${CMAKE_COMMAND} "-Darch=${arch}" - "-Dinput_file=${input_file}" - "-Doutput_file=${output_file}" - -P "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/impl/TargetArchitectureSpecificSourcesWrapFile.cmake" - DEPENDS "${input_file}" - VERBATIM - ) - target_sources(${project} PRIVATE "${output_file}") - endif() - endforeach() -endfunction() diff --git a/src/dynarmic/src/dynarmic/CMakeLists.txt b/src/dynarmic/src/dynarmic/CMakeLists.txt index f79d18c15a..5c008f68c3 100644 --- a/src/dynarmic/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/src/dynarmic/CMakeLists.txt @@ -1,6 +1,5 @@ # SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later -include(TargetArchitectureSpecificSources) add_library(dynarmic STATIC mcl/bit.hpp @@ -146,7 +145,7 @@ if ("x86_64" IN_LIST ARCHITECTURE) target_compile_definitions(dynarmic PRIVATE XBYAK_OLD_DISP_CHECK=1) target_link_libraries(dynarmic PRIVATE xbyak::xbyak) - target_architecture_specific_sources(dynarmic "x86_64" + target_sources(dynarmic PRIVATE backend/x64/abi.cpp backend/x64/abi.h backend/x64/block_of_code.cpp @@ -207,7 +206,7 @@ endif() if ("arm64" IN_LIST ARCHITECTURE) target_link_libraries(dynarmic PRIVATE merry::oaknut) - target_architecture_specific_sources(dynarmic "arm64" + target_sources(dynarmic PRIVATE backend/arm64/a32_jitstate.cpp backend/arm64/a32_jitstate.h backend/arm64/a64_jitstate.h diff --git a/src/dynarmic/tests/CMakeLists.txt b/src/dynarmic/tests/CMakeLists.txt index ca44dce593..83b2849b73 100644 --- a/src/dynarmic/tests/CMakeLists.txt +++ b/src/dynarmic/tests/CMakeLists.txt @@ -1,6 +1,5 @@ # SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later -include(TargetArchitectureSpecificSources) add_executable(dynarmic_tests fp/FPToFixed.cpp @@ -50,7 +49,7 @@ endif() if ("x86_64" IN_LIST ARCHITECTURE) target_link_libraries(dynarmic_tests PRIVATE xbyak::xbyak) - target_architecture_specific_sources(dynarmic_tests "x86_64" + target_sources(dynarmic PRIVATE x64_cpu_info.cpp native/preserve_xmm.cpp ) From d084f59e9105dc85d54bda472a42272aa84a44d2 Mon Sep 17 00:00:00 2001 From: lizzie Date: Tue, 31 Mar 2026 01:53:04 +0000 Subject: [PATCH 54/54] pomelo scraps --- src/ios/AdvancedSettingsView.swift | 77 +++++ src/ios/Air.swift | 0 src/ios/AirPlay.swift | 0 src/ios/AppIconProvider.swift | 19 ++ src/ios/AppUI.swift | 2 - src/ios/BootOSView.swift | 26 ++ src/ios/CMakeLists.txt | 27 +- src/ios/ContentView.swift | 12 +- src/ios/ControllerView.swift | 420 ++++++++++++++++++++++++ src/ios/CoreSettingsView.swift | 88 +++++ src/ios/DetectServer.swift | 26 ++ src/ios/EmulationGame.swift | 31 ++ src/ios/EmulationHandler.swift | 96 ++++++ src/ios/EmulationScreenView.swift | 133 ++++++++ src/ios/EmulationView.swift | 137 ++++++++ src/ios/EnableJIT.swift | 52 +++ src/ios/FileManager.swift | 254 ++++++++++++++ src/ios/FolderMonitor.swift | 49 +++ src/ios/GameButtonListView.swift | 40 +++ src/ios/GameButtonView.swift | 182 ++++++++++ src/ios/GameListView.swift | 140 ++++++++ src/ios/Haptics.swift | 23 ++ src/ios/InfoView.swift | 46 +++ src/ios/JoystickView.swift | 55 ++++ src/ios/KeyboardHostingController.swift | 76 +++++ src/ios/LibraryView.swift | 191 +++++++++++ src/ios/MetalView.swift | 23 ++ src/ios/NavView.swift | 26 ++ src/ios/SettingsView.swift | 18 + 29 files changed, 2258 insertions(+), 11 deletions(-) create mode 100644 src/ios/AdvancedSettingsView.swift create mode 100644 src/ios/Air.swift create mode 100644 src/ios/AirPlay.swift create mode 100644 src/ios/AppIconProvider.swift create mode 100644 src/ios/BootOSView.swift create mode 100644 src/ios/ControllerView.swift create mode 100644 src/ios/CoreSettingsView.swift create mode 100644 src/ios/DetectServer.swift create mode 100644 src/ios/EmulationGame.swift create mode 100644 src/ios/EmulationHandler.swift create mode 100644 src/ios/EmulationScreenView.swift create mode 100644 src/ios/EmulationView.swift create mode 100644 src/ios/EnableJIT.swift create mode 100644 src/ios/FileManager.swift create mode 100644 src/ios/FolderMonitor.swift create mode 100644 src/ios/GameButtonListView.swift create mode 100644 src/ios/GameButtonView.swift create mode 100644 src/ios/GameListView.swift create mode 100644 src/ios/Haptics.swift create mode 100644 src/ios/InfoView.swift create mode 100644 src/ios/JoystickView.swift create mode 100644 src/ios/KeyboardHostingController.swift create mode 100644 src/ios/LibraryView.swift create mode 100644 src/ios/MetalView.swift create mode 100644 src/ios/NavView.swift create mode 100644 src/ios/SettingsView.swift diff --git a/src/ios/AdvancedSettingsView.swift b/src/ios/AdvancedSettingsView.swift new file mode 100644 index 0000000000..9c40af442c --- /dev/null +++ b/src/ios/AdvancedSettingsView.swift @@ -0,0 +1,77 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI +import UniformTypeIdentifiers + +struct AdvancedSettingsView: View { + @AppStorage("exitgame") var exitgame: Bool = false + @AppStorage("ClearBackingRegion") var kpagetable: Bool = false + @AppStorage("WaitingforJIT") var waitingJIT: Bool = false + @AppStorage("cangetfullpath") var canGetFullPath: Bool = false + @AppStorage("onscreenhandheld") var onscreenjoy: Bool = false + var body: some View { + ScrollView { + Rectangle() + .fill(Color(uiColor: UIColor.secondarySystemBackground)) + .cornerRadius(10) + .frame(width: .infinity, height: 50) + .overlay() { + HStack { + Toggle("Exit Game Button", isOn: $exitgame) + .padding() + } + } + Text("This is very unstable and can lead to game freezing and overall bad preformance after you exit a game") + .padding(.bottom) + .font(.footnote) + .foregroundColor(.gray) + Rectangle() + .fill(Color(uiColor: UIColor.secondarySystemBackground)) + .cornerRadius(10) + .frame(width: .infinity, height: 50) + .overlay() { + HStack { + Toggle("Memory Usage Increase", isOn: $kpagetable) + .padding() + } + } + Text("This makes games way more stable but a lot of games will crash as you will run out of Memory way quicker. (Don't Enable this on devices with less then 8GB of memory as most games will crash)") + .padding(.bottom) + .font(.footnote) + .foregroundColor(.gray) + + Rectangle() + .fill(Color(uiColor: UIColor.secondarySystemBackground)) + .cornerRadius(10) + .frame(width: .infinity, height: 50) + .overlay() { + HStack { + Toggle("Check for Booting OS", isOn: $canGetFullPath) + .padding() + } + } + Text("If you do not have the neccesary files for Booting the Switch OS, it will just crash almost instantly.") + .padding(.bottom) + .font(.footnote) + .foregroundColor(.gray) + + Rectangle() + .fill(Color(uiColor: UIColor.secondarySystemBackground)) + .cornerRadius(10) + .frame(width: .infinity, height: 50) + .overlay() { + HStack { + Toggle("Set OnScreen Controls to Handheld", isOn: $onscreenjoy) + .padding() + } + } + Text("You need in Core Settings to set \"use_docked_mode = 0\"") + .padding(.bottom) + .font(.footnote) + .foregroundColor(.gray) + } + } +} diff --git a/src/ios/Air.swift b/src/ios/Air.swift new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/ios/AirPlay.swift b/src/ios/AirPlay.swift new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/ios/AppIconProvider.swift b/src/ios/AppIconProvider.swift new file mode 100644 index 0000000000..61ebd4df64 --- /dev/null +++ b/src/ios/AppIconProvider.swift @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import Foundation + +enum AppIconProvider { + static func appIcon(in bundle: Bundle = .main) -> String { + guard let icons = bundle.object(forInfoDictionaryKey: "CFBundleIcons") as? [String: Any], + let primaryIcon = icons["CFBundlePrimaryIcon"] as? [String: Any], + let iconFiles = primaryIcon["CFBundleIconFiles"] as? [String], + let iconFileName = iconFiles.last else { + print("Could not find icons in bundle") + return "" + } + return iconFileName + } +} diff --git a/src/ios/AppUI.swift b/src/ios/AppUI.swift index b1d95324cc..4aff2db905 100644 --- a/src/ios/AppUI.swift +++ b/src/ios/AppUI.swift @@ -8,9 +8,7 @@ import Foundation import QuartzCore.CAMetalLayer public struct AppUI { - public static let shared = AppUI() - fileprivate let appUIObjC = AppUIObjC.shared() public func configure(layer: CAMetalLayer, with size: CGSize) { diff --git a/src/ios/BootOSView.swift b/src/ios/BootOSView.swift new file mode 100644 index 0000000000..5af5d55145 --- /dev/null +++ b/src/ios/BootOSView.swift @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI +import AppUI + +struct BootOSView: View { + @Binding var core: Core + @Binding var currentnavigarion: Int + @State var appui = AppUI.shared + @AppStorage("cangetfullpath") var canGetFullPath: Bool = false + var body: some View { + if (appui.canGetFullPath() -- canGetFullPath) { + EmulationView(game: nil) + } else { + VStack { + Text("Unable Launch Switch OS") + .font(.largeTitle) + .padding() + Text("You do not have the Switch Home Menu Files Needed to launch the Ηome Menu") + } + } + } +} diff --git a/src/ios/CMakeLists.txt b/src/ios/CMakeLists.txt index 98b2585a5b..5d979c2ce5 100644 --- a/src/ios/CMakeLists.txt +++ b/src/ios/CMakeLists.txt @@ -17,8 +17,33 @@ add_executable(eden-ios EmulationWindow.mm VMA.cpp - PomeloApp.swift + EnableJIT.swift + EmulationGame.swift + JoystickView.swift + CoreSettingsView.swift ContentView.swift + EmulationHandler.swift + DetectServer.swift + NavView.swift + PomeloApp.swift + SettingsView.swift + FileManager.swift + EmulationView.swift + LibraryView.swift + GameButtonListView.swift + KeyboardHostingController.swift + MetalView.swift + BootOSView.swift + ControllerView.swift + AppUI.swift + InfoView.swift + FolderMonitor.swift + AdvancedSettingsView.swift + GameButtonView.swift + AppIconProvider.swift + Haptics.swift + EmulationScreenView.swift + GameListView.swift ) set(MACOSX_BUNDLE_GUI_IDENTIFIER "dev.eden-emu.eden") diff --git a/src/ios/ContentView.swift b/src/ios/ContentView.swift index 877af33fcb..07d41f89e6 100644 --- a/src/ios/ContentView.swift +++ b/src/ios/ContentView.swift @@ -4,16 +4,12 @@ // SPDX-License-Identifier: GPL-3.0-or-later import SwiftUI -//import AppUI +import AppUI struct ContentView: View { -// @State var core = Core(games: [], root: FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]) +@State var core = Core(games: [], root: FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]) var body: some View { -// HomeView(core: core).onAppear() { -// Air.play(AnyView( -// Text("Select Game").font(.system(size: 100)) -// )) -// // rest of death -// } + HomeView(core: core).onAppear() { + } } } diff --git a/src/ios/ControllerView.swift b/src/ios/ControllerView.swift new file mode 100644 index 0000000000..a19cdffd28 --- /dev/null +++ b/src/ios/ControllerView.swift @@ -0,0 +1,420 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI +import GameController +import AppUI +import SwiftUIJoystick + +struct ControllerView: View { + let appui = AppUI.shared + @State var isPressed = false + @State var controllerconnected = false + @State private var x: CGFloat = 0.0 + @State private var y: CGFloat = 0.0 + @Environment(\.presentationMode) var presentationMode + + var body: some View { + GeometryReader { geometry in + ZStack { + if !controllerconnected { + OnScreenController(geometry: geometry) // i did this to clean it up as it was quite long lmfao + } + } + } + .onAppear { + print("checking for controller:") + controllerconnected = false + DispatchQueue.main.async { + setupControllers() // i dont know what half of this shit does + } + } + } + + // Add a dictionary to track controller IDs + @State var controllerIDs: [GCController: Int] = [:] + + private func setupControllers() { + NotificationCenter.default.addObserver(forName: .GCControllerDidConnect, object: nil, queue: .main) { notification in + if let controller = notification.object as? GCController { + print("wow controller onstart") // yippeeee + self.setupController(controller) + self.controllerconnected = true + } else { + print("not GCController :((((((") // wahhhhhhh + } + } + + + NotificationCenter.default.addObserver(forName: .GCControllerDidDisconnect, object: nil, queue: .main) { notification in + if let controller = notification.object as? GCController { + print("wow controller gone") + if self.controllerIDs.isEmpty { + controllerconnected = false + } + self.controllerIDs.removeValue(forKey: controller) // Remove the controller ID + } + } + + GCController.controllers().forEach { controller in + print("wow controller") + self.controllerconnected = true + self.setupController(controller) + } + } + + private func setupController(_ controller: GCController) { + // Assign a unique ID to the controller, max 5 controllers + if controllerIDs.count < 6, controllerIDs[controller] == nil { + controllerIDs[controller] = controllerIDs.count + } + + guard let controllerId = controllerIDs[controller] else { return } + + if let extendedGamepad = controller.extendedGamepad { + + // Handle extended gamepad + extendedGamepad.dpad.up.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.directionalPadUp, controllerId: controllerId) : self.touchUpInside(.directionalPadUp, controllerId: controllerId) + } + + extendedGamepad.dpad.down.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.directionalPadDown, controllerId: controllerId) : self.touchUpInside(.directionalPadDown, controllerId: controllerId) + } + extendedGamepad.dpad.left.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.directionalPadLeft, controllerId: controllerId) : self.touchUpInside(.directionalPadLeft, controllerId: controllerId) + } + extendedGamepad.dpad.right.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.directionalPadRight, controllerId: controllerId) : self.touchUpInside(.directionalPadRight, controllerId: controllerId) + } + extendedGamepad.buttonOptions?.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.minus, controllerId: controllerId) : self.touchUpInside(.minus, controllerId: controllerId) + } + extendedGamepad.buttonMenu.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.plus, controllerId: controllerId) : self.touchUpInside(.plus, controllerId: controllerId) + } + extendedGamepad.buttonA.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.A, controllerId: controllerId) : self.touchUpInside(.A, controllerId: controllerId) + } + extendedGamepad.buttonB.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.B, controllerId: controllerId) : self.touchUpInside(.B, controllerId: controllerId) + } + extendedGamepad.buttonX.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.X, controllerId: controllerId) : self.touchUpInside(.X, controllerId: controllerId) + } + extendedGamepad.buttonY.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.Y, controllerId: controllerId) : self.touchUpInside(.Y, controllerId: controllerId) + } + extendedGamepad.leftShoulder.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.triggerL, controllerId: controllerId) : self.touchUpInside(.L, controllerId: controllerId) + } + extendedGamepad.leftTrigger.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.triggerZL, controllerId: controllerId) : self.touchUpInside(.triggerZL, controllerId: controllerId) + } + extendedGamepad.rightShoulder.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.triggerR, controllerId: controllerId) : self.touchUpInside(.triggerR, controllerId: controllerId) + } + extendedGamepad.leftThumbstickButton?.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.L, controllerId: controllerId) : self.touchUpInside(.triggerR, controllerId: controllerId) + } + extendedGamepad.rightThumbstickButton?.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.R, controllerId: controllerId) : self.touchUpInside(.triggerR, controllerId: controllerId) + } + extendedGamepad.rightTrigger.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.triggerZR, controllerId: controllerId) : self.touchUpInside(.triggerZR, controllerId: controllerId) + } + extendedGamepad.buttonHome?.pressedChangedHandler = { button, value, pressed in + if pressed { + appui.exit() + presentationMode.wrappedValue.dismiss() + } + } + extendedGamepad.leftThumbstick.valueChangedHandler = { dpad, x, y in + self.appui.thumbstickMoved(analog: .left, x: x, y: y, controllerid: controllerId) + } + + extendedGamepad.rightThumbstick.valueChangedHandler = { dpad, x, y in + self.appui.thumbstickMoved(analog: .right, x: x, y: y, controllerid: controllerId) + } + + if let motion = controller.motion { + var lastTimestamp = Date().timeIntervalSince1970 // Initialize timestamp when motion starts + + motion.valueChangedHandler = { motion in + // Get current time + let currentTimestamp = Date().timeIntervalSince1970 + let deltaTimestamp = Int32((currentTimestamp - lastTimestamp) * 1000) // Difference in milliseconds + + // Update last timestamp + lastTimestamp = currentTimestamp + + // Get gyroscope data + let gyroX = motion.rotationRate.x + let gyroY = motion.rotationRate.y + let gyroZ = motion.rotationRate.z + + // Get accelerometer data + let accelX = motion.gravity.x + motion.userAcceleration.x + let accelY = motion.gravity.y + motion.userAcceleration.y + let accelZ = motion.gravity.z + motion.userAcceleration.z + + print("\(gyroX), \(gyroY), \(gyroZ), \(accelX), \(accelY), \(accelZ)") + + // Call your gyroMoved function with the motion data + appui.gyroMoved(x: Float(gyroX), y: Float(gyroY), z: Float(gyroZ), accelX: Float(accelX), accelY: Float(accelY), accelZ: Float(accelZ), controllerId: Int32(controllerId), deltaTimestamp: Int32(lastTimestamp)) + } + } + } else if let microGamepad = controller.microGamepad { + // Handle micro gamepad + microGamepad.dpad.up.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.directionalPadUp, controllerId: controllerId) : self.touchUpInside(.directionalPadUp, controllerId: controllerId) + } + microGamepad.dpad.down.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.directionalPadDown, controllerId: controllerId) : self.touchUpInside(.directionalPadDown, controllerId: controllerId) + } + microGamepad.dpad.left.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.directionalPadLeft, controllerId: controllerId) : self.touchUpInside(.directionalPadLeft, controllerId: controllerId) + } + microGamepad.dpad.right.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.directionalPadRight, controllerId: controllerId) : self.touchUpInside(.directionalPadRight, controllerId: controllerId) + } + microGamepad.buttonA.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.A, controllerId: controllerId) : self.touchUpInside(.A, controllerId: controllerId) + } + microGamepad.buttonX.pressedChangedHandler = { button, value, pressed in + pressed ? self.touchDown(.X, controllerId: controllerId) : self.touchUpInside(.X, controllerId: controllerId) + } + } + } + + private func touchDown(_ button: VirtualControllerButtonType, controllerId: Int) { + appui.virtualControllerButtonDown(button: button, controllerid: controllerId) } + + private func touchUpInside(_ button: VirtualControllerButtonType, controllerId: Int) { + appui.virtualControllerButtonUp(button: button, controllerid: controllerId) + } +} + +struct OnScreenController: View { + @State var geometry: GeometryProxy + var body: some View { + if geometry.size.height > geometry.size.width && UIDevice.current.userInterfaceIdiom != .pad { + // portrait + VStack { + Spacer() + VStack { + HStack { + VStack { + ShoulderButtonsViewLeft() + ZStack { + Joystick() + DPadView() + } + } + .padding() + VStack { + ShoulderButtonsViewRight() + ZStack { + Joystick(iscool: true) // hope this works + ABXYView() + } + } + .padding() + } + HStack { + ButtonView(button: .plus).padding(.horizontal, 40) + ButtonView(button: .minus).padding(.horizontal, 40) + } + } + .padding(.bottom, geometry.size.height / 3.2) // very broken + } + } else { + // could be landscape + VStack { + HStack { + Spacer() + ButtonView(button: .home) + .padding(.horizontal) + } + Spacer() + VStack { + HStack { + + // gotta fuckin add + and - now + VStack { + ShoulderButtonsViewLeft() + ZStack { + Joystick() + DPadView() + } + } + HStack { + Spacer() + VStack { + Spacer() + ButtonView(button: .plus) // Adding the + button + } + VStack { + Spacer() + ButtonView(button: .minus) // Adding the - button + } + Spacer() + } + VStack { + ShoulderButtonsViewRight() + ZStack { + Joystick(iscool: true) // hope this work s + ABXYView() + } + } + } + + } + .padding(.bottom, geometry.size.height / 11) // also extremally broken ( + } + } + } +} + +struct ShoulderButtonsViewLeft: View { + var body: some View { + HStack { + ButtonView(button: .triggerZL) + .padding(.horizontal) + ButtonView(button: .triggerL) + .padding(.horizontal) + } + .frame(width: 160, height: 20) + } +} + +struct ShoulderButtonsViewRight: View { + var body: some View { + HStack { + ButtonView(button: .triggerR) + .padding(.horizontal) + ButtonView(button: .triggerZR) + .padding(.horizontal) + } + .frame(width: 160, height: 20) + + } +} + +struct DPadView: View { + var body: some View { + VStack { + ButtonView(button: .directionalPadUp) + HStack { + ButtonView(button: .directionalPadLeft) + Spacer(minLength: 20) + ButtonView(button: .directionalPadRight) + } + ButtonView(button: .directionalPadDown) + .padding(.horizontal) + } + .frame(width: 145, height: 145) + } +} + +struct ABXYView: View { + var body: some View { + VStack { + ButtonView(button: .X) + HStack { + ButtonView(button: .Y) + Spacer(minLength: 20) + ButtonView(button: .A) + } + ButtonView(button: .B) + .padding(.horizontal) + } + .frame(width: 145, height: 145) + } +} + +struct ButtonView: View { + var button: VirtualControllerButtonType + @StateObject private var viewModel: EmulationViewModel = EmulationViewModel(game: nil) + let appui = AppUI.shared + @State var mtkView: MTKView? + @State var width: CGFloat = 45 + @State var height: CGFloat = 45 + @State var isPressed = false + var id: Int { + if onscreenjoy { + return 8 + } + return 0 + } + @AppStorage("onscreenhandheld") var onscreenjoy: Bool = false + @Environment(\.colorScheme) var colorScheme + @Environment(\.presentationMode) var presentationMode + + var body: some View { + Image(systemName: buttonText) + .resizable() + .frame(width: width, height: height) + .foregroundColor(colorScheme == .dark ? Color.gray : Color.gray) + .opacity(isPressed ? 0.5 : 1) + .gesture( + DragGesture(minimumDistance: 0) + .onChanged { _ in + if !self.isPressed { + self.isPressed = true + DispatchQueue.main.async { + if button == .home { + presentationMode.wrappedValue.dismiss() + appui.exit() + } else { + appui.virtualControllerButtonDown(button: button, controllerid: id) + Haptics.shared.play(.heavy) + } + } + } + } + .onEnded { _ in + self.isPressed = false + DispatchQueue.main.async { + if button != .home { + appui.virtualControllerButtonUp(button: button, controllerid: id) + } + } + } + ) + .onAppear() { + if button == .triggerL || button == .triggerZL || button == .triggerZR || button == .triggerR { + width = 65 + } + + + if button == .minus || button == .plus || button == .home { + width = 35 + height = 35 + } + } + } + + private var buttonText: String { + switch button { + case .A: return "a.circle.fill" + case .B: return "b.circle.fill" + case .X: return "x.circle.fill" + case .Y: return "y.circle.fill" + case .directionalPadUp: return "arrowtriangle.up.circle.fill" + case .directionalPadDown: return "arrowtriangle.down.circle.fill" + case .directionalPadLeft: return "arrowtriangle.left.circle.fill" + case .directionalPadRight: return "arrowtriangle.right.circle.fill" + case .triggerZL: return"zl.rectangle.roundedtop.fill" + case .triggerZR: return "zr.rectangle.roundedtop.fill" + case .triggerL: return "l.rectangle.roundedbottom.fill" + case .triggerR: return "r.rectangle.roundedbottom.fill" + case .plus: return "plus.circle.fill" + case .minus: return "minus.circle.fill" + case .home: return "house.circle.fill" + default: return "" + } + } +} diff --git a/src/ios/CoreSettingsView.swift b/src/ios/CoreSettingsView.swift new file mode 100644 index 0000000000..12b5c3c624 --- /dev/null +++ b/src/ios/CoreSettingsView.swift @@ -0,0 +1,88 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI +import Foundation +import AppUI + +struct CoreSettingsView: View { + @State private var text: String = "" + @State private var isLoading: Bool = true + @Environment(\.presentationMode) var presentationMode + + var body: some View { + VStack { + if isLoading { + ProgressView() + .progressViewStyle(CircularProgressViewStyle()) + } else { + TextEditor(text: $text) + .padding() + + } + } + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button { + let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] + let configfolder = documentDirectory.appendingPathComponent("config", conformingTo: .folder) + let fileURL = configfolder.appendingPathComponent("config.ini") + + presentationMode.wrappedValue.dismiss() + + do { + try FileManager.default.removeItem(at: fileURL) + } catch { + print("\(error.localizedDescription)") + } + + AppUI.shared.settingsSaved() + + } label: { + Text("Reset File") + } + } + } + .onAppear { + loadFile() + } + .onDisappear() { + saveFile() + } + } + + private func loadFile() { + let fileManager = FileManager.default + let documentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0] + let configfolder = documentDirectory.appendingPathComponent("config", conformingTo: .folder) + let fileURL = configfolder.appendingPathComponent("config.ini") + + if fileManager.fileExists(atPath: fileURL.path) { + do { + text = try String(contentsOf: fileURL, encoding: .utf8) + } catch { + print("Error reading file: \(error)") + } + } else { + text = "" // Initialize with empty text if file doesn't exist + } + isLoading = false + } + + private func saveFile() { + let fileManager = FileManager.default + let documentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0] + let configfolder = documentDirectory.appendingPathComponent("config", conformingTo: .folder) + let fileURL = configfolder.appendingPathComponent("config.ini") + + do { + try text.write(to: fileURL, atomically: true, encoding: .utf8) + AppUI.shared.settingsSaved() + print("File saved successfully!") + } catch { + print("Error saving file: \(error)") + } + } +} diff --git a/src/ios/DetectServer.swift b/src/ios/DetectServer.swift new file mode 100644 index 0000000000..a36563fc66 --- /dev/null +++ b/src/ios/DetectServer.swift @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import Foundation + +func isSideJITServerDetected(completion: @escaping (Result) -> Void) { + let address = UserDefaults.standard.string(forKey: "sidejitserver") ?? "" + var SJSURL = address + if (address).isEmpty { + SJSURL = "http://sidejitserver._http._tcp.local:8080" + } + // Create a network operation at launch to Refresh SideJITServer + let url = URL(string: SJSURL)! + let task = URLSession.shared.dataTask(with: url) { (data, response, error) in + if let error = error { + print("No SideJITServer on Network") + completion(.failure(error)) + return + } + completion(.success(())) + } + task.resume() + return +} diff --git a/src/ios/EmulationGame.swift b/src/ios/EmulationGame.swift new file mode 100644 index 0000000000..da06753279 --- /dev/null +++ b/src/ios/EmulationGame.swift @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import Foundation + +struct EmulationGame : Comparable, Hashable, Identifiable { + var id = UUID() + + let developer: String + let fileURL: URL + let imageData: Data + let title: String + + func hash(into hasher: inout Hasher) { + hasher.combine(id) + hasher.combine(developer) + hasher.combine(fileURL) + hasher.combine(imageData) + hasher.combine(title) + } + + static func < (lhs: EmulationGame, rhs: Yuzu) -> Bool { + lhs.title < rhs.title + } + + static func == (lhs: EmulationGame, rhs: Yuzu) -> Bool { + lhs.title == rhs.title + } +} diff --git a/src/ios/EmulationHandler.swift b/src/ios/EmulationHandler.swift new file mode 100644 index 0000000000..9ae1e2f248 --- /dev/null +++ b/src/ios/EmulationHandler.swift @@ -0,0 +1,96 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI +import AppUI +import Metal +import Foundation + +class EmulationViewModel: ObservableObject { + @Published var isShowingCustomButton = true + @State var should = false + var device: MTLDevice? + @State var mtkView: MTKView = MTKView() + var CaLayer: CAMetalLayer? + private var sudachiGame: EmulationGame? + private let appui = AppUI.shared + private var thread: Thread! + private var isRunning = false + var doesneedresources = false + @State var iscustom: Bool = false + + init(game: EmulationGame?) { + self.device = MTLCreateSystemDefaultDevice() + self.sudachiGame = game + } + + func configureAppUI(with mtkView: MTKView) { + self.mtkView = mtkView + device = self.mtkView.device + guard !isRunning else { return } + isRunning = true + appui.configure(layer: mtkView.layer as! CAMetalLayer, with: mtkView.frame.size) + + iscustom = ((sudachiGame?.fileURL.startAccessingSecurityScopedResource()) != nil) + + DispatchQueue.global(qos: .userInitiated).async { [self] in + if let sudachiGame = self.sudachiGame { + self.appui.insert(game: sudachiGame.fileURL) + } else { + self.appui.bootOS() + } + } + + thread = .init(block: self.step) + thread.name = "Yuzu" + thread.qualityOfService = .userInteractive + thread.threadPriority = 0.9 + thread.start() + } + + private func step() { + while true { + appui.step() + } + } + + func customButtonTapped() { + stopEmulation() + } + + private func stopEmulation() { + if isRunning { + isRunning = false + appui.exit() + thread.cancel() + if iscustom { + sudachiGame?.fileURL.stopAccessingSecurityScopedResource() + } + } + } + + func handleOrientationChange() { + DispatchQueue.main.async { [weak self] in + guard let self = self else { return } + let interfaceOrientation = self.getInterfaceOrientation(from: UIDevice.current.orientation) + self.appui.orientationChanged(orientation: interfaceOrientation, with: self.mtkView.layer as! CAMetalLayer, size: mtkView.frame.size) + } + } + + private func getInterfaceOrientation(from deviceOrientation: UIDeviceOrientation) -> UIInterfaceOrientation { + switch deviceOrientation { + case .portrait: + return .portrait + case .portraitUpsideDown: + return .portraitUpsideDown + case .landscapeLeft: + return .landscapeRight + case .landscapeRight: + return .landscapeLeft + default: + return .unknown + } + } +} diff --git a/src/ios/EmulationScreenView.swift b/src/ios/EmulationScreenView.swift new file mode 100644 index 0000000000..9db9d5abba --- /dev/null +++ b/src/ios/EmulationScreenView.swift @@ -0,0 +1,133 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI +import AppUI +import MetalKit + +class EmulationScreenView: UIView { + var primaryScreen: UIView! + var portraitconstraints = [NSLayoutConstraint]() + var landscapeconstraints = [NSLayoutConstraint]() + var fullscreenconstraints = [NSLayoutConstraint]() + let appui = AppUI.shared + let userDefaults = UserDefaults.standard + + override init(frame: CGRect) { + super.init(frame: frame) + if UIDevice.current.userInterfaceIdiom == .pad { + setupAppUIScreenforiPad() + } else { + setupAppUIScreen() + } + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + if UIDevice.current.userInterfaceIdiom == .pad { + setupAppUIScreenforiPad() + } else { + setupAppUIScreen() + } + + } + + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + super.touchesBegan(touches, with: event) + guard let touch = touches.first else { + return + } + + print("Location: \(touch.location(in: primaryScreen))") + appui.touchBegan(at: touch.location(in: primaryScreen), for: 0) + } + + override func touchesEnded(_ touches: Set, with event: UIEvent?) { + super.touchesEnded(touches, with: event) + print("Touch Ended") + appui.touchEnded(for: 0) + } + + override func touchesMoved(_ touches: Set, with event: UIEvent?) { + super.touchesMoved(touches, with: event) + guard let touch = touches.first else { + return + } + let location = touch.location(in: primaryScreen) + print("Location Moved: \(location)") + appui.touchMoved(at: location, for: 0) + } + + func setupAppUIScreenforiPad() { + primaryScreen = MTKView(frame: .zero, device: MTLCreateSystemDefaultDevice()) + primaryScreen.translatesAutoresizingMaskIntoConstraints = false + primaryScreen.clipsToBounds = true + primaryScreen.layer.borderColor = UIColor.secondarySystemBackground.cgColor + primaryScreen.layer.borderWidth = 3 + primaryScreen.layer.cornerCurve = .continuous + primaryScreen.layer.cornerRadius = 10 + addSubview(primaryScreen) + + + portraitconstraints = [ + primaryScreen.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 10), + primaryScreen.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 10), + primaryScreen.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor, constant: -10), + primaryScreen.heightAnchor.constraint(equalTo: primaryScreen.widthAnchor, multiplier: 9 / 16), + ] + + landscapeconstraints = [ + primaryScreen.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 50), + primaryScreen.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -100), + primaryScreen.widthAnchor.constraint(equalTo: primaryScreen.heightAnchor, multiplier: 16 / 9), + primaryScreen.centerXAnchor.constraint(equalTo: safeAreaLayoutGuide.centerXAnchor), + ] + + + updateConstraintsForOrientation() + } + + + + func setupAppUIScreen() { + primaryScreen = MTKView(frame: .zero, device: MTLCreateSystemDefaultDevice()) + primaryScreen.translatesAutoresizingMaskIntoConstraints = false + primaryScreen.clipsToBounds = true + primaryScreen.layer.borderColor = UIColor.secondarySystemBackground.cgColor + primaryScreen.layer.borderWidth = 3 + primaryScreen.layer.cornerCurve = .continuous + primaryScreen.layer.cornerRadius = 10 + addSubview(primaryScreen) + + + portraitconstraints = [ + primaryScreen.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 10), + primaryScreen.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 10), + primaryScreen.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor, constant: -10), + primaryScreen.heightAnchor.constraint(equalTo: primaryScreen.widthAnchor, multiplier: 9 / 16), + ] + + landscapeconstraints = [ + primaryScreen.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 10), + primaryScreen.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -10), + primaryScreen.widthAnchor.constraint(equalTo: primaryScreen.heightAnchor, multiplier: 16 / 9), + primaryScreen.centerXAnchor.constraint(equalTo: safeAreaLayoutGuide.centerXAnchor), + ] + + updateConstraintsForOrientation() + } + + override func layoutSubviews() { + super.layoutSubviews() + updateConstraintsForOrientation() + } + + private func updateConstraintsForOrientation() { + removeConstraints(portraitconstraints) + removeConstraints(landscapeconstraints) + let isPortrait = UIApplication.shared.statusBarOrientation.isPortrait + addConstraints(isPortrait ? portraitconstraints : landscapeconstraints) + } +} diff --git a/src/ios/EmulationView.swift b/src/ios/EmulationView.swift new file mode 100644 index 0000000000..586afa88c1 --- /dev/null +++ b/src/ios/EmulationView.swift @@ -0,0 +1,137 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI +import AppUI +import Foundation +import GameController +import UIKit +import SwiftUIIntrospect + +struct EmulationView: View { + @StateObject private var viewModel: EmulationViewModel + @State var controllerconnected = false + @State var appui = AppUI.shared + var device: MTLDevice? = MTLCreateSystemDefaultDevice() + @State var CaLayer: CAMetalLayer? + @State var ShowPopup: Bool = false + @State var mtkview: MTKView? + @State private var thread: Thread! + @State var uiTabBarController: UITabBarController? + @State private var isFirstFrameShown = false + @State private var timer: Timer? + @Environment(\.scenePhase) var scenePhase + + init(game: EmulationGame?) { + _viewModel = StateObject(wrappedValue: EmulationViewModel(game: game)) + } + + var body: some View { + ZStack { + MetalView(device: device) { view in + DispatchQueue.main.async { + if let metalView = view as? MTKView { + mtkview = metalView + viewModel.configureAppUI(with: metalView) + } else { + print("Error: view is not of type MTKView") + } + } + } + .onRotate { size in + viewModel.handleOrientationChange() + } + ControllerView() + } + .overlay( + // Loading screen overlay on top of MetalView + Group { + if !isFirstFrameShown { + LoadingView() + } + } + .transition(.opacity) + ) + .onAppear { + UIApplication.shared.isIdleTimerDisabled = true + startPollingFirstFrameShowed() + } + .onDisappear { + stopPollingFirstFrameShowed() + uiTabBarController?.tabBar.isHidden = false + viewModel.customButtonTapped() + } + .navigationBarBackButtonHidden(true) + .introspect(.tabView, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { (tabBarController) in + tabBarController.tabBar.isHidden = true + uiTabBarController = tabBarController + } + } + + private func startPollingFirstFrameShowed() { + timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { _ in + if appui.FirstFrameShowed() { + withAnimation { + isFirstFrameShown = true + } + stopPollingFirstFrameShowed() + } + } + } + + private func stopPollingFirstFrameShowed() { + timer?.invalidate() + timer = nil + print("Timer Invalidated") + } +} + +struct LoadingView: View { + var body: some View { + VStack { + ProgressView("Loading...") + // .font(.system(size: 90)) + .progressViewStyle(CircularProgressViewStyle()) + .padding() + Text("Please wait while the game loads.") + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(Color.black.opacity(0.8)) + .foregroundColor(.white) + } +} + +extension View { + func onRotate(perform action: @escaping (CGSize) -> Void) -> some View { + self.modifier(DeviceRotationModifier(action: action)) + } +} + +struct DeviceRotationModifier: ViewModifier { + let action: (CGSize) -> Void + @State var startedfirst: Bool = false + + func body(content: Content) -> some View { content + .background(GeometryReader { geometry in + Color.clear + .preference(key: SizePreferenceKey.self, value: geometry.size) + }) + .onPreferenceChange(SizePreferenceKey.self) { newSize in + if startedfirst { + action(newSize) + } else { + startedfirst = true + } + } + } +} + +struct SizePreferenceKey: PreferenceKey { + static var defaultValue: CGSize = .zero + + static func reduce(value: inout CGSize, nextValue: () -> CGSize) { + value = nextValue() + } +} diff --git a/src/ios/EnableJIT.swift b/src/ios/EnableJIT.swift new file mode 100644 index 0000000000..105615fd29 --- /dev/null +++ b/src/ios/EnableJIT.swift @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import Foundation + +enum SideJITServerErrorType: Error { + case invalidURL + case errorConnecting + case deviceNotFound + case other(String) +} + +func sendrequestsidejit(url: String, completion: @escaping (Result) -> Void) { + let url = URL(string: url)! + let task = URLSession.shared.dataTask(with: url) {(data, response, error) in + if let error = error { + completion(.failure(.errorConnecting)) + return + } + guard let data = data, let datastring = String(data: data, encoding: .utf8) else { return } + if datastring == "Enabled JIT" { + completion(.success(())) + } else { + let errorType: SideJITServerErrorType = datastring == "Could not find device!" ? .deviceNotFound : .other(datastring) + completion(.failure(errorType)) + } + } + task.resume() +} + +func sendrefresh(url: String, completion: @escaping (Result) -> Void) { + let url = URL(string: url)! + + let task = URLSession.shared.dataTask(with: url) {(data, response, error) in + if let error = error { + completion(.failure(.errorConnecting)) + return + } + + guard let data = data, let datastring = String(data: data, encoding: .utf8) else { return } + let inputText = "{\"OK\":\"Refreshed!\"}" + if datastring == inputText { + completion(.success(())) + } else { + let errorType: SideJITServerErrorType = datastring == "Could not find device!" ? .deviceNotFound : .other(datastring) + completion(.failure(errorType)) + } + } + task.resume() +} diff --git a/src/ios/FileManager.swift b/src/ios/FileManager.swift new file mode 100644 index 0000000000..f3fddff8b1 --- /dev/null +++ b/src/ios/FileManager.swift @@ -0,0 +1,254 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI +import Foundation +import UIKit +import AppUI +import Zip + +struct Core : Comparable, Hashable { + + let name = "Yuzu" + var games: [EmulationGame] + let root: URL + + static func < (lhs: Core, rhs: Core) -> Bool { + lhs.name < rhs.name + } + + func AddFirmware(at fileURL: URL) { + do { + let fileManager = FileManager.default + let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first! + let destinationURL = documentsDirectory.appendingPathComponent("nand/system/Contents/registered") + + + if !fileManager.fileExists(atPath: destinationURL.path) { + try fileManager.createDirectory(at: destinationURL, withIntermediateDirectories: true, attributes: nil) + } + + + try Zip.unzipFile(fileURL, destination: destinationURL, overwrite: true, password: nil) + print("File unzipped successfully to \(destinationURL.path)") + + } catch { + print("Failed to unzip file: \(error)") + } + } +} + +class YuzuFileManager { + static var shared = YuzuFileManager() + + func directories() -> [String : [String : String]] { + [ + "themes" : [:], + "amiibo" : [:], + "cache" : [:], + "config" : [:], + "crash_dumps" : [:], + "dump" : [:], + "keys" : [:], + "load" : [:], + "log" : [:], + "nand" : [:], + "play_time" : [:], + "roms" : [:], + "screenshots" : [:], + "sdmc" : [:], + "shader" : [:], + "tas" : [:], + "icons" : [:] + ] + } + + func createdirectories() throws { + let documentdir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] + try directories().forEach() { directory, filename in + let directoryURL = documentdir.appendingPathComponent(directory) + + if !FileManager.default.fileExists(atPath: directoryURL.path) { + print("creating dir at \(directoryURL.path)") // yippee + try FileManager.default.createDirectory(at: directoryURL, withIntermediateDirectories: false, attributes: nil) + } + } + } + + func DetectKeys() -> (Bool, Bool) { + var prodkeys = false + var titlekeys = false + let filemanager = FileManager.default + let documentdir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] + let KeysFolderURL = documentdir.appendingPathComponent("keys") + prodkeys = filemanager.fileExists(atPath: KeysFolderURL.appendingPathComponent("prod.keys").path) + titlekeys = filemanager.fileExists(atPath: KeysFolderURL.appendingPathComponent("title.keys").path) + return (prodkeys, titlekeys) + } +} + +enum LibManError : Error { + case ripenum, urlgobyebye +} + +class LibraryManager { + static let shared = LibraryManager() + let documentdir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("roms", conformingTo: .folder) + + + func removerom(_ game: EmulationGame) throws { + do { + try FileManager.default.removeItem(at: game.fileURL) + } catch { + throw error + } + } + + func homebrewroms() -> [EmulationGame] { + // TODO(lizzie): this is horrible + var urls: [URL] = [] + let sdmc = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("sdmc", conformingTo: .folder) + let sdfolder = sdmc.appendingPathComponent("switch", conformingTo: .folder) + if FileManager.default.fileExists(atPath: sdfolder.path) { + if let dirContents = FileManager.default.enumerator(at: sdmc, includingPropertiesForKeys: nil, options: []) { + do { + try dirContents.forEach() { files in + if let file = files as? URL { + let getaboutfile = try file.resourceValues(forKeys: [.isRegularFileKey]) + if let isfile = getaboutfile.isRegularFile, isfile { + if ["nso", "nro"].contains(file.pathExtension.lowercased()) { + urls.append(file) + } + } + } + } + } catch { + if let dirContents = FileManager.default.enumerator(at: documentdir, includingPropertiesForKeys: nil, options: []) { + do { + try dirContents.forEach() { files in + if let file = files as? URL { + let getaboutfile = try file.resourceValues(forKeys: [.isRegularFileKey]) + if let isfile = getaboutfile.isRegularFile, isfile { + if ["nso", "nro"].contains(file.pathExtension.lowercased()) { + urls.append(file) + } + } + } + } + } catch { + print("damn") + if let dirContents = FileManager.default.enumerator(at: documentdir, includingPropertiesForKeys: nil, options: []) { + do { + try dirContents.forEach() { files in + if let file = files as? URL { + let getaboutfile = try file.resourceValues(forKeys: [.isRegularFileKey]) + if let isfile = getaboutfile.isRegularFile, isfile { + if ["nso", "nro"].contains(file.pathExtension.lowercased()) { + urls.append(file) + } + } + } + } + } catch { + return [] + } + } else { + return [] + } + + } + } + } + } + } + if let dirContents = FileManager.default.enumerator(at: documentdir, includingPropertiesForKeys: nil, options: []) { + do { + try dirContents.forEach() { files in + if let file = files as? URL { + let getaboutfile = try file.resourceValues(forKeys: [.isRegularFileKey]) + if let isfile = getaboutfile.isRegularFile, isfile { + if ["nso", "nro"].contains(file.pathExtension.lowercased()) { + urls.append(file) + } + } + } + } + } catch { + return [] + } + } else { + return [] + } + func games(from urls: [URL]) -> [EmulationGame] { + var pomelogames: [EmulationGame] = [] + pomelogames = urls.reduce(into: [EmulationGame]()) { partialResult, element in + let iscustom = element.startAccessingSecurityScopedResource() + let information = AppUI.shared.information(for: element) + let game = EmulationGame(developer: information.developer, fileURL: element, imageData: information.iconData, title: information.title) + if iscustom { + element.stopAccessingSecurityScopedResource() + } + partialResult.append(game) + } + return pomelogames + } + return games(from: urls) + } + + func library() throws -> Core { + func getromsfromdir() throws -> [URL] { + guard let dirContents = FileManager.default.enumerator(at: documentdir, includingPropertiesForKeys: nil, options: []) else { + print("uhoh how unfortunate for some reason FileManager.default.enumerator aint workin") + throw LibManError.ripenum + } + let appui = AppUI.shared + var urls: [URL] = [] + try dirContents.forEach() { files in + if let file = files as? URL { + let getaboutfile = try file.resourceValues(forKeys: [.isRegularFileKey]) + if let isfile = getaboutfile.isRegularFile, isfile { + if ["nca", "nro", "nsp", "nso", "xci"].contains(file.pathExtension.lowercased()) { + urls.append(file) + } + } + } + } + let sdmc = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("sdmc", conformingTo: .folder) + let sdfolder = sdmc.appendingPathComponent("switch", conformingTo: .folder) + if FileManager.default.fileExists(atPath: sdfolder.path) { + if let dirContents = FileManager.default.enumerator(at: sdmc, includingPropertiesForKeys: nil, options: []) { + try dirContents.forEach() { files in + if let file = files as? URL { + let getaboutfile = try file.resourceValues(forKeys: [.isRegularFileKey]) + if let isfile = getaboutfile.isRegularFile, isfile { + if ["nso", "nro"].contains(file.pathExtension.lowercased()) { + urls.append(file) + } + } + } + } + } + } + appui.insert(games: urls) + return urls + } + + func games(from urls: [URL], core: inout Core) { + core.games = urls.reduce(into: [EmulationGame]()) { partialResult, element in + let iscustom = element.startAccessingSecurityScopedResource() + let information = AppUI.shared.information(for: element) + let game = EmulationGame(developer: information.developer, fileURL: element, imageData: information.iconData, title: information.title) + if iscustom { + element.stopAccessingSecurityScopedResource() + } + partialResult.append(game) + } + } + let directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] + var YuzuCore = Core(games: [], root: directory) + games(from: try getromsfromdir(), core: &YuzuCore) + return YuzuCore + } +} diff --git a/src/ios/FolderMonitor.swift b/src/ios/FolderMonitor.swift new file mode 100644 index 0000000000..ecae4c0857 --- /dev/null +++ b/src/ios/FolderMonitor.swift @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import Foundation + +class FolderMonitor { + private var folderDescriptor: Int32 = -1 + private var folderMonitorSource: DispatchSourceFileSystemObject? + private let folderURL: URL + private let onFolderChange: () -> Void + init(folderURL: URL, onFolderChange: @escaping () -> Void) { + self.folderURL = folderURL + self.onFolderChange = onFolderChange + startMonitoring() + } + private func startMonitoring() { + folderDescriptor = open(folderURL.path, O_EVTONLY) + guard folderDescriptor != -1 else { + print("Failed to open folder descriptor.") + return + } + + folderMonitorSource = DispatchSource.makeFileSystemObjectSource( + fileDescriptor: folderDescriptor, + eventMask: .write, + queue: DispatchQueue.global() + ) + folderMonitorSource?.setEventHandler { [weak self] in + self?.folderDidChange() + } + folderMonitorSource?.setCancelHandler { + close(self.folderDescriptor) + } + folderMonitorSource?.resume() + } + + private func folderDidChange() { + // Detect the change and call the refreshcore function + print("Folder changed! New file added or removed.") + DispatchQueue.main.async { [weak self] in + self?.onFolderChange() + } + } + deinit { + folderMonitorSource?.cancel() + } +} diff --git a/src/ios/GameButtonListView.swift b/src/ios/GameButtonListView.swift new file mode 100644 index 0000000000..c58d329e72 --- /dev/null +++ b/src/ios/GameButtonListView.swift @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, TechGuy +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI +import Foundation +import UIKit + +struct GameButtonListView: View { + var game: EmulationGame + @Environment(\.colorScheme) var colorScheme + + var body: some View { + HStack(spacing: 15) { + if let image = UIImage(data: game.imageData) { + Image(uiImage: image) + .resizable() + .frame(width: 60, height: 60) + .cornerRadius(8) + } else { + Image(systemName: "photo") + .resizable() + .frame(width: 60, height: 60) + .cornerRadius(8) + } + + VStack(alignment: .leading, spacing: 4) { + Text(game.title) + .font(.headline) + .foregroundColor(colorScheme == .dark ? Color.white : Color.black) + Text(game.developer) + .font(.subheadline) + .foregroundColor(.gray) + } + Spacer() + } + .padding(.vertical, 8) + } +} diff --git a/src/ios/GameButtonView.swift b/src/ios/GameButtonView.swift new file mode 100644 index 0000000000..fae44544e7 --- /dev/null +++ b/src/ios/GameButtonView.swift @@ -0,0 +1,182 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI +import Foundation +import UIKit +import UniformTypeIdentifiers +import Combine + +struct GameIconView: View { + var game: EmulationGame + @Binding var selectedGame: EmulationGame? + @State var startgame: Bool = false + @State var timesTapped: Int = 0 + + var isSelected: Bool { + selectedGame == game + } + + var body: some View { + NavigationLink( + destination: EmulationView(game: game).toolbar(.hidden, for: .tabBar), + isActive: $startgame, + label: { + EmptyView() + } + ) + VStack(spacing: 5) { + if isSelected { + Text(game.title) + .foregroundColor(.blue) + .font(.title2) + } + if let uiImage = UIImage(data: game.imageData) { + Image(uiImage: uiImage) + .resizable() + .scaledToFit() + .frame(width: isSelected ? 200 : 180, height: isSelected ? 200 : 180) + .cornerRadius(10) + .overlay( + isSelected ? RoundedRectangle(cornerRadius: 10) + .stroke(Color.blue, lineWidth: 5) + : nil + ) + .onTapGesture { + if isSelected { + startgame = true + print(isSelected) + } + if !isSelected { + selectedGame = game + } + } + } else { + Image(systemName: "questionmark") + .resizable() + .scaledToFit() + .frame(width: 200, height: 200) + .cornerRadius(10) + .onTapGesture { selectedGame = game } + } + } + .frame(width: 200, height: 250) + } +} + +struct BottomMenuView: View { + @State var core: Core + var body: some View { + HStack(spacing: 40) { + Button { + + } label: { + Circle() + .overlay { + Image(systemName: "message").font(.system(size: 30)).foregroundColor(.red) + } + .frame(width: 50, height: 50) + .foregroundColor(Color.init(uiColor: .lightGray)) + } + Button { + + } label: { + Circle() + .overlay { + Image(systemName: "photo").font(.system(size: 30)).foregroundColor(.blue) + } + .frame(width: 50, height: 50) + .foregroundColor(Color.init(uiColor: .lightGray)) + } + NavigationLink(destination: SettingsView(core: core)) { + Circle() + .overlay { + Image(systemName: "gearshape").foregroundColor(Color.init(uiColor: .darkGray)).font(.system(size: 30)) + } + .frame(width: 50, height: 50) + .foregroundColor(Color.init(uiColor: .lightGray)) + } + + Button { + + } label: { + Circle() + .overlay { + Image(systemName: "power").foregroundColor(Color.init(uiColor: .darkGray)).font(.system(size: 30)) + } + .frame(width: 50, height: 50) + .foregroundColor(Color.init(uiColor: .lightGray)) + } + } + .padding(.bottom, 20) + } +} + +struct HomeView: View { + @State private var selectedGame: EmulationGame? = nil + + @State var core: Core + + init(selectedGame: EmulationGame? = nil, core: Core) { + _core = State(wrappedValue: core) + self.selectedGame = selectedGame + refreshcore() + } + + var body: some View { + NavigationStack { + GeometryReader { geometry in + VStack { + GameCarouselView(core: core, selectedGame: $selectedGame) + Spacer() + BottomMenuView(core: core) + } + } + } + .background(Color.gray.opacity(0.1)) + .edgesIgnoringSafeArea(.all) + .onAppear { + refreshcore() + if let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first { + let romsFolderURL = documentsDirectory.appendingPathComponent("roms") + let folderMonitor = FolderMonitor(folderURL: romsFolderURL) { + do { + core = Core(games: [], root: documentsDirectory) + core = try LibraryManager.shared.library() + } catch { + print("Error refreshing core: \(error)") + } + } + } + } + } + + func refreshcore() { + print("Loading library...") + do { + core = try LibraryManager.shared.library() + print(core.games) + } catch { + print("Failed to fetch library: \(error)") + return + } + } +} + + +struct GameCarouselView: View { + // let games: [EmulationGame] + @State var core: Core + @Binding var selectedGame: EmulationGame? + var body: some View { + ScrollView(.horizontal, showsIndicators: false) { + HStack(spacing: 20) { + ForEach(core.games) { game in + GameIconView(game: game, selectedGame: $selectedGame) + } + } + } + } +} diff --git a/src/ios/GameListView.swift b/src/ios/GameListView.swift new file mode 100644 index 0000000000..1c8d39e780 --- /dev/null +++ b/src/ios/GameListView.swift @@ -0,0 +1,140 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI +import Foundation +import UIKit +import UniformTypeIdentifiers +import AppUI + +struct GameListView: View { + @State var core: Core + @State private var searchText = "" + @State var game: Int = 1 + @State var startgame: Bool = false + @Binding var isGridView: Bool + @State var showAlert = false + @State var alertMessage: Alert? = nil + + var body: some View { + let filteredGames = core.games.filter { game in + guard let EmulationGame = game as? PoYuzume else { return false } + return searchText.isEmpty || EmulationGame.title.localizedCaseInsensitiveContains(searchText) + } + + ScrollView { + VStack { + VStack(alignment: .leading) { + + if isGridView { + LazyVGrid(columns: [GridItem(.adaptive(minimum: 160))], spacing: 10) { + ForEach(0.. String { + guard let s = infoDictionary?["CFBundleShortVersionString"] as? String else { + return "Unknown" + } + return s + } +} diff --git a/src/ios/JoystickView.swift b/src/ios/JoystickView.swift new file mode 100644 index 0000000000..24ce8e4739 --- /dev/null +++ b/src/ios/JoystickView.swift @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI +import SwiftUIJoystick +import AppUI + +public struct Joystick: View { + @State var iscool: Bool? = nil + var id: Int { + if onscreenjoy { + return 8 + } + return 0 + } + @AppStorage("onscreenhandheld") var onscreenjoy: Bool = false + + let appui = AppUI.shared + + @ObservedObject public var joystickMonitor = JoystickMonitor() + private let dragDiameter: CGFloat = 160 + private let shape: JoystickShape = .circle + + public var body: some View { + VStack{ + JoystickBuilder( + monitor: self.joystickMonitor, + width: self.dragDiameter, + shape: .circle, + background: { + // Example Background + RoundedRectangle(cornerRadius: 8).fill(Color.gray.opacity(0)) + }, + foreground: { + // Example Thumb + Circle().fill(Color.gray) + }, + locksInPlace: false) + .onChange(of: self.joystickMonitor.xyPoint) { newValue in + let scaledX = Float(newValue.x) + let scaledY = Float(-newValue.y) // my dumbass broke this by having -y instead of y :/ (well it appears that with the new joystick code, its supposed to be -y) + joystickMonitor.objectWillChange + print("Joystick Position: (\(scaledX), \(scaledY))") + + if iscool != nil { + appui.thumbstickMoved(analog: .right, x: scaledX, y: scaledY, controllerid: id) + } else { + appui.thumbstickMoved(analog: .left, x: scaledX, y: scaledY, controllerid: id) + } + } + } + } +} diff --git a/src/ios/KeyboardHostingController.swift b/src/ios/KeyboardHostingController.swift new file mode 100644 index 0000000000..85e1cd01d0 --- /dev/null +++ b/src/ios/KeyboardHostingController.swift @@ -0,0 +1,76 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI +import UIKit + +class KeyboardHostingController: UIHostingController { + + override var canBecomeFirstResponder: Bool { + return true + } + + override func viewDidLoad() { + super.viewDidLoad() + becomeFirstResponder() // Make sure the view can become the first responder + } + + override var keyCommands: [UIKeyCommand]? { + return [ + UIKeyCommand(input: UIKeyCommand.inputUpArrow, modifierFlags: [], action: #selector(handleKeyCommand)), + UIKeyCommand(input: UIKeyCommand.inputDownArrow, modifierFlags: [], action: #selector(handleKeyCommand)), + UIKeyCommand(input: UIKeyCommand.inputLeftArrow, modifierFlags: [], action: #selector(handleKeyCommand)), + UIKeyCommand(input: UIKeyCommand.inputRightArrow, modifierFlags: [], action: #selector(handleKeyCommand)), + UIKeyCommand(input: "w", modifierFlags: [], action: #selector(handleKeyCommand)), + UIKeyCommand(input: "s", modifierFlags: [], action: #selector(handleKeyCommand)), + UIKeyCommand(input: "a", modifierFlags: [], action: #selector(handleKeyCommand)), + UIKeyCommand(input: "d", modifierFlags: [], action: #selector(handleKeyCommand)) + ] + } + + @objc func handleKeyCommand(_ sender: UIKeyCommand) { + if let input = sender.input { + switch input { + case UIKeyCommand.inputUpArrow: + print("Up Arrow Pressed") + case UIKeyCommand.inputDownArrow: + print("Down Arrow Pressed") + case UIKeyCommand.inputLeftArrow: + print("Left Arrow Pressed") + case UIKeyCommand.inputRightArrow: + print("Right Arrow Pressed") + case "w": + print("W Key Pressed") + case "s": + print("S Key Pressed") + case "a": + print("A Key Pressed") + case "d": + print("D Key Pressed") + default: + break + } + } + } +} + + +struct KeyboardSupportView: UIViewControllerRepresentable { + let content: Text + + func makeUIViewController(context: Context) -> KeyboardHostingController { + return KeyboardHostingController(rootView: content) + } + + func updateUIViewController(_ uiViewController: KeyboardHostingController, context: Context) { + // Handle any updates needed + } +} + +struct KeyboardView: View { + var body: some View { + KeyboardSupportView(content: Text("")) + } +} diff --git a/src/ios/LibraryView.swift b/src/ios/LibraryView.swift new file mode 100644 index 0000000000..c85b39608d --- /dev/null +++ b/src/ios/LibraryView.swift @@ -0,0 +1,191 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI +import CryptoKit +import AppUI + +struct LibraryView: View { + @Binding var core: Core + @State var isGridView: Bool = true + @State var doesitexist = (false, false) + @State var importedgame: EmulationGame? = nil + @State var importgame: Bool = false + @State var isimportingfirm: Bool = false + @State var launchGame: Bool = false + var body: some View { + NavigationStack { + if let importedgame = importedgame { + NavigationLink( + isActive: $launchGame, + destination: { + EmulationView(game: importedgame).toolbar(.hidden, for: .tabBar) + }, + label: { + EmptyView() // This keeps the link hidden + } + ) + } + + VStack { + if doesitexist.0, doesitexist.1 { + HomeView(core: core) + } else { + let (doesKeyExist, doesProdExist) = doeskeysexist() + ScrollView { + Text("You Are Missing These Files:") + .font(.headline) + .foregroundColor(.red) + HStack { + if !doesProdExist { + Text("Prod.keys") + .font(.subheadline) + .foregroundColor(.red) + } + if !doesKeyExist { + Text("Title.keys") + .font(.subheadline) + .foregroundColor(.red) + } + } + Text("These goes into the Keys folder") + .font(.caption) + .foregroundColor(.red) + .padding(.bottom) + + if !LibraryManager.shared.homebrewroms().isEmpty { + Text("Homebrew Roms:") + .font(.headline) + LazyVGrid(columns: [GridItem(.adaptive(minimum: 160))], spacing: 10) { + ForEach(LibraryManager.shared.homebrewroms()) { game in + NavigationLink(destination: EmulationView(game: game).toolbar(.hidden, for: .tabBar)) { + // GameButtonView(game: game) + // .frame(maxWidth: .infinity, minHeight: 200) + } + .contextMenu { + NavigationLink(destination: EmulationView(game: game)) { + Text("Launch") + } + } + } + } + } + } + .refreshable { + doesitexist = doeskeysexist() + } + + + } + + } + .fileImporter(isPresented: $isimportingfirm, allowedContentTypes: [.zip], onCompletion: { result in + switch result { + case .success(let elements): + core.AddFirmware(at: elements) + case .failure(let error): + + print(error.localizedDescription) + } + }) + .fileImporter(isPresented: $importgame, allowedContentTypes: [.item], onCompletion: { result in + switch result { + case .success(let elements): + let iscustom = elements.startAccessingSecurityScopedResource() + let information = AppUI.shared.information(for: elements) + + let game = EmulationGame(developer: information.developer, fileURL: elements, + imageData: information.iconData, + title: information.title) + + importedgame = game + + + DispatchQueue.main.async { + + if iscustom { + elements.stopAccessingSecurityScopedResource() + } + + launchGame = true + } + case .failure(let error): + + print(error.localizedDescription) + } + }) + .onAppear() { + doesitexist = doeskeysexist() + } + .navigationBarTitle("Library", displayMode: .inline) + .toolbar { + ToolbarItem(placement: .navigationBarLeading) { // why did this take me so long to figure out lmfao + Button(action: { + isGridView.toggle() + }) { + Image(systemName: isGridView ? "rectangle.grid.1x2" : "square.grid.2x2") + .imageScale(.large) + .padding() + } + } + + ToolbarItem(placement: .navigationBarTrailing) { // funsies + Menu { + Button(action: { + importgame = true // this part took a while + + }) { + Text("Launch Game") + } + + Button(action: { + isimportingfirm = true + }) { + Text("Import Firmware") + } + } label: { + Image(systemName: "plus.circle.fill") + .imageScale(.large) + .padding() + } + + } + } + } + } + + + func doeskeysexist() -> (Bool, Bool) { + var doesprodexist = false + var doestitleexist = false + + + let title = core.root.appendingPathComponent("keys").appendingPathComponent("title.keys") + let prod = core.root.appendingPathComponent("keys").appendingPathComponent("prod.keys") + let fileManager = FileManager.default + let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0] + + if fileManager.fileExists(atPath: prod.path) { + doesprodexist = true + } else { + print("File does not exist") + } + + if fileManager.fileExists(atPath: title.path) { + doestitleexist = true + } else { + print("File does not exist") + } + + return (doestitleexist, doesprodexist) + } +} + +func getDeveloperNames() -> String { + guard let s = infoDictionary?["CFBundleIdentifier"] as? String else { + return "Unknown" + } + return s +} diff --git a/src/ios/MetalView.swift b/src/ios/MetalView.swift new file mode 100644 index 0000000000..c6a746e9f2 --- /dev/null +++ b/src/ios/MetalView.swift @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI +import Metal +import AppUI + +struct MetalView: UIViewRepresentable { + let device: MTLDevice? + let configure: (UIView) -> Void + + func makeUIView(context: Context) -> EmulationScreenView { + let view = EmulationScreenView() + configure(view.primaryScreen) + return view + } + + func updateUIView(_ uiView: EmulationScreenView, context: Context) { + // + } +} diff --git a/src/ios/NavView.swift b/src/ios/NavView.swift new file mode 100644 index 0000000000..b989dd5925 --- /dev/null +++ b/src/ios/NavView.swift @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI +import AppUI + +struct NavView: View { + @Binding var core: Core + @State private var selectedTab = 0 + var body: some View { + TabView(selection: $selectedTab) { + LibraryView(core: $core) + .tabItem { Label("Library", systemImage: "rectangle.on.rectangle") } + .tag(0) + BootOSView(core: $core, currentnavigarion: $selectedTab) + .toolbar(.hidden, for: .tabBar) + .tabItem { Label("Boot OS", systemImage: "house") } + .tag(1) + SettingsView(core: core) + .tabItem { Label("Settings", systemImage: "gear") } + .tag(2) + } + } +} diff --git a/src/ios/SettingsView.swift b/src/ios/SettingsView.swift new file mode 100644 index 0000000000..dca90e7574 --- /dev/null +++ b/src/ios/SettingsView.swift @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 Pomelo, Stossy11 +// SPDX-License-Identifier: GPL-3.0-or-later + +import SwiftUI + +struct SettingsView: View { + @State var core: Core + @State var showprompt = false + + @AppStorage("icon") var iconused = 1 + var body: some View { + NavigationStack { + + } + } +}