diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3aaf9a93..ed8bb077 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -128,7 +128,16 @@ jobs: path: artifacts build-windows: - runs-on: windows-2022 + strategy: + fail-fast: false + matrix: + include: + - os: windows-2022 + arch: x64 + - os: windows-11-arm + arch: arm64 + name: build-windows-${{ matrix.arch }} + runs-on: ${{ matrix.os }} steps: - name: "Checkout repo" uses: actions/checkout@v6 @@ -190,19 +199,19 @@ jobs: shell: cmd run: | cd src\resource - makensis /DPRODUCT_VERSION=${{ inputs.next_version_major }}.${{ inputs.next_version_minor }} installer.nsi + makensis /DPRODUCT_VERSION=${{ inputs.next_version_major }}.${{ inputs.next_version_minor }} /DARCH=${{ matrix.arch }} installer.nsi - name: Upload artifact uses: actions/upload-artifact@v6 with: - name: cemu-bin-windows-x64 + name: cemu-bin-windows-${{ matrix.arch }} path: ./bin/Cemu.exe - name: Upload NSIS Installer uses: actions/upload-artifact@v6 with: - name: cemu-installer-windows-x64 - path: ./src/resource/cemu-${{ inputs.next_version_major }}.${{ inputs.next_version_minor }}-windows-x64-installer.exe + name: cemu-installer-windows-${{ matrix.arch }} + path: ./src/resource/cemu-${{ inputs.next_version_major }}.${{ inputs.next_version_minor }}-windows-${{ matrix.arch }}-installer.exe build-macos: runs-on: macos-14 diff --git a/CMakeLists.txt b/CMakeLists.txt index 644032ce..b8541b3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,8 +51,16 @@ if (ENABLE_VCPKG) # CONFIG option set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE) if (WIN32) - set(VCPKG_TARGET_TRIPLET "x64-windows-static" CACHE STRING "") - endif() + message(STATUS "CPU Arch is: $ENV{PROCESSOR_ARCHITECTURE}") + if($ENV{PROCESSOR_ARCHITECTURE} MATCHES "x86_64|amd64|AMD64") + set(VCPKG_TARGET_TRIPLET "x64-windows-static" CACHE STRING "" FORCE) + set(VCPKG_HOST_TRIPLET "x64-windows-static" CACHE STRING "" FORCE) + else() + set(VCPKG_TARGET_TRIPLET "arm64-windows-static" CACHE STRING "" FORCE) + set(VCPKG_HOST_TRIPLET "arm64-windows-static" CACHE STRING "" FORCE) + endif() + message(STATUS "Using VCPKG triplet: ${VCPKG_TARGET_TRIPLET}") + endif() endif() project(Cemu VERSION 2.0.0) @@ -79,6 +87,7 @@ set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON) if (MSVC) set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT CemuBin) # floating point model: precise, fiber safe optimizations + add_compile_definitions(NOMINMAX) add_compile_options(/EHsc /fp:precise) if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") # Speeds up static linking (especially helpful in incremental compilation) @@ -173,6 +182,19 @@ if (NOT TARGET glslang::SPIRV AND TARGET SPIRV) add_library(glslang::SPIRV ALIAS SPIRV) endif() +if (UNIX AND NOT APPLE) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") + set(ARCH_TRIPLET "aarch64-linux-gnu") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") + set(ARCH_TRIPLET "x86_64-linux-gnu") + else() + message(WARNING "Unknown architecture: ${CMAKE_SYSTEM_PROCESSOR}") + endif() + if(ARCH_TRIPLET) + set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/share/pkgconfig:/usr/lib/${ARCH_TRIPLET}/pkgconfig:/usr/local/share/pkgconfig") + endif() +endif() + if (UNIX AND NOT APPLE) find_package(X11 REQUIRED) if (ENABLE_WAYLAND) @@ -253,6 +275,9 @@ if (ENABLE_CUBEB) endif() add_subdirectory("dependencies/ih264d" EXCLUDE_FROM_ALL) +if(MSVC) + target_compile_options(ih264d PRIVATE /wd4005) +endif() if (CMAKE_OSX_ARCHITECTURES) set(CEMU_ARCHITECTURE ${CMAKE_OSX_ARCHITECTURES}) @@ -261,6 +286,9 @@ else() endif() if(CEMU_ARCHITECTURE MATCHES "(aarch64)|(AARCH64)|(arm64)|(ARM64)") add_subdirectory("dependencies/xbyak_aarch64" EXCLUDE_FROM_ALL) + if(MSVC) + target_compile_options(xbyak_aarch64 PRIVATE "/wd4245" "/wd4458") + endif() endif() find_package(ZArchive QUIET) diff --git a/CMakeSettings.json b/CMakeSettings.json index 0927e98b..7ea3d70e 100644 --- a/CMakeSettings.json +++ b/CMakeSettings.json @@ -1,4 +1,4 @@ -{ +{ "configurations": [ { "name": "RelWithDebInfo", @@ -25,4 +25,4 @@ "installRoot": "${projectDir}\\out\\install\\${name}" } ] -} \ No newline at end of file +} diff --git a/dependencies/ih264d/CMakeLists.txt b/dependencies/ih264d/CMakeLists.txt index a8ef3776..3f26cc49 100644 --- a/dependencies/ih264d/CMakeLists.txt +++ b/dependencies/ih264d/CMakeLists.txt @@ -1,204 +1,148 @@ -cmake_minimum_required (VERSION 3.8) +cmake_minimum_required(VERSION 3.10) -project ("ih264d") +project(ih264d LANGUAGES C) -add_library (ih264d -"common/ih264_buf_mgr.c" -"common/ih264_buf_mgr.h" -"common/ih264_cabac_tables.c" -"common/ih264_cabac_tables.h" -"common/ih264_cavlc_tables.c" -"common/ih264_cavlc_tables.h" -"common/ih264_chroma_intra_pred_filters.c" -"common/ih264_common_tables.c" -"common/ih264_common_tables.h" -"common/ih264_deblk_edge_filters.c" -"common/ih264_deblk_edge_filters.h" -"common/ih264_deblk_tables.c" -"common/ih264_deblk_tables.h" -"common/ih264_debug.h" -"common/ih264_defs.h" -"common/ih264_disp_mgr.c" -"common/ih264_disp_mgr.h" -"common/ih264_dpb_mgr.c" -"common/ih264_dpb_mgr.h" -"common/ih264_error.h" -"common/ih264_ihadamard_scaling.c" -"common/ih264_inter_pred_filters.c" -"common/ih264_inter_pred_filters.h" -"common/ih264_intra_pred_filters.h" -"common/ih264_iquant_itrans_recon.c" -"common/ih264_list.c" -"common/ih264_list.h" -"common/ih264_luma_intra_pred_filters.c" -"common/ih264_macros.h" -"common/ih264_mem_fns.c" -"common/ih264_mem_fns.h" -"common/ih264_padding.c" -"common/ih264_padding.h" -"common/ih264_resi_trans.h" -"common/ih264_resi_trans_quant.c" -"common/ih264_size_defs.h" -"common/ih264_structs.h" -"common/ih264_trans_data.c" -"common/ih264_trans_data.h" -"common/ih264_trans_macros.h" -"common/ih264_trans_quant_itrans_iquant.h" -"common/ih264_typedefs.h" -"common/ih264_weighted_pred.c" -"common/ih264_weighted_pred.h" -"common/ithread.c" -"common/ithread.h" -"decoder/ih264d.h" -"decoder/ih264d_api.c" -"decoder/ih264d_bitstrm.c" -"decoder/ih264d_bitstrm.h" -"decoder/ih264d_cabac.c" -"decoder/ih264d_cabac.h" -"decoder/ih264d_cabac_init_tables.c" -"decoder/ih264d_compute_bs.c" -"decoder/ih264d_deblocking.c" -"decoder/ih264d_deblocking.h" -"decoder/ih264d_debug.h" -"decoder/ih264d_defs.h" -"decoder/ih264d_dpb_manager.h" -"decoder/ih264d_dpb_mgr.c" -"decoder/ih264d_error_handler.h" -"decoder/ih264d_format_conv.c" -"decoder/ih264d_format_conv.h" -"decoder/ih264d_function_selector.h" -"decoder/ih264d_function_selector_generic.c" -"decoder/ih264d_inter_pred.c" -"decoder/ih264d_inter_pred.h" -"decoder/ih264d_mb_utils.c" -"decoder/ih264d_mb_utils.h" -"decoder/ih264d_mem_request.h" -"decoder/ih264d_mvpred.c" -"decoder/ih264d_mvpred.h" -"decoder/ih264d_nal.c" -"decoder/ih264d_nal.h" -"decoder/ih264d_parse_bslice.c" -"decoder/ih264d_parse_cabac.c" -"decoder/ih264d_parse_cabac.h" -"decoder/ih264d_parse_cavlc.c" -"decoder/ih264d_parse_cavlc.h" -"decoder/ih264d_parse_headers.c" -"decoder/ih264d_parse_headers.h" -"decoder/ih264d_parse_islice.c" -"decoder/ih264d_parse_islice.h" -"decoder/ih264d_parse_mb_header.c" -"decoder/ih264d_parse_mb_header.h" -"decoder/ih264d_parse_pslice.c" -"decoder/ih264d_parse_slice.c" -"decoder/ih264d_parse_slice.h" -"decoder/ih264d_process_bslice.c" -"decoder/ih264d_process_bslice.h" -"decoder/ih264d_process_intra_mb.c" -"decoder/ih264d_process_intra_mb.h" -"decoder/ih264d_process_pslice.c" -"decoder/ih264d_process_pslice.h" -"decoder/ih264d_quant_scaling.c" -"decoder/ih264d_quant_scaling.h" -"decoder/ih264d_sei.c" -"decoder/ih264d_sei.h" -"decoder/ih264d_structs.h" -"decoder/ih264d_tables.c" -"decoder/ih264d_tables.h" -"decoder/ih264d_thread_compute_bs.c" -"decoder/ih264d_thread_compute_bs.h" -"decoder/ih264d_thread_parse_decode.c" -"decoder/ih264d_thread_parse_decode.h" -"decoder/ih264d_transfer_address.h" -"decoder/ih264d_utils.c" -"decoder/ih264d_utils.h" -"decoder/ih264d_vui.c" -"decoder/ih264d_vui.h" -"decoder/iv.h" -"decoder/ivd.h" +add_library(ih264d STATIC + "common/ih264_buf_mgr.c" + "common/ih264_cabac_tables.c" + "common/ih264_cavlc_tables.c" + "common/ih264_chroma_intra_pred_filters.c" + "common/ih264_common_tables.c" + "common/ih264_deblk_edge_filters.c" + "common/ih264_deblk_tables.c" + "common/ih264_disp_mgr.c" + "common/ih264_dpb_mgr.c" + "common/ih264_ihadamard_scaling.c" + "common/ih264_inter_pred_filters.c" + "common/ih264_iquant_itrans_recon.c" + "common/ih264_list.c" + "common/ih264_luma_intra_pred_filters.c" + "common/ih264_mem_fns.c" + "common/ih264_padding.c" + "common/ih264_resi_trans_quant.c" + "common/ih264_trans_data.c" + "common/ih264_weighted_pred.c" + "common/ithread.c" + "decoder/ih264d_api.c" + "decoder/ih264d_bitstrm.c" + "decoder/ih264d_cabac.c" + "decoder/ih264d_cabac_init_tables.c" + "decoder/ih264d_compute_bs.c" + "decoder/ih264d_deblocking.c" + "decoder/ih264d_dpb_mgr.c" + "decoder/ih264d_format_conv.c" + "decoder/ih264d_function_selector_generic.c" + "decoder/ih264d_inter_pred.c" + "decoder/ih264d_mb_utils.c" + "decoder/ih264d_mvpred.c" + "decoder/ih264d_nal.c" + "decoder/ih264d_parse_bslice.c" + "decoder/ih264d_parse_cabac.c" + "decoder/ih264d_parse_cavlc.c" + "decoder/ih264d_parse_headers.c" + "decoder/ih264d_parse_islice.c" + "decoder/ih264d_parse_mb_header.c" + "decoder/ih264d_parse_pslice.c" + "decoder/ih264d_parse_slice.c" + "decoder/ih264d_process_bslice.c" + "decoder/ih264d_process_intra_mb.c" + "decoder/ih264d_process_pslice.c" + "decoder/ih264d_quant_scaling.c" + "decoder/ih264d_sei.c" + "decoder/ih264d_tables.c" + "decoder/ih264d_thread_compute_bs.c" + "decoder/ih264d_thread_parse_decode.c" + "decoder/ih264d_utils.c" + "decoder/ih264d_vui.c" ) -if (CMAKE_OSX_ARCHITECTURES) -set(IH264D_ARCHITECTURE ${CMAKE_OSX_ARCHITECTURES}) +if(CMAKE_OSX_ARCHITECTURES) + set(IH264D_ARCHITECTURE ${CMAKE_OSX_ARCHITECTURES}) else() -set(IH264D_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) + set(IH264D_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) endif() -if (IH264D_ARCHITECTURE STREQUAL "x86_64" OR IH264D_ARCHITECTURE STREQUAL "amd64" OR IH264D_ARCHITECTURE STREQUAL "AMD64") -set(LIBAVCDEC_X86_INCLUDES "common/x86" "decoder/x86") -include_directories("common/" "decoder/" ${LIBAVCDEC_X86_INCLUDES}) -target_sources(ih264d PRIVATE -"common/x86/ih264_chroma_intra_pred_filters_ssse3.c" -"common/x86/ih264_deblk_chroma_ssse3.c" -"common/x86/ih264_deblk_luma_ssse3.c" -"common/x86/ih264_ihadamard_scaling_sse42.c" -"common/x86/ih264_ihadamard_scaling_ssse3.c" -"common/x86/ih264_inter_pred_filters_ssse3.c" -"common/x86/ih264_iquant_itrans_recon_dc_ssse3.c" -"common/x86/ih264_iquant_itrans_recon_sse42.c" -"common/x86/ih264_iquant_itrans_recon_ssse3.c" -"common/x86/ih264_luma_intra_pred_filters_ssse3.c" -"common/x86/ih264_mem_fns_ssse3.c" -"common/x86/ih264_padding_ssse3.c" -"common/x86/ih264_platform_macros.h" -"common/x86/ih264_resi_trans_quant_sse42.c" -"common/x86/ih264_weighted_pred_sse42.c" -"decoder/x86/ih264d_function_selector.c" -"decoder/x86/ih264d_function_selector_sse42.c" -"decoder/x86/ih264d_function_selector_ssse3.c" -) -elseif(IH264D_ARCHITECTURE STREQUAL "aarch64" OR IH264D_ARCHITECTURE STREQUAL "arm64") -enable_language( C CXX ASM ) -set(LIBAVCDEC_ARM_INCLUDES "common/armv8" "decoder/arm") -include_directories("common/" "decoder/" ${LIBAVCDEC_ARM_INCLUDES}) -target_sources(ih264d PRIVATE -"common/armv8/ih264_deblk_chroma_av8.s" -"common/armv8/ih264_deblk_luma_av8.s" -"common/armv8/ih264_default_weighted_pred_av8.s" -"common/armv8/ih264_ihadamard_scaling_av8.s" -"common/armv8/ih264_inter_pred_chroma_av8.s" -"common/armv8/ih264_inter_pred_filters_luma_horz_av8.s" -"common/armv8/ih264_inter_pred_filters_luma_vert_av8.s" -"common/armv8/ih264_inter_pred_luma_copy_av8.s" -"common/armv8/ih264_inter_pred_luma_horz_hpel_vert_hpel_av8.s" -"common/armv8/ih264_inter_pred_luma_horz_hpel_vert_qpel_av8.s" -"common/armv8/ih264_inter_pred_luma_horz_qpel_av8.s" -"common/armv8/ih264_inter_pred_luma_horz_qpel_vert_hpel_av8.s" -"common/armv8/ih264_inter_pred_luma_horz_qpel_vert_qpel_av8.s" -"common/armv8/ih264_inter_pred_luma_vert_qpel_av8.s" -"common/armv8/ih264_intra_pred_chroma_av8.s" -"common/armv8/ih264_intra_pred_luma_16x16_av8.s" -"common/armv8/ih264_intra_pred_luma_4x4_av8.s" -"common/armv8/ih264_intra_pred_luma_8x8_av8.s" -"common/armv8/ih264_iquant_itrans_recon_av8.s" -"common/armv8/ih264_iquant_itrans_recon_dc_av8.s" -"common/armv8/ih264_mem_fns_neon_av8.s" -"common/armv8/ih264_neon_macros.s" -"common/armv8/ih264_padding_neon_av8.s" -"common/armv8/ih264_platform_macros.h" -"common/armv8/ih264_resi_trans_quant_av8.s" -"common/armv8/ih264_weighted_bi_pred_av8.s" -"common/armv8/ih264_weighted_pred_av8.s" -"decoder/arm/ih264d_function_selector_a9q.c" -"decoder/arm/ih264d_function_selector_av8.c" -"decoder/arm/ih264d_function_selector.c" -) -target_compile_options(ih264d PRIVATE -DARMV8 $<$:-Wno-unused-command-line-argument>) -if(NOT MSVC) - set(CMAKE_ASM_FLAGS "${CFLAGS} -x assembler-with-cpp") -endif() -if(APPLE) - target_sources(ih264d PRIVATE "common/armv8/macos_arm_symbol_aliases.s") -endif() +message(STATUS "DEBUG: ih264d detected architecture is: ${IH264D_ARCHITECTURE}") + +if(IH264D_ARCHITECTURE MATCHES "x86_64|amd64|AMD64|i386|i686") + set(LIBAVCDEC_X86_INCLUDES "common/x86" "decoder/x86") + include_directories("common/" "decoder/" ${LIBAVCDEC_X86_INCLUDES}) + target_sources(ih264d PRIVATE + "common/x86/ih264_chroma_intra_pred_filters_ssse3.c" + "common/x86/ih264_deblk_chroma_ssse3.c" + "common/x86/ih264_deblk_luma_ssse3.c" + "common/x86/ih264_ihadamard_scaling_sse42.c" + "common/x86/ih264_ihadamard_scaling_ssse3.c" + "common/x86/ih264_inter_pred_filters_ssse3.c" + "common/x86/ih264_iquant_itrans_recon_dc_ssse3.c" + "common/x86/ih264_iquant_itrans_recon_sse42.c" + "common/x86/ih264_iquant_itrans_recon_ssse3.c" + "common/x86/ih264_luma_intra_pred_filters_ssse3.c" + "common/x86/ih264_mem_fns_ssse3.c" + "common/x86/ih264_padding_ssse3.c" + "common/x86/ih264_resi_trans_quant_sse42.c" + "common/x86/ih264_weighted_pred_sse42.c" + "decoder/x86/ih264d_function_selector.c" + "decoder/x86/ih264d_function_selector_sse42.c" + "decoder/x86/ih264d_function_selector_ssse3.c" + ) + +elseif(IH264D_ARCHITECTURE MATCHES "aarch64|arm64|ARM64") + set(LIBAVCDEC_ARM_INCLUDES "common/armv8" "decoder/arm") + include_directories("common/" "decoder/" ${LIBAVCDEC_ARM_INCLUDES}) + + if(MSVC) + message(STATUS "MSVC ARM64 detected: Forcing portable C implementation.") + target_sources(ih264d PRIVATE + "decoder/arm/ih264d_function_selector.c" + "decoder/arm/ih264d_function_selector_av8.c" + ) + target_compile_definitions(ih264d PRIVATE PORTABLE_C ARCH_GENERIC DISABLE_NEON) + else() + enable_language(ASM) + message(STATUS "ARM64 Clang/GCC detected: Enabling assembly optimization.") + target_sources(ih264d PRIVATE + "common/armv8/ih264_deblk_chroma_av8.s" + "common/armv8/ih264_deblk_luma_av8.s" + "common/armv8/ih264_default_weighted_pred_av8.s" + "common/armv8/ih264_ihadamard_scaling_av8.s" + "common/armv8/ih264_inter_pred_chroma_av8.s" + "common/armv8/ih264_inter_pred_filters_luma_horz_av8.s" + "common/armv8/ih264_inter_pred_filters_luma_vert_av8.s" + "common/armv8/ih264_inter_pred_luma_copy_av8.s" + "common/armv8/ih264_inter_pred_luma_horz_hpel_vert_hpel_av8.s" + "common/armv8/ih264_inter_pred_luma_horz_hpel_vert_qpel_av8.s" + "common/armv8/ih264_inter_pred_luma_horz_qpel_av8.s" + "common/armv8/ih264_inter_pred_luma_horz_qpel_vert_hpel_av8.s" + "common/armv8/ih264_inter_pred_luma_horz_qpel_vert_qpel_av8.s" + "common/armv8/ih264_inter_pred_luma_vert_qpel_av8.s" + "common/armv8/ih264_intra_pred_chroma_av8.s" + "common/armv8/ih264_intra_pred_luma_16x16_av8.s" + "common/armv8/ih264_intra_pred_luma_4x4_av8.s" + "common/armv8/ih264_intra_pred_luma_8x8_av8.s" + "common/armv8/ih264_iquant_itrans_recon_av8.s" + "common/armv8/ih264_iquant_itrans_recon_dc_av8.s" + "common/armv8/ih264_mem_fns_neon_av8.s" + "common/armv8/ih264_padding_neon_av8.s" + "common/armv8/ih264_resi_trans_quant_av8.s" + "common/armv8/ih264_weighted_bi_pred_av8.s" + "common/armv8/ih264_weighted_pred_av8.s" + "decoder/arm/ih264d_function_selector_av8.c" + "decoder/arm/ih264d_function_selector.c" + ) + target_compile_definitions(ih264d PRIVATE ARMV8) + set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -x assembler-with-cpp") + endif() + + if(APPLE) + target_sources(ih264d PRIVATE "common/armv8/macos_arm_symbol_aliases.s") + endif() + else() -message(FATAL_ERROR "ih264d unknown architecture: ${IH264D_ARCHITECTURE}") + message(FATAL_ERROR "ih264d unknown architecture: ${IH264D_ARCHITECTURE}") endif() if(MSVC) -set_property(TARGET ih264d PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") - -# tune settings for slightly better performance -target_compile_options(ih264d PRIVATE $<$:/Oi>) # enable intrinsic functions -target_compile_options(ih264d PRIVATE $<$:/Ot>) # favor speed -target_compile_options(ih264d PRIVATE "/GS-") # disable runtime checks - + set_property(TARGET ih264d PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + target_compile_options(ih264d PRIVATE $<$:/Oi> $<$:/Ot> "/GS-") endif() diff --git a/dependencies/ih264d/CMakeSettings.json b/dependencies/ih264d/CMakeSettings.json index d2bcfced..709110af 100644 --- a/dependencies/ih264d/CMakeSettings.json +++ b/dependencies/ih264d/CMakeSettings.json @@ -21,6 +21,17 @@ "buildCommandArgs": "", "ctestCommandArgs": "", "inheritEnvironments": [ "msvc_x64_x64" ] + }, + { + "name": "arm64-Release", + "generator": "Ninja", + "configurationType": "Release", + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "inheritEnvironments": [ "msvc_arm64_x64" ] } ] -} \ No newline at end of file +} diff --git a/dependencies/ih264d/common/armv8/ih264_platform_macros.h b/dependencies/ih264d/common/armv8/ih264_platform_macros.h index a4d7f3a7..162ff97e 100644 --- a/dependencies/ih264d/common/armv8/ih264_platform_macros.h +++ b/dependencies/ih264d/common/armv8/ih264_platform_macros.h @@ -38,144 +38,95 @@ #include -#ifndef ARMV8 - -static __inline WORD32 CLIP_U8(WORD32 x) -{ - asm("usat %0, #8, %1" : "=r"(x) : "r"(x)); - return x; -} - -static __inline WORD32 CLIP_S8(WORD32 x) -{ - asm("ssat %0, #8, %1" : "=r"(x) : "r"(x)); - return x; -} - -static __inline WORD32 CLIP_U10(WORD32 x) -{ - asm("usat %0, #10, %1" : "=r"(x) : "r"(x)); - return x; -} - -static __inline WORD32 CLIP_S10(WORD32 x) -{ - asm("ssat %0, #10, %1" : "=r"(x) : "r"(x)); - return x; -} - -static __inline WORD32 CLIP_U11(WORD32 x) -{ - asm("usat %0, #11, %1" : "=r"(x) : "r"(x)); - return x; -} - -static __inline WORD32 CLIP_S11(WORD32 x) -{ - asm("ssat %0, #11, %1" : "=r"(x) : "r"(x)); - return x; -} - -static __inline WORD32 CLIP_U12(WORD32 x) -{ - asm("usat %0, #12, %1" : "=r"(x) : "r"(x)); - return x; -} - -static __inline WORD32 CLIP_S12(WORD32 x) -{ - asm("ssat %0, #12, %1" : "=r"(x) : "r"(x)); - return x; -} - -static __inline WORD32 CLIP_U16(WORD32 x) -{ - asm("usat %0, #16, %1" : "=r"(x) : "r"(x)); - return x; -} -static __inline WORD32 CLIP_S16(WORD32 x) -{ - asm("ssat %0, #16, %1" : "=r"(x) : "r"(x)); - return x; -} - - -static __inline UWORD32 ITT_BIG_ENDIAN(UWORD32 x) -{ - asm("rev %0, %1" : "=r"(x) : "r"(x)); - return x; -} -#define NOP(nop_cnt) {UWORD32 nop_i; for (nop_i = 0; nop_i < nop_cnt; nop_i++) asm("nop");} - -#else - -#define CLIP_U8(x) CLIP3(0, UINT8_MAX, (x)) -#define CLIP_S8(x) CLIP3(INT8_MIN, INT8_MAX, (x)) - -#define CLIP_U10(x) CLIP3(0, 1023, (x)) -#define CLIP_S10(x) CLIP3(-512, 511, (x)) - -#define CLIP_U11(x) CLIP3(0, 2047, (x)) -#define CLIP_S11(x) CLIP3(-1024, 1023, (x)) - -#define CLIP_U12(x) CLIP3(0, 4095, (x)) -#define CLIP_S12(x) CLIP3(-2048, 2047, (x)) - -#define CLIP_U16(x) CLIP3(0, UINT16_MAX, (x)) -#define CLIP_S16(x) CLIP3(INT16_MIN, INT16_MAX, (x)) - -#define ITT_BIG_ENDIAN(x) __asm__("rev %0, %1" : "=r"(x) : "r"(x)); - -#define NOP(nop_cnt) \ -{ \ - UWORD32 nop_i; \ - for (nop_i = 0; nop_i < nop_cnt; nop_i++) \ - __asm__ __volatile__("mov x0, x0"); \ -} - +#ifndef WORD32 +typedef int32_t WORD32; +#endif +#ifndef UWORD32 +typedef uint32_t UWORD32; #endif -/*saturating instructions are not available for WORD64 in ARMv7, hence we cannot - * use inline assembly like other clips*/ -#define CLIP_U32(x) CLIP3(0, UINT32_MAX, (x)) -#define CLIP_S32(x) CLIP3(INT32_MIN, INT32_MAX, (x)) +#include -#define DATA_SYNC() __sync_synchronize() +#ifdef _MSC_VER + #include + + #if defined(_M_ARM64) && !defined(__arm64_intrinsics_h__) + #ifndef _ARM64_BARRIER_ISH + #define _ARM64_BARRIER_ISH 0xB + #endif + #endif -#define SHL(x,y) (((y) < 32) ? ((x) << (y)) : 0) -#define SHR(x,y) (((y) < 32) ? ((x) >> (y)) : 0) + #define INLINE __inline + #define MEM_ALIGN8 __declspec(align(8)) + #define MEM_ALIGN16 __declspec(align(16)) + #define MEM_ALIGN32 __declspec(align(32)) + + #define DATA_SYNC() __dmb(_ARM64_BARRIER_ISH) + + #define NOP(nop_cnt) { for (int i = 0; i < (int)nop_cnt; i++) __nop(); } + + #define ITT_BIG_ENDIAN(x) _byteswap_ulong(x) +#else + #define INLINE inline + #define MEM_ALIGN8 __attribute__ ((aligned (8))) + #define MEM_ALIGN16 __attribute__ ((aligned (16))) + #define MEM_ALIGN32 __attribute__ ((aligned (32))) + + #define DATA_SYNC() __sync_synchronize() + + #define NOP(nop_cnt) \ + { \ + uint32_t nop_i; \ + for (nop_i = 0; nop_i < nop_cnt; nop_i++) \ + __asm__ __volatile__("mov x0, x0"); \ + } + + static INLINE uint32_t ITT_BIG_ENDIAN(uint32_t x) { + return __builtin_bswap32(x); + } +#endif + +#ifndef CLIP3 +#define CLIP3(min_val, max_val, x) (((x) < (min_val)) ? (min_val) : (((x) > (max_val)) ? (max_val) : (x))) +#endif + +#define CLIP_U8(x) CLIP3(0, 255, (x)) +#define CLIP_S8(x) CLIP3(-128, 127, (x)) +#define CLIP_U10(x) CLIP3(0, 1023, (x)) +#define CLIP_S10(x) CLIP3(-512, 511, (x)) +#define CLIP_U11(x) CLIP3(0, 2047, (x)) +#define CLIP_S11(x) CLIP3(-1024, 1023, (x)) +#define CLIP_U12(x) CLIP3(0, 4095, (x)) +#define CLIP_S12(x) CLIP3(-2048, 2047, (x)) +#define CLIP_U16(x) CLIP3(0, 65535, (x)) +#define CLIP_S16(x) CLIP3(-32768, 32767, (x)) +#define CLIP_U32(x) CLIP3(0, 0xFFFFFFFF, (x)) +#define CLIP_S32(x) CLIP3(-2147483647-1, 2147483647, (x)) + +static INLINE uint32_t CLZ(uint32_t u4_word) { + if (u4_word == 0) return 31; +#ifdef _MSC_VER + return (uint32_t)_CountLeadingZeros(u4_word); +#else + return (uint32_t)__builtin_clz(u4_word); +#endif +} + +static INLINE uint32_t CTZ(uint32_t u4_word) { + if (u4_word == 0) return 31; +#ifdef _MSC_VER + unsigned long index; + _BitScanForward(&index, u4_word); + return (uint32_t)index; +#else + return (uint32_t)__builtin_ctz(u4_word); +#endif +} + +#define SHL(x,y) (((y) < 32) ? ((uint32_t)(x) << (y)) : 0) +#define SHR(x,y) (((y) < 32) ? ((uint32_t)(x) >> (y)) : 0) #define SHR_NEG(val,shift) ((shift>0)?(val>>shift):(val<<(-shift))) #define SHL_NEG(val,shift) ((shift<0)?(val>>(-shift)):(val< + - + @@ -13,4 +13,4 @@ True/PM - \ No newline at end of file + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 977f48b7..0b905725 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -70,10 +70,16 @@ add_executable(CemuBin cemu_use_precompiled_header(CemuBin) -if(MSVC AND MSVC_VERSION EQUAL 1940) +if(MSVC) + set(CEMU_LINKER_FLAGS "/NODEFAULTLIB:MSVCRT") + + if(MSVC_VERSION EQUAL 1940) # workaround for an msvc issue on VS 17.10 where generated ILK files are too large # see https://developercommunity.visualstudio.com/t/After-updating-to-VS-1710-the-size-of-/10665511 - set_target_properties(CemuBin PROPERTIES LINK_FLAGS "/INCREMENTAL:NO") + string(APPEND CEMU_LINKER_FLAGS " /INCREMENTAL:NO") + endif() + + set_target_properties(CemuBin PROPERTIES LINK_FLAGS "${CEMU_LINKER_FLAGS}") endif() if(WIN32) diff --git a/src/Cafe/CMakeLists.txt b/src/Cafe/CMakeLists.txt index b509e722..71864ebf 100644 --- a/src/Cafe/CMakeLists.txt +++ b/src/Cafe/CMakeLists.txt @@ -83,13 +83,6 @@ add_library(CemuCafe HW/Espresso/Recompiler/PPCRecompilerImlGenFPU.cpp HW/Espresso/Recompiler/PPCRecompilerIml.h HW/Espresso/Recompiler/PPCRecompilerIntermediate.cpp - HW/Espresso/Recompiler/BackendX64/BackendX64AVX.cpp - HW/Espresso/Recompiler/BackendX64/BackendX64BMI.cpp - HW/Espresso/Recompiler/BackendX64/BackendX64.cpp - HW/Espresso/Recompiler/BackendX64/BackendX64FPU.cpp - HW/Espresso/Recompiler/BackendX64/BackendX64Gen.cpp - HW/Espresso/Recompiler/BackendX64/BackendX64GenFPU.cpp - HW/Espresso/Recompiler/BackendX64/BackendX64.h HW/Espresso/Recompiler/BackendX64/X64Emit.hpp HW/Espresso/Recompiler/BackendX64/x86Emitter.h HW/Latte/Common/RegisterSerializer.cpp @@ -618,12 +611,23 @@ if(ENABLE_METAL) ) endif() -if(CEMU_ARCHITECTURE MATCHES "(aarch64)|(AARCH64)|(arm64)|(ARM64)") - target_sources(CemuCafe PRIVATE - HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.cpp - HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.h - ) - target_link_libraries(CemuCafe PRIVATE xbyak_aarch64) +if(CEMU_ARCHITECTURE MATCHES "(x86_64|amd64|AMD64)") + target_sources(CemuCafe PRIVATE + HW/Espresso/Recompiler/BackendX64/BackendX64.cpp + HW/Espresso/Recompiler/BackendX64/BackendX64.h + HW/Espresso/Recompiler/BackendX64/BackendX64AVX.cpp + HW/Espresso/Recompiler/BackendX64/BackendX64BMI.cpp + HW/Espresso/Recompiler/BackendX64/BackendX64FPU.cpp + HW/Espresso/Recompiler/BackendX64/BackendX64Gen.cpp + HW/Espresso/Recompiler/BackendX64/BackendX64GenFPU.cpp + ) +else() + target_sources(CemuCafe PRIVATE + HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.cpp + HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.h + ) + target_link_libraries(CemuCafe PRIVATE xbyak_aarch64) + target_compile_definitions(ih264d PRIVATE ARCH_GENERIC DISABLE_NEON) endif() set_property(TARGET CemuCafe PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") @@ -646,7 +650,7 @@ else() endif() target_link_libraries(CemuCafe PRIVATE - CemuCommon + CemuCommon CemuGui ZArchive::zarchive imguiImpl @@ -668,7 +672,7 @@ endif() if (ENABLE_LIBUSB) if (ENABLE_VCPKG) if(WIN32) - set(PKG_CONFIG_EXECUTABLE "${VCPKG_INSTALLED_DIR}/x64-windows/tools/pkgconf/pkgconf.exe") + set(PKG_CONFIG_EXECUTABLE "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/tools/pkgconf/pkgconf.exe") endif() find_package(PkgConfig REQUIRED) pkg_check_modules(libusb REQUIRED IMPORTED_TARGET libusb-1.0) diff --git a/src/Cafe/HW/Espresso/Debugger/Debugger.cpp b/src/Cafe/HW/Espresso/Debugger/Debugger.cpp index 3670cc1e..3ff85f40 100644 --- a/src/Cafe/HW/Espresso/Debugger/Debugger.cpp +++ b/src/Cafe/HW/Espresso/Debugger/Debugger.cpp @@ -199,7 +199,7 @@ void debugger_updateMemoryBreakpoint(DebuggerBreakpoint* bp) { std::vector schedulerThreadHandles = coreinit::OSGetSchedulerThreads(); -#if BOOST_OS_WINDOWS +#if BOOST_OS_WINDOWS && defined(_M_X64) s_debuggerState.activeMemoryBreakpoint = bp; for (auto& hThreadNH : schedulerThreadHandles) { @@ -235,9 +235,51 @@ void debugger_updateMemoryBreakpoint(DebuggerBreakpoint* bp) SetThreadContext(hThread, &ctx); ResumeThread(hThread); } - #else +#elif defined(_M_X64) + s_debuggerState.activeMemoryBreakpoint = bp; + for (auto& hThreadNH : schedulerThreadHandles) + { + HANDLE hThread = (HANDLE)hThreadNH; + CONTEXT ctx{}; + ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; + + SuspendThread(hThread); + if (GetThreadContext(hThread, &ctx)) + { + if (s_debuggerState.activeMemoryBreakpoint) + { + // ARM64 uses Bvr/Bcr pairs. We'll use slot 0. + ctx.Bvr[0] = (DWORD64)memory_getPointerFromVirtualOffset(bp->address); + + // Construct the Control Register (BCR) + DWORD64 bcr = 0; + bcr |= 0x1; // Bit 0: Global Enable + bcr |= (0x3 << 1); // Bits 1-2: User and Privileged access + bcr |= (0xF << 5); // Bits 5-8: Byte address select (watch all 4 bytes) + + // Map Cemu BP types to ARM64 Watchpoint types + if (bp->bpType == DEBUGGER_BP_T_MEMORY_READ) + bcr |= (0x1 << 21); // Bit 21-22: 1 = Load + else if (bp->bpType == DEBUGGER_BP_T_MEMORY_WRITE) + bcr |= (0x2 << 21); // Bit 21-22: 2 = Store + else + bcr |= (0x3 << 21); // Bit 21-22: 3 = Either + + ctx.Bcr[0] = bcr; + } + else + { + // Disable breakpoint slot 0 + ctx.Bvr[0] = 0; + ctx.Bcr[0] = 0; + } + SetThreadContext(hThread, &ctx); + } + ResumeThread(hThread); + } +#else cemuLog_log(LogType::Force, "Debugger breakpoints are not supported"); - #endif +#endif } void debugger_handleSingleStepException(uint64 dr6) diff --git a/src/Cafe/HW/Espresso/Recompiler/IML/IMLInstruction.h b/src/Cafe/HW/Espresso/Recompiler/IML/IMLInstruction.h index 4df2a666..873732db 100644 --- a/src/Cafe/HW/Espresso/Recompiler/IML/IMLInstruction.h +++ b/src/Cafe/HW/Espresso/Recompiler/IML/IMLInstruction.h @@ -823,4 +823,4 @@ namespace IMLArchX86 { static constexpr int PHYSREG_GPR_BASE = 0; static constexpr int PHYSREG_FPR_BASE = 16; -}; \ No newline at end of file +}; diff --git a/src/Cafe/HW/Latte/Core/LatteTextureCache.cpp b/src/Cafe/HW/Latte/Core/LatteTextureCache.cpp index 3145e90e..bd6f7277 100644 --- a/src/Cafe/HW/Latte/Core/LatteTextureCache.cpp +++ b/src/Cafe/HW/Latte/Core/LatteTextureCache.cpp @@ -146,7 +146,7 @@ uint32 LatteTexture_CalculateTextureDataHash(LatteTexture* hostTexture) bool isCompressedFormat = hostTexture->IsCompressedFormat(); if( isCompressedFormat == false ) { -#if BOOST_OS_WINDOWS +#if BOOST_OS_WINDOWS && defined(_M_X64) if (g_CPUFeatures.x86.avx2) { __m256i h256 = { 0 }; @@ -430,4 +430,4 @@ void LatteTC_UnloadAllTextures() LatteTexture_Delete(itr); } LatteRenderTarget_unloadAll(); -} \ No newline at end of file +} diff --git a/src/Cafe/HW/Latte/Core/LatteTextureLoader.cpp b/src/Cafe/HW/Latte/Core/LatteTextureLoader.cpp index 589b3bd0..caeca487 100644 --- a/src/Cafe/HW/Latte/Core/LatteTextureLoader.cpp +++ b/src/Cafe/HW/Latte/Core/LatteTextureLoader.cpp @@ -1,3 +1,4 @@ +#include "Cafe/OS/common/OSCommon.h" #include "Cafe/HW/Latte/Renderer/Renderer.h" #include "Cafe/HW/Latte/LatteAddrLib/LatteAddrLib.h" #include "config/ActiveSettings.h" @@ -707,7 +708,7 @@ void optimizedLinearReadbackWriteLoop(LatteTextureLoaderCtx* textureLoader, uint copyType* blockData = (copyType*)LatteTextureLoader_getInputLinearOptimized_(textureLoader, 0, y, 1, 1, sizeof(copyType) * 8, 0, 1, 0, textureLoader->pitch, textureLoader->height); if constexpr (sizeof(copyType) == 4) { - memcpy_dwords(blockData, rowPixelData, textureLoader->width); + SAFE_MOVSD(blockData, rowPixelData, textureLoader->width); } else { diff --git a/src/Cafe/OS/common/OSCommon.h b/src/Cafe/OS/common/OSCommon.h index d35ff893..efee7191 100644 --- a/src/Cafe/OS/common/OSCommon.h +++ b/src/Cafe/OS/common/OSCommon.h @@ -113,4 +113,41 @@ static void* _ppc_va_arg(ppc_va_list* vargs, ppc_va_type argType) vargs->overflow_arg_area += 8; return r; } -} \ No newline at end of file +} + +#ifdef _WIN32 + #include +#else + #include + #if defined(__x86_64__) || defined(__i386__) + #include + #endif +#endif + +#ifdef _WIN32 + static inline void safe_memcpy_dwords(void* dest, const void* src, size_t count) { + #if defined(_M_ARM64) || defined(_M_ARM) + memcpy(dest, src, count * 4); + #else + __movsd((unsigned long*)dest, (const unsigned long*)src, (unsigned long)count); + #endif + } + static inline void safe_memcpy_qwords(void* dest, const void* src, size_t count) { + #if defined(_M_ARM64) || defined(_M_ARM) + memcpy(dest, src, count * 8); + #else + __movsq((unsigned __int64*)dest, (const unsigned __int64*)src, count); + #endif + } + #define SAFE_MOVSD(d, s, c) safe_memcpy_dwords((d), (s), (c)) + #define SAFE_MOVSQ(d, s, c) safe_memcpy_qwords((d), (s), (c)) +#else + static inline void safe_memcpy_dwords(void* dest, const void* src, size_t count) { + memcpy(dest, src, count * 4); + } + static inline void safe_memcpy_qwords(void* dest, const void* src, size_t count) { + memcpy(dest, src, count * 8); + } + #define SAFE_MOVSD(d, s, c) safe_memcpy_dwords((d), (s), (c)) + #define SAFE_MOVSQ(d, s, c) safe_memcpy_qwords((d), (s), (c)) +#endif diff --git a/src/Cafe/OS/libs/coreinit/coreinit_LockedCache.cpp b/src/Cafe/OS/libs/coreinit/coreinit_LockedCache.cpp index a051fce1..4298677d 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_LockedCache.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_LockedCache.cpp @@ -256,7 +256,7 @@ namespace coreinit uint8* destPtr = memory_getPointerFromVirtualOffset(hCPU->gpr[3]); uint8* srcPtr = memory_getPointerFromVirtualOffset(hCPU->gpr[4]); // copy right away, we don't emulate the DMAQueue currently - memcpy_qwords(destPtr, srcPtr, numBlocks * (32 / sizeof(uint64))); + SAFE_MOVSQ(destPtr, srcPtr, (size_t)numBlocks * 4); LatteBufferCache_notifyDCFlush(hCPU->gpr[3], numBlocks * 32); diff --git a/src/Cafe/OS/libs/gx2/GX2_Command.cpp b/src/Cafe/OS/libs/gx2/GX2_Command.cpp index d12bf210..5e05b50f 100644 --- a/src/Cafe/OS/libs/gx2/GX2_Command.cpp +++ b/src/Cafe/OS/libs/gx2/GX2_Command.cpp @@ -42,7 +42,7 @@ void gx2WriteGather_submitU32AsLEArray(uint32* v, uint32 numValues) uint32 coreIndex = PPCInterpreter_getCoreIndex(PPCInterpreter_getCurrentInstance()); if (GX2::s_perCoreCBState[coreIndex].currentWritePtr == nullptr) return; - memcpy_dwords(GX2::s_perCoreCBState[coreIndex].currentWritePtr, v, numValues); + SAFE_MOVSD(GX2::s_perCoreCBState[coreIndex].currentWritePtr, v, numValues); GX2::s_perCoreCBState[coreIndex].currentWritePtr += numValues; cemu_assert_debug(GX2::s_perCoreCBState[coreIndex].currentWritePtr <= (GX2::s_perCoreCBState[coreIndex].bufferPtr + GX2::s_perCoreCBState[coreIndex].bufferSizeInU32s)); } diff --git a/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp b/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp index 6b205d26..3bd715f6 100644 --- a/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp +++ b/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp @@ -209,6 +209,20 @@ void createCrashlog(EXCEPTION_POINTERS* e, PCONTEXT context) // register info sprintf(dumpLine, "\n"); cemuLog_writePlainToLog(dumpLine); +#if defined(_M_ARM64) + // ARM64 Register Dump + sprintf(dumpLine, "X0 =%016I64x X1 =%016I64x X2 =%016I64x X3 =%016I64x\n", context->X0, context->X1, context->X2, context->X3); + cemuLog_writePlainToLog(dumpLine); + sprintf(dumpLine, "X4 =%016I64x X5 =%016I64x X6 =%016I64x X7 =%016I64x\n", context->X4, context->X5, context->X6, context->X7); + cemuLog_writePlainToLog(dumpLine); + sprintf(dumpLine, "X8 =%016I64x X9 =%016I64x X10=%016I64x X11=%016I64x\n", context->X8, context->X9, context->X10, context->X11); + cemuLog_writePlainToLog(dumpLine); + sprintf(dumpLine, "X12=%016I64x X13=%016I64x X14=%016I64x X15=%016I64x\n", context->X12, context->X13, context->X14, context->X15); + cemuLog_writePlainToLog(dumpLine); + sprintf(dumpLine, "SP =%016I64x PC =%016I64x\n", context->Sp, context->Pc); + cemuLog_writePlainToLog(dumpLine); +#else + // x86_64 Register Dump sprintf(dumpLine, "RAX=%016I64x RBX=%016I64x RCX=%016I64x RDX=%016I64x\n", context->Rax, context->Rbx, context->Rcx, context->Rdx); cemuLog_writePlainToLog(dumpLine); sprintf(dumpLine, "RSP=%016I64x RBP=%016I64x RDI=%016I64x RSI=%016I64x\n", context->Rsp, context->Rbp, context->Rdi, context->Rsi); @@ -217,6 +231,7 @@ void createCrashlog(EXCEPTION_POINTERS* e, PCONTEXT context) cemuLog_writePlainToLog(dumpLine); sprintf(dumpLine, "R12=%016I64x R13=%016I64x R14=%016I64x R15=%016I64x\n", context->R12, context->R13, context->R14, context->R15); cemuLog_writePlainToLog(dumpLine); +#endif CrashLog_SetOutputChannels(false, true); ExceptionHandler_LogGeneralInfo(); @@ -264,10 +279,13 @@ LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo) if (r != EXCEPTION_CONTINUE_SEARCH) return r; +#if !defined(_M_ARM64) + // Hardware breakpoints (Dr6) are x86-specific in the Windows CONTEXT struct if (GetBits(pExceptionInfo->ContextRecord->Dr6, 0, 1) || GetBits(pExceptionInfo->ContextRecord->Dr6, 1, 1)) debugger_handleSingleStepException(pExceptionInfo->ContextRecord->Dr6); else if (GetBits(pExceptionInfo->ContextRecord->Dr6, 2, 1) || GetBits(pExceptionInfo->ContextRecord->Dr6, 3, 1)) g_gdbstub->HandleAccessException(pExceptionInfo->ContextRecord->Dr6); +#endif return EXCEPTION_CONTINUE_EXECUTION; } return EXCEPTION_CONTINUE_SEARCH; diff --git a/src/Common/precompiled.h b/src/Common/precompiled.h index e0373952..140e4a5a 100644 --- a/src/Common/precompiled.h +++ b/src/Common/precompiled.h @@ -179,6 +179,12 @@ inline sint16 _swapEndianS16(sint16 v) { return (sint16)(((uint16)v >> 8) | ((uint16)v << 8)); } +#if defined(_M_ARM64) +inline uint64 _umul128(uint64 multiplier, uint64 multiplicand, uint64 *highProduct) { + *highProduct = __umulh(multiplier, multiplicand); + return multiplier * multiplicand; +} +#endif #else inline uint64 _swapEndianU64(uint64 v) { @@ -290,6 +296,18 @@ inline uint64 _udiv128(uint64 highDividend, uint64 lowDividend, uint64 divisor, *remainder = (uint64)((dividend % divisor) & 0xFFFFFFFFFFFFFFFF); return (uint64)((dividend / divisor) & 0xFFFFFFFFFFFFFFFF); } +#elif defined(_M_ARM64) +inline uint64 _udiv128(uint64 highDividend, uint64 lowDividend, uint64 divisor, uint64 *remainder) +{ + uint64 high = highDividend; + uint64 low = lowDividend; + if (high >= divisor) { + high %= divisor; + } + unsigned __int128 dividend = (((unsigned __int128)highDividend) << 64) | lowDividend; + *remainder = (uint64)(dividend % divisor); + return (uint64)(dividend / divisor); +} #endif #if defined(_MSC_VER) @@ -341,48 +359,65 @@ inline uint64 _udiv128(uint64 highDividend, uint64 lowDividend, uint64 divisor, #define FORCE_INLINE inline #endif -FORCE_INLINE int BSF(uint32 v) // returns index of first bit set, counting from LSB. If v is 0 then result is undefined +FORCE_INLINE int BSF(uint32 v) // returns index of first bit set, counting from LSB. If v is 0 then result is 32 { #if defined(_MSC_VER) - return _tzcnt_u32(v); // TZCNT requires BMI1. But if not supported it will execute as BSF + #if defined(_M_ARM64) || defined(_M_ARM) + unsigned long index; + if (_BitScanForward(&index, (unsigned long)v)) + return (int)index; + return 32; + #else + // This is the x86/x64 specific intrinsic that was causing ARM64 build failures + return (v == 0) ? 32 : (int)_tzcnt_u32(v); + #endif #elif defined(__GNUC__) || defined(__clang__) - return __builtin_ctz(v); + return v == 0 ? 32 : __builtin_ctz(v); #else - return std::countr_zero(v); + return (int)std::countr_zero(v); #endif } -// On aarch64 we handle some of the x86 intrinsics by implementing them as wrappers -#if defined(__aarch64__) +#if defined(__aarch64__) || defined(_M_ARM64) inline void _mm_pause() { +#if defined(_MSC_VER) + __yield(); +#else asm volatile("yield"); +#endif } inline uint64 __rdtsc() { +#if defined(_MSC_VER) + return (uint64)_ReadStatusReg(ARM64_CNTVCT_EL0); +#else uint64 t; asm volatile("mrs %0, cntvct_el0" : "=r" (t)); return t; +#endif } inline void _mm_mfence() { - asm volatile("" ::: "memory"); - std::atomic_thread_fence(std::memory_order_seq_cst); + std::atomic_thread_fence(std::memory_order_seq_cst); } inline unsigned char _addcarry_u64(unsigned char carry, unsigned long long a, unsigned long long b, unsigned long long *result) { - *result = a + b + (unsigned long long)carry; - if (*result < a) - return 1; - return 0; +#if !defined(_MSC_VER) + unsigned __int128 res = (unsigned __int128)a + b + carry; + *result = (unsigned long long)res; + return (res >> 64) ? 1 : 0; +#else + *result = a + b + carry; + return (*result < a || (*result == a && carry > 0)) ? 1 : 0; +#endif } #endif - // asserts diff --git a/src/gui/wxgui/CMakeLists.txt b/src/gui/wxgui/CMakeLists.txt index 079a78cd..875937b0 100644 --- a/src/gui/wxgui/CMakeLists.txt +++ b/src/gui/wxgui/CMakeLists.txt @@ -191,6 +191,7 @@ endif() if(WIN32) target_link_libraries(CemuWxGui PRIVATE bthprops) + target_compile_options(CemuWxGui PRIVATE /wd4312) endif() if(ALLOW_PORTABLE) diff --git a/src/resource/cemu.rc b/src/resource/cemu.rc index e6332032..3ea4b7cf 100644 --- a/src/resource/cemu.rc +++ b/src/resource/cemu.rc @@ -13,10 +13,10 @@ #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// -// Neutral (Default) (unknown sub-lang: 0x8) resources +// Neutral (Default) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ZZZ) -LANGUAGE LANG_NEUTRAL, 0x8 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL ///////////////////////////////////////////////////////////////////////////// // @@ -64,7 +64,6 @@ END #endif // APSTUDIO_INVOKED - ///////////////////////////////////////////////////////////////////////////// // // Version @@ -73,16 +72,25 @@ END #define xstr(s) str(s) #define str(s) #s +#if defined(_M_ARM64) + #define ARCH_DESC " (ARM64)" +#elif defined(_M_X64) || defined(_M_AMD64) + #define ARCH_DESC " (x64)" +#else + #define ARCH_DESC "" +#endif + VS_VERSION_INFO VERSIONINFO -FILEVERSION EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_MINOR, EMULATOR_VERSION_PATCH, 0 -PRODUCTVERSION EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_MINOR, EMULATOR_VERSION_PATCH, 0 + FILEVERSION EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_MINOR, EMULATOR_VERSION_PATCH, 0 + PRODUCTVERSION EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_MINOR, EMULATOR_VERSION_PATCH, 0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif - FILEOS 0x0L + // VOS_NT_WINDOWS32 is used for both x64 and ARM64 NT-based systems + FILEOS 0x40004L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN @@ -90,12 +98,12 @@ BEGIN BEGIN BLOCK "040904b0" BEGIN - VALUE "FileDescription", "Cemu Wii U emulator" + VALUE "FileDescription", "Cemu Wii U emulator" ARCH_DESC VALUE "InternalName", "Cemu" VALUE "LegalCopyright", "Team Cemu" VALUE "OriginalFilename", "Cemu.exe" VALUE "ProductName", "Cemu" - VALUE "ProductVersion", xstr(EMULATOR_VERSION_MAJOR) "." xstr(EMULATOR_VERSION_MINOR) "." xstr(EMULATOR_VERSION_PATCH) EMULATOR_VERSION_SUFFIX "\0" + VALUE "ProductVersion", xstr(EMULATOR_VERSION_MAJOR) "." xstr(EMULATOR_VERSION_MINOR) "." xstr(EMULATOR_VERSION_PATCH) EMULATOR_VERSION_SUFFIX "\0" END END BLOCK "VarFileInfo" @@ -104,7 +112,6 @@ BEGIN END END - ///////////////////////////////////////////////////////////////////////////// // // RCDATA @@ -112,10 +119,7 @@ END IDR_FONTAWESOME RCDATA "resource\\fontawesome-webfont.ttf" -#endif // Neutral (Default) (unknown sub-lang: 0x8) resources -///////////////////////////////////////////////////////////////////////////// - - +#endif // Neutral resources #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// @@ -126,4 +130,3 @@ IDR_FONTAWESOME RCDATA "resource\\fontawesome-webfont.t ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED - diff --git a/src/resource/installer.nsi b/src/resource/installer.nsi index 9d35c738..c6bad352 100644 --- a/src/resource/installer.nsi +++ b/src/resource/installer.nsi @@ -4,10 +4,17 @@ ; Usage: ; get the latest nsis: https://nsis.sourceforge.io/Download ; probably also want vscode extension: https://marketplace.visualstudio.com/items?itemName=idleberg.nsis +; makensis.exe /DPRODUCT_VERSION=2.0 /DARCH=arm64 installer.nsi +; makensis.exe /DPRODUCT_VERSION=2.0 /DARCH=x64 installer.nsi ; Require /DPRODUCT_VERSION for makensis. !ifndef PRODUCT_VERSION - !error "PRODUCT_VERSION must be defined" + !error "PRODUCT_VERSION must be defined (e.g. /DPRODUCT_VERSION=2.0)" +!endif + +; Default to x64 if ARCH is not defined +!ifndef ARCH + !define ARCH "x64" !endif ManifestDPIAware true @@ -19,9 +26,9 @@ ManifestDPIAware true !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" !define BINARY_SOURCE_DIR "..\..\bin" +OutFile "cemu-${PRODUCT_VERSION}-windows-${ARCH}-installer.exe" -Name "${PRODUCT_NAME}" -OutFile "cemu-${PRODUCT_VERSION}-windows-x64-installer.exe" +Name "${PRODUCT_NAME} (${ARCH})" SetCompressor /SOLID lzma InstallDir "$LOCALAPPDATA\Cemu" ShowInstDetails show @@ -30,6 +37,7 @@ ShowUnInstDetails show !include "MUI2.nsh" ; Custom page plugin !include "nsDialogs.nsh" +!include "x64.nsh" ; MUI Settings !define MUI_ICON "logo_icon.ico" @@ -81,8 +89,19 @@ Var DesktopShortcut ; MUI end ------ Function .onInit - StrCpy $DesktopShortcut 1 + ; Block installation if trying to install x64 on ARM without emulation, + ; or ensure the user is aware. + ${If} "${ARCH}" == "arm64" + ${Unless} ${IsNativeARM64} + MessageBox MB_OK|MB_ICONEXCLAMATION "This installer is for ARM64 systems. Your CPU does not appear to support it natively." + ${EndUnless} + ${Else} + ${If} ${IsNativeARM64} + DetailPrint "Running x64 installer on ARM64 system via Prism/Emulation." + ${EndIf} + ${EndIf} + StrCpy $DesktopShortcut 1 !insertmacro MUI_LANGDLL_DISPLAY FunctionEnd @@ -97,7 +116,6 @@ Function desktopShortcutPageCreate ${NSD_CreateCheckbox} 0u 0u 100% 12u "Create a desktop shortcut" Pop $DesktopShortcutCheckbox ${NSD_SetState} $DesktopShortcutCheckbox $DesktopShortcut - nsDialogs::Show FunctionEnd @@ -106,13 +124,14 @@ Function desktopShortcutPageLeave FunctionEnd Section "Base" + ; Prevent running the uninstaller of a different arch in the same folder + ; without cleaning up first ExecWait '"$INSTDIR\uninst.exe" /S _?=$INSTDIR' SectionIn RO - SetOutPath "$INSTDIR" - ; The binplaced build output will be included verbatim. + ; This will pull files from the directory defined at the top File /r "${BINARY_SOURCE_DIR}\*" ; Create start menu and desktop shortcuts @@ -136,10 +155,12 @@ Section -Post WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}" WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}" WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "InstallLocation" "$INSTDIR" + ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 IntFmt $0 "0x%08X" $0 WriteRegDWORD HKCU "${PRODUCT_UNINST_KEY}" "EstimatedSize" "$0" + ; File Associations WriteRegStr HKCU "Software\Classes\.wud" "" "$(^Name)" WriteRegStr HKCU "Software\Classes\.wux" "" "$(^Name)" WriteRegStr HKCU "Software\Classes\.wua" "" "$(^Name)" @@ -151,7 +172,7 @@ Section Uninstall Delete "$DESKTOP\$(^Name).lnk" Delete "$SMPROGRAMS\$(^Name).lnk" -; Be a bit careful to not delete files a user may have put into the install directory +; Be a bit careful to not delete files a user may have put into the install directory Delete "$INSTDIR\Cemu.exe" Delete "$INSTDIR\uninst.exe" RMDir /r "$INSTDIR\gameProfiles" @@ -162,9 +183,9 @@ Section Uninstall DeleteRegKey HKCU "Software\Classes\.wux" DeleteRegKey HKCU "Software\Classes\.wua" DeleteRegKey HKCU "Software\Classes\$(^Name)" - + DeleteRegKey HKCU "Software\Classes\discord-460807638964371468" - + DeleteRegKey HKCU "${PRODUCT_UNINST_KEY}" DeleteRegKey HKCU "${PRODUCT_DIR_REGKEY}" diff --git a/vcpkg.json b/vcpkg.json index 3687d2b3..4b455be2 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -67,7 +67,8 @@ "zip" ] }, - "libusb" + "libusb", + "pkgconf" ], "overrides": [ {