cmake_minimum_required(VERSION 3.19...4.3) if(CMAKE_VERSION VERSION_GREATER_EQUAL 4.0) set(CMAKE_POLICY_VERSION_MINIMUM 3.10 CACHE STRING "Minimum policy version for bundled dependencies") endif() get_property(KYTY_GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(NOT KYTY_GENERATOR_IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build" FORCE) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release RelWithDebInfo MinSizeRel) endif() project(Kyty) find_program(SCCACHE_PROGRAM sccache) find_program(CCACHE_PROGRAM ccache) foreach(lang IN ITEMS C CXX) # An explicitly empty launcher disables caching for this language. if(NOT DEFINED CMAKE_${lang}_COMPILER_LAUNCHER) if(SCCACHE_PROGRAM) set(CMAKE_${lang}_COMPILER_LAUNCHER "${SCCACHE_PROGRAM}") message(STATUS "sccache enabled for ${lang}: ${SCCACHE_PROGRAM}") elseif(CCACHE_PROGRAM) set(CMAKE_${lang}_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") message(STATUS "ccache enabled for ${lang}: ${CCACHE_PROGRAM}") endif() endif() endforeach() set(KYTY_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src") set(KYTY_TESTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests") set(KYTY_THIRD_PARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty") if(CMAKE_SYSTEM_NAME MATCHES ".*Linux") set(LINUX TRUE) endif() if (NOT (WIN32 OR LINUX OR APPLE)) message(FATAL_ERROR "only Windows, Linux, and macOS builds are supported") endif() if(WIN32) # Prevent Windows headers from defining min/max macros in all targets. add_compile_definitions(NOMINMAX) endif() set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_SCAN_FOR_MODULES OFF) include("${KYTY_SOURCE_DIR}/utils.cmake") include(CTest) option(KYTY_ENABLE_CLANG_TIDY "Run clang-tidy checks during builds" OFF) set(KYTY_BUILD_ORIGIN "Source" CACHE STRING "Build provenance shown in diagnostics") set_property(CACHE KYTY_BUILD_ORIGIN PROPERTY STRINGS Source Official Fork) if(NOT KYTY_BUILD_ORIGIN STREQUAL "Source" AND NOT KYTY_BUILD_ORIGIN STREQUAL "Official" AND NOT KYTY_BUILD_ORIGIN STREQUAL "Fork") message(FATAL_ERROR "KYTY_BUILD_ORIGIN must be Source, Official, or Fork") endif() set(KYTY_RELEASE_TAG "" CACHE STRING "Release tag embedded in official builds") set(KYTY_BUILD_REPOSITORY "" CACHE STRING "GitHub repository embedded in fork builds") set(KYTY_OFFICIAL_BUILD OFF) set(KYTY_FORK_BUILD OFF) if(KYTY_BUILD_ORIGIN STREQUAL "Official") if(KYTY_RELEASE_TAG STREQUAL "") message(FATAL_ERROR "Official builds require KYTY_RELEASE_TAG") endif() set(KYTY_OFFICIAL_BUILD ON) elseif(KYTY_BUILD_ORIGIN STREQUAL "Fork") if(KYTY_BUILD_REPOSITORY STREQUAL "") message(FATAL_ERROR "Fork builds require KYTY_BUILD_REPOSITORY") endif() set(KYTY_FORK_BUILD ON) endif() set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) include(TestBigEndian) if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8) message(FATAL_ERROR "only 64-bit builds are supported") endif() test_big_endian(BIG_ENDIAN) if(BIG_ENDIAN) set(KYTY_ENDIAN KYTY_ENDIAN_BIG) else() set(KYTY_ENDIAN KYTY_ENDIAN_LITTLE) endif() if(CMAKE_BUILD_TYPE MATCHES Debug) set(KYTY_BUILD KYTY_BUILD_DEBUG) else() set(KYTY_BUILD KYTY_BUILD_RELEASE) endif() if(LINUX OR APPLE) # macOS rides the POSIX/Linux code paths until it gets a dedicated platform set(KYTY_PLATFORM KYTY_PLATFORM_LINUX) else() set(KYTY_PLATFORM KYTY_PLATFORM_WINDOWS) endif() set(CLANG FALSE) set(GCC FALSE) set(KYTY_CLANG_CL FALSE) get_filename_component(KYTY_CXX_COMPILER_NAME "${CMAKE_CXX_COMPILER}" NAME_WE) string(TOLOWER "${KYTY_CXX_COMPILER_NAME}" KYTY_CXX_COMPILER_NAME) if(CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$") set(CLANG TRUE) set(KYTY_COMPILER CLANG) if(WIN32 AND KYTY_CXX_COMPILER_NAME STREQUAL "clang-cl") set(KYTY_CLANG_CL TRUE) set(KYTY_LINKER LLD_LINK) elseif(APPLE) set(KYTY_LINKER LD64) # Apple's default linker; lld flags don't apply else() set(KYTY_LINKER LLD) endif() if ((CMAKE_AR MATCHES "llvm") AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.0.0) AND (CMAKE_CXX_COMPILER MATCHES "winlibs")) string(REPLACE "llvm-ar.exe" "ar.exe" CMAKE_AR ${CMAKE_AR}) # llvm-ar.exe 11.0.0 from winlibs is broken endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(GCC TRUE) set(KYTY_COMPILER GCC) set(KYTY_LINKER LD) else() message(FATAL_ERROR "only Clang and GCC are supported; found ${CMAKE_CXX_COMPILER_ID}") endif() set(KYTY_PROJECT_NAME "Emulator" CACHE STRING "Project name suffix") string(TOLOWER ${KYTY_COMPILER} KYTY_COMPILER_ID) string(TOLOWER ${KYTY_LINKER} KYTY_LINKER_ID) if (CLANG AND (KYTY_LINKER STREQUAL LLD)) set(KYTY_LD_OPTIONS "-fuse-ld=lld") endif() if (KYTY_LINKER STREQUAL LD AND NOT LINUX) set(KYTY_LD_OPTIONS "-Wl,--image-base=0x100000000000") endif() project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.3.0) include_directories( ${KYTY_THIRD_PARTY_DIR}/gtest/include ${KYTY_THIRD_PARTY_DIR}/gtest ${KYTY_THIRD_PARTY_DIR}/fmt/include ${KYTY_THIRD_PARTY_DIR}/magic_enum/include/magic_enum ${PROJECT_BINARY_DIR} ${KYTY_SOURCE_DIR} ) set(KYTY_VERSION "${PROJECT_VERSION}") configure_file( ${KYTY_SOURCE_DIR}/cmake_config.h.in ${PROJECT_BINARY_DIR}/cmake_config.h ) find_package(Git) add_custom_target(KytyGitVersion COMMAND ${CMAKE_COMMAND} -D INPUT_FILE=${KYTY_SOURCE_DIR}/kytyGitVersion.h.in -D OUTPUT_FILE=${PROJECT_BINARY_DIR}/kytyGitVersion.h -D GIT_EXECUTABLE=${GIT_EXECUTABLE} -D GIT_WORKING_DIRECTORY=${CMAKE_CURRENT_SOURCE_DIR} -P ${KYTY_SOURCE_DIR}/generate_version.cmake BYPRODUCTS ${PROJECT_BINARY_DIR}/kytyGitVersion.h COMMENT "Generate kytyGitVersion.h" ) add_library(kyty_git_version INTERFACE) add_dependencies(kyty_git_version KytyGitVersion) if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0.0) list(APPEND KYTY_IWYU kyty_emulator common #launcher ) list(APPEND KYTY_CLANG_TIDY kyty_emulator #common launcher ) endif() option(KYTY_BUILD_LAUNCHER "Build Qt launcher" ON) config_compiler_and_linker() add_subdirectory("${KYTY_THIRD_PARTY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/3rdparty") add_subdirectory("${KYTY_SOURCE_DIR}/common" "${CMAKE_CURRENT_BINARY_DIR}/common") file(GLOB kyty_emulator_src CONFIGURE_DEPENDS "${KYTY_SOURCE_DIR}/libs/*.cpp" "${KYTY_SOURCE_DIR}/libs/*.h" "${KYTY_SOURCE_DIR}/graphics/*.cpp" "${KYTY_SOURCE_DIR}/graphics/*.h" "${KYTY_SOURCE_DIR}/graphics/guest_gpu/*.cpp" "${KYTY_SOURCE_DIR}/graphics/guest_gpu/*.h" "${KYTY_SOURCE_DIR}/graphics/guest_gpu/command_processor/*.cpp" "${KYTY_SOURCE_DIR}/graphics/guest_gpu/command_processor/*.h" "${KYTY_SOURCE_DIR}/graphics/host_gpu/*.cpp" "${KYTY_SOURCE_DIR}/graphics/host_gpu/*.h" "${KYTY_SOURCE_DIR}/graphics/host_gpu/renderer/*.cpp" "${KYTY_SOURCE_DIR}/graphics/host_gpu/renderer/*.h" "${KYTY_SOURCE_DIR}/graphics/host_gpu/renderer/cache/*.cpp" "${KYTY_SOURCE_DIR}/graphics/host_gpu/renderer/cache/*.h" "${KYTY_SOURCE_DIR}/graphics/host_gpu/renderer/image/*.cpp" "${KYTY_SOURCE_DIR}/graphics/host_gpu/renderer/image/*.h" "${KYTY_SOURCE_DIR}/graphics/host_gpu/renderer/pipeline/*.cpp" "${KYTY_SOURCE_DIR}/graphics/host_gpu/renderer/pipeline/*.h" "${KYTY_SOURCE_DIR}/graphics/shader/*.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/*.h" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/*.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/*.h" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/frontend/cfg/*.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/frontend/cfg/*.h" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/frontend/decode/*.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/frontend/decode/*.h" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/frontend/translate/*.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/frontend/translate/*.h" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/backend/spirv/*.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/backend/spirv/*.h" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/*.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/*.h" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/opcodes/*.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/opcodes/*.h" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/opcodes/*.inc" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/*.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/*.h" "${KYTY_SOURCE_DIR}/graphics/presentation/*.cpp" "${KYTY_SOURCE_DIR}/graphics/presentation/*.h" "${KYTY_SOURCE_DIR}/graphics/presentation/window/*.cpp" "${KYTY_SOURCE_DIR}/graphics/presentation/window/*.h" "${KYTY_SOURCE_DIR}/kernel/*.cpp" "${KYTY_SOURCE_DIR}/kernel/*.h" "${KYTY_SOURCE_DIR}/loader/*.cpp" "${KYTY_SOURCE_DIR}/loader/*.h" ) find_program(KYTY_GLSLANG_VALIDATOR NAMES glslangValidator glslang REQUIRED) set(gpu_tiler_shader_dir "${KYTY_SOURCE_DIR}/graphics/host_gpu/shaders") set(gpu_tiler_generated_dir "${PROJECT_BINARY_DIR}/gpu_tiler_shaders") set(gpu_tiler_shader_names standard256 standard4 standard4_3d standard64 standard64_3d prt prt_3d render_target depth promote_d16 demote_d16 color_transform ) file(GLOB gpu_tiler_shader_includes CONFIGURE_DEPENDS "${gpu_tiler_shader_dir}/gpu_tiler_*.inc") foreach(shader_name IN LISTS gpu_tiler_shader_names) set(shader_source "${gpu_tiler_shader_dir}/gpu_tiler_${shader_name}.comp") set(shader_spv "${gpu_tiler_generated_dir}/gpu_tiler_${shader_name}.spv") set(shader_header "${gpu_tiler_generated_dir}/gpu_tiler_${shader_name}_spv.h") string(TOUPPER "GPU_TILER_${shader_name}_SPV" shader_symbol) add_custom_command( OUTPUT "${shader_header}" COMMAND ${CMAKE_COMMAND} -E make_directory "${gpu_tiler_generated_dir}" COMMAND "${KYTY_GLSLANG_VALIDATOR}" -V --target-env vulkan1.3 -Os "-I${gpu_tiler_shader_dir}" -o "${shader_spv}" "${shader_source}" COMMAND ${CMAKE_COMMAND} -DINPUT=${shader_spv} -DOUTPUT=${shader_header} -DSYMBOL=${shader_symbol} -P "${KYTY_SOURCE_DIR}/embed_spirv.cmake" DEPENDS "${shader_source}" ${gpu_tiler_shader_includes} VERBATIM ) list(APPEND gpu_tiler_shader_headers "${shader_header}") endforeach() set(fault_buffer_shader_source "${gpu_tiler_shader_dir}/fault_buffer_process.comp") set(fault_buffer_shader_spv "${gpu_tiler_generated_dir}/fault_buffer_process.spv") set(fault_buffer_shader_header "${gpu_tiler_generated_dir}/fault_buffer_process_spv.h") add_custom_command( OUTPUT "${fault_buffer_shader_header}" COMMAND ${CMAKE_COMMAND} -E make_directory "${gpu_tiler_generated_dir}" COMMAND "${KYTY_GLSLANG_VALIDATOR}" -V --target-env vulkan1.3 -Os -DCACHING_PAGEBITS=14 -DMAX_PAGE_FAULTS=1024 -o "${fault_buffer_shader_spv}" "${fault_buffer_shader_source}" COMMAND ${CMAKE_COMMAND} -DINPUT=${fault_buffer_shader_spv} -DOUTPUT=${fault_buffer_shader_header} -DSYMBOL=FAULT_BUFFER_PROCESS_SPV -P "${KYTY_SOURCE_DIR}/embed_spirv.cmake" DEPENDS "${fault_buffer_shader_source}" VERBATIM ) list(APPEND kyty_emulator_src "${fault_buffer_shader_header}") list(APPEND kyty_emulator_src ${gpu_tiler_shader_headers}) set(gpu_blit_generated_dir "${PROJECT_BINARY_DIR}/gpu_blit_shaders") function(add_gpu_blit_shader shader_name shader_file) set(shader_source "${gpu_tiler_shader_dir}/${shader_file}") set(shader_spv "${gpu_blit_generated_dir}/${shader_name}.spv") set(shader_header "${gpu_blit_generated_dir}/${shader_name}_spv.h") string(TOUPPER "${shader_name}_SPV" shader_symbol) add_custom_command( OUTPUT "${shader_header}" COMMAND ${CMAKE_COMMAND} -E make_directory "${gpu_blit_generated_dir}" COMMAND "${KYTY_GLSLANG_VALIDATOR}" -V --target-env vulkan1.3 -Os ${ARGN} "-I${gpu_tiler_shader_dir}" -o "${shader_spv}" "${shader_source}" COMMAND ${CMAKE_COMMAND} -DINPUT=${shader_spv} -DOUTPUT=${shader_header} -DSYMBOL=${shader_symbol} -P "${KYTY_SOURCE_DIR}/embed_spirv.cmake" DEPENDS "${shader_source}" VERBATIM ) set(gpu_blit_shader_headers ${gpu_blit_shader_headers} "${shader_header}" PARENT_SCOPE) endfunction() add_gpu_blit_shader(gpu_blit_fs_triangle gpu_blit_fs_triangle.vert) add_gpu_blit_shader(gpu_blit_color_to_ms_depth gpu_blit_color_to_ms_depth.frag) add_gpu_blit_shader(gpu_video_out_overlay gpu_video_out_overlay.frag) add_gpu_blit_shader(gpu_imgui_hdr gpu_video_out_overlay.frag -DIMGUI_HDR=1) list(APPEND kyty_emulator_src ${gpu_blit_shader_headers}) list(APPEND kyty_emulator_src "${KYTY_SOURCE_DIR}/emulator.h" "${KYTY_SOURCE_DIR}/emulator.cpp" ) list(REMOVE_DUPLICATES kyty_emulator_src) if (KYTY_CLANG_CL) set_source_files_properties(${kyty_emulator_src} PROPERTIES COMPILE_FLAGS "-Wno-pragma-pack -Wno-deprecated-declarations -D_TIMESPEC_DEFINED") endif() set(kyty_emulator_link_libraries common Vulkan::Headers spirv-tools-opt spirv-tools SDL3::SDL3-static imgui xxhash FFmpeg::ffmpeg fmt::fmt nlohmann_json::nlohmann_json LibAtrac9 kyty_git_version Zydis::Zydis xbyak::xbyak opus) # Linux system libraries. if(LINUX) find_package(Threads REQUIRED) list(APPEND kyty_emulator_link_libraries m ${CMAKE_DL_LIBS} Threads::Threads) endif() set(inc_headers ${KYTY_SOURCE_DIR} ${KYTY_THIRD_PARTY_DIR}/VulkanMemoryAllocator/include ${KYTY_THIRD_PARTY_DIR}/SPIRV-Tools/include ${KYTY_THIRD_PARTY_DIR}/SPIRV-Headers/include ${KYTY_THIRD_PARTY_DIR}/fmt/include ${KYTY_THIRD_PARTY_DIR}/xxhash ${KYTY_THIRD_PARTY_DIR}/cpuinfo/include ${KYTY_THIRD_PARTY_DIR}/renderdoc ${KYTY_THIRD_PARTY_DIR}/stb ) if (KYTY_CLANG_CL) list(APPEND kyty_emulator_link_libraries winpthread) list(APPEND inc_headers ${KYTY_THIRD_PARTY_DIR}/winpthread/include ) endif() list(APPEND check_headers ${KYTY_SOURCE_DIR} ) function(add_kyty_full_emulator_test target source) add_executable(${target} EXCLUDE_FROM_ALL ${source} ${kyty_emulator_src}) target_link_libraries(${target} ${kyty_emulator_link_libraries}) target_include_directories(${target} PRIVATE ${inc_headers}) if (WIN32) target_link_libraries(${target} iphlpapi) endif() if (KYTY_CLANG_CL) target_link_libraries(${target} onecore) add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${KYTY_THIRD_PARTY_DIR}/winpthread/bin/libwinpthread-1.dll" $/libwinpthread-1.dll) endif() # The macOS x86_64 guest address space needs its .zerofill segments anchored # by linker flags, or the kernel kills the binary on load (posix_spawn EIO). configure_macos_guest_address_space(${target}) endfunction() function(configure_macos_guest_address_space target) if(APPLE AND (CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64" OR (NOT CMAKE_OSX_ARCHITECTURES AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64)$"))) target_sources(${target} PRIVATE "${KYTY_SOURCE_DIR}/kernel/macosGuestAddressSpace.cpp") target_compile_definitions(${target} PRIVATE KYTY_LINKED_GUEST_ADDRESS_SPACE=1) target_link_options(${target} PRIVATE -Wl,-ld_classic,-no_pie,-no_fixup_chains,-no_huge,-pagezero_size,0x40000,-segaddr,SYSTEM_MANAGED,0x40000,-segaddr,SYSTEM_RESERVED,0x7ffffc000,-segaddr,USER_AREA,0x7000000000,-image_base,0x700000000000) endif() endfunction() add_kyty_full_emulator_test(shader_cfg_tests "${KYTY_TESTS_DIR}/shaderCfgTests.cpp") add_executable(scalar_provenance_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/ScalarProvenanceTests.cpp" "${KYTY_SOURCE_DIR}/graphics/guest_gpu/gpu_format.cpp" "${KYTY_SOURCE_DIR}/graphics/host_gpu/hostMemory.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/ReadLaneElimination.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/SrtWalker.cpp" ) target_link_libraries(scalar_provenance_tests fmt::fmt xbyak::xbyak) target_include_directories(scalar_provenance_tests PRIVATE ${inc_headers}) add_executable(page_manager_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/PageManagerTests.cpp" "${KYTY_SOURCE_DIR}/graphics/host_gpu/pageManager.cpp" ) target_link_libraries(page_manager_tests common) target_include_directories(page_manager_tests PRIVATE ${inc_headers}) add_executable(archive_file_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/ArchiveFileTests.cpp" ) target_link_libraries(archive_file_tests common ZArchive::zarchive) target_include_directories(archive_file_tests PRIVATE ${inc_headers}) add_executable(trophy_system_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/TrophySystemTests.cpp" ) target_link_libraries(trophy_system_tests common) target_include_directories(trophy_system_tests PRIVATE ${inc_headers}) add_executable(avplayer_file_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/AvPlayerFileTests.cpp" "${KYTY_SOURCE_DIR}/loader/timer.cpp" ) target_link_libraries(avplayer_file_tests common FFmpeg::ffmpeg ZArchive::zarchive) target_include_directories(avplayer_file_tests PRIVATE ${inc_headers}) add_executable(vdecsw_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/VdecswTests.cpp" "${KYTY_SOURCE_DIR}/libs/videoDec2Decoder.cpp" "${KYTY_SOURCE_DIR}/loader/timer.cpp" ) target_link_libraries(vdecsw_tests common FFmpeg::ffmpeg) target_include_directories(vdecsw_tests PRIVATE ${inc_headers}) add_executable(bit_array_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/BitArrayTests.cpp" ) target_include_directories(bit_array_tests PRIVATE ${inc_headers}) add_executable(lru_cache_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/LruCacheTests.cpp" ) target_include_directories(lru_cache_tests PRIVATE ${inc_headers}) add_executable(ime_dialog_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/ImeDialogTests.cpp" "${KYTY_SOURCE_DIR}/libs/imeCommon.cpp" "${KYTY_SOURCE_DIR}/libs/imeDialog.cpp" ) target_include_directories(ime_dialog_tests PRIVATE ${inc_headers}) add_executable(memory_tracker_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/MemoryTrackerTests.cpp" "${KYTY_SOURCE_DIR}/graphics/host_gpu/pageManager.cpp" "${KYTY_SOURCE_DIR}/graphics/host_gpu/memoryTracker.cpp" ) target_link_libraries(memory_tracker_tests fmt::fmt common) target_include_directories(memory_tracker_tests PRIVATE ${inc_headers}) add_executable(shader_vertex_metadata_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/ShaderVertexMetadataTests.cpp" "${KYTY_SOURCE_DIR}/graphics/host_gpu/hostMemory.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/shaderVertexMetadata.cpp" ) target_include_directories(shader_vertex_metadata_tests PRIVATE ${inc_headers}) add_executable(resource_materialization_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/ResourceMaterializationTests.cpp" "${KYTY_SOURCE_DIR}/graphics/guest_gpu/gpu_format.cpp" "${KYTY_SOURCE_DIR}/graphics/host_gpu/hostMemory.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/SrtWalker.cpp" ) target_link_libraries(resource_materialization_tests fmt::fmt xbyak::xbyak) target_include_directories(resource_materialization_tests PRIVATE ${inc_headers}) add_executable(resource_tracking_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/ResourceTrackingTests.cpp" "${KYTY_SOURCE_DIR}/graphics/guest_gpu/gpu_format.cpp" "${KYTY_SOURCE_DIR}/graphics/host_gpu/hostMemory.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/shaderPixelParameter.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/SrtWalker.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/ResourceTracking.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/ResourceMaterialization.cpp" "${KYTY_SOURCE_DIR}/graphics/shader/recompiler/ir/passes/ShaderInfoCollection.cpp" ) target_link_libraries(resource_tracking_tests fmt::fmt xbyak::xbyak) target_include_directories(resource_tracking_tests PRIVATE ${inc_headers}) add_executable(audio_out2_port_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/AudioOut2PortTests.cpp" "${KYTY_SOURCE_DIR}/libs/libAudio2.cpp" "${KYTY_SOURCE_DIR}/loader/timer.cpp" ) target_link_libraries(audio_out2_port_tests common fmt::fmt) target_include_directories(audio_out2_port_tests PRIVATE ${inc_headers}) add_executable(audio_out_timing_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/AudioOutTimingTests.cpp") target_link_libraries(audio_out_timing_tests common fmt::fmt SDL3::SDL3-static) target_include_directories(audio_out_timing_tests PRIVATE ${inc_headers}) add_executable(ngs2_sampler_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/Ngs2SamplerTests.cpp" "${KYTY_SOURCE_DIR}/loader/timer.cpp" ) target_link_libraries(ngs2_sampler_tests common fmt::fmt LibAtrac9) target_include_directories(ngs2_sampler_tests PRIVATE ${inc_headers}) add_executable(pad_haptics_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/PadHapticsTests.cpp" ) target_link_libraries(pad_haptics_tests common fmt::fmt SDL3::SDL3-static opus) target_include_directories(pad_haptics_tests PRIVATE ${inc_headers}) add_executable(controller_settings_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/ControllerSettingsTests.cpp" ) target_link_libraries(controller_settings_tests common fmt::fmt SDL3::SDL3-static) target_include_directories(controller_settings_tests PRIVATE ${inc_headers}) add_executable(save_data_memory_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/SaveDataMemoryTests.cpp" ) target_link_libraries(save_data_memory_tests common fmt::fmt) target_include_directories(save_data_memory_tests PRIVATE ${inc_headers}) add_executable(png_enc_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/PngEncTests.cpp") target_link_libraries(png_enc_tests common fmt::fmt) target_include_directories(png_enc_tests PRIVATE ${inc_headers}) add_executable(ces_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/CesTests.cpp") target_link_libraries(ces_tests common fmt::fmt SDL3::SDL3-static) target_include_directories(ces_tests PRIVATE ${inc_headers}) add_executable(save_data_dialog_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/SaveDataDialogTests.cpp" "${KYTY_SOURCE_DIR}/libs/dialog.cpp" ) target_link_libraries(save_data_dialog_tests common fmt::fmt) target_include_directories(save_data_dialog_tests PRIVATE ${inc_headers}) add_kyty_full_emulator_test(http_uri_parse_tests "${KYTY_TESTS_DIR}/HttpUriParseTests.cpp") add_executable(event_queue_lifetime_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/EventQueueLifetimeTests.cpp" "${KYTY_SOURCE_DIR}/kernel/eventQueue.cpp" "${KYTY_SOURCE_DIR}/loader/timer.cpp" ) target_link_libraries(event_queue_lifetime_tests common fmt::fmt) target_include_directories(event_queue_lifetime_tests PRIVATE ${inc_headers}) add_kyty_full_emulator_test(kernel_file_system_tests "${KYTY_TESTS_DIR}/KernelFileSystemTests.cpp") target_link_libraries(kernel_file_system_tests ZArchive::zarchive) add_executable(sync_on_address_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/SyncOnAddressTests.cpp" "${KYTY_SOURCE_DIR}/kernel/syncOnAddress.cpp" ) target_link_libraries(sync_on_address_tests common) target_include_directories(sync_on_address_tests PRIVATE ${inc_headers}) add_executable(image_page_table_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/ImagePageTableTests.cpp" ) target_link_libraries(image_page_table_tests common fmt::fmt) target_include_directories(image_page_table_tests PRIVATE ${inc_headers}) add_kyty_full_emulator_test(shader_recompiler_compute_tests "${KYTY_TESTS_DIR}/ShaderRecompilerComputeTests.cpp") set(gpu_test_generated_dir "${PROJECT_BINARY_DIR}/gpu_test_shaders") set(gpu_test_ms_depth_source "${gpu_tiler_shader_dir}/gpu_test_ms_depth.comp") set(gpu_test_ms_depth_spv "${gpu_test_generated_dir}/gpu_test_ms_depth.spv") set(gpu_test_ms_depth_header "${gpu_test_generated_dir}/gpu_test_ms_depth_spv.h") add_custom_command( OUTPUT "${gpu_test_ms_depth_header}" COMMAND ${CMAKE_COMMAND} -E make_directory "${gpu_test_generated_dir}" COMMAND "${KYTY_GLSLANG_VALIDATOR}" -V --target-env vulkan1.3 -Os -o "${gpu_test_ms_depth_spv}" "${gpu_test_ms_depth_source}" COMMAND ${CMAKE_COMMAND} -DINPUT=${gpu_test_ms_depth_spv} -DOUTPUT=${gpu_test_ms_depth_header} -DSYMBOL=GPU_TEST_MS_DEPTH_SPV -P "${KYTY_SOURCE_DIR}/embed_spirv.cmake" DEPENDS "${gpu_test_ms_depth_source}" VERBATIM ) target_sources(shader_recompiler_compute_tests PRIVATE "${gpu_test_ms_depth_header}") add_kyty_full_emulator_test(virtual_memory_allocation_tests "${KYTY_TESTS_DIR}/VirtualMemoryAllocationTests.cpp") target_compile_definitions(virtual_memory_allocation_tests PRIVATE KYTY_VIRTUAL_MEMORY_ALLOCATION_TESTS=1) # These tests use exceptions. if(NOT KYTY_CLANG_CL) foreach(kyty_exception_test scalar_provenance_tests resource_tracking_tests virtual_memory_allocation_tests) target_compile_options(${kyty_exception_test} PRIVATE -fexceptions) endforeach() endif() if(BUILD_TESTING) add_test(NAME emulator_user_name_cli COMMAND $ --help --user-name 1234567890123456) add_test(NAME emulator_user_name_too_long COMMAND $ --help --user-name 12345678901234567) set_tests_properties(emulator_user_name_too_long PROPERTIES WILL_FAIL TRUE) add_test(NAME emulator_present_mode_cli COMMAND $ --help --present-mode Immediate) add_test(NAME emulator_present_mode_invalid COMMAND $ --help --present-mode Invalid) set_tests_properties(emulator_present_mode_invalid PROPERTIES WILL_FAIL TRUE) add_test(NAME ime_dialog COMMAND $) add_test(NAME shader_cfg COMMAND $) add_test(NAME scalar_provenance COMMAND $) add_test(NAME image_page_table COMMAND $) add_test(NAME memory_tracker COMMAND $) add_test(NAME page_manager COMMAND $) add_test(NAME archive_file COMMAND $) add_test(NAME trophy_system COMMAND $) add_test(NAME avplayer_file COMMAND $) add_test(NAME vdecsw COMMAND $) add_test(NAME bit_array COMMAND $) add_test(NAME lru_cache COMMAND $) add_test(NAME shader_vertex_metadata COMMAND $) add_test(NAME resource_materialization COMMAND $) add_test(NAME resource_tracking COMMAND $) add_test(NAME event_queue_lifetime COMMAND $) add_test(NAME kernel_file_system COMMAND $) add_test(NAME sync_on_address COMMAND $) add_test(NAME audio_out2_port COMMAND $) add_test(NAME audio_out_timing COMMAND $) add_test(NAME ngs2_sampler COMMAND $) add_test(NAME pad_haptics COMMAND $) add_test(NAME controller_settings COMMAND $) add_test(NAME save_data_memory COMMAND $) add_test(NAME png_enc COMMAND $) add_test(NAME ces COMMAND $) add_test(NAME save_data_dialog COMMAND $) add_test(NAME http_uri_parse COMMAND $) add_test(NAME shader_recompiler_compute COMMAND $) add_test(NAME shader_recompiler_alignbyte COMMAND $ --alignbyte-only) add_test(NAME graphics_pipeline_rasterization COMMAND $ --polygon-mode-only) add_test(NAME graphics_draw_offsets COMMAND $ --draw-offset-only) add_test(NAME virtual_memory_allocation COMMAND $) add_test(NAME guest_red_zone_patcher COMMAND $ --red-zone-patcher-only) add_test(NAME command_scheduler_timeline COMMAND $ --scheduler-only) add_test(NAME stream_buffer_ring COMMAND $ --stream-buffer-only) add_test(NAME gpu_command_lane COMMAND $ --gpu-command-lane-only) add_test(NAME pm4_context_state COMMAND $ --context-state-only) add_test(NAME gpu_tiler COMMAND $ --gpu-tiler-only) add_test(NAME image_transfer_layout COMMAND $ --image-layout-only) add_test(NAME texture_cache_layered_image COMMAND $ --layered-image-only) add_test(NAME host_image_allocation COMMAND $ --host-image-allocation-only) add_test(NAME texture_cache_image_views COMMAND $ --image-view-cache-only) add_test(NAME texture_cache_storage_sampled COMMAND $ --storage-sampled-only) add_test(NAME texture_cache_depth_readback COMMAND $ --depth-readback-only) add_test(NAME compute_meta_clear_classification COMMAND $ --compute-meta-clear-only) add_test(NAME buffer_cache_dirty_gc COMMAND $ --buffer-cache-gc-only) add_test(NAME color_render_target_1d COMMAND $ --rt1d-only) add_test(NAME texture_cache_image_overlap COMMAND $ --image-overlap-only) add_test(NAME texture_cache_htile_clear COMMAND $ --htile-clear-only) add_test(NAME buffer_cache_ranges COMMAND $ --buffer-cache-range-only) add_custom_target(kyty_tests DEPENDS ime_dialog_tests shader_cfg_tests scalar_provenance_tests image_page_table_tests memory_tracker_tests page_manager_tests archive_file_tests trophy_system_tests avplayer_file_tests vdecsw_tests bit_array_tests lru_cache_tests shader_vertex_metadata_tests resource_materialization_tests resource_tracking_tests event_queue_lifetime_tests kernel_file_system_tests sync_on_address_tests shader_recompiler_compute_tests virtual_memory_allocation_tests audio_out2_port_tests audio_out_timing_tests ngs2_sampler_tests pad_haptics_tests controller_settings_tests save_data_memory_tests png_enc_tests ces_tests save_data_dialog_tests http_uri_parse_tests ) endif() # Test Darwin signal-context restoration for SSE4a instructions. if(APPLE AND (CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64" OR (NOT CMAKE_OSX_ARCHITECTURES AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64)$"))) add_executable(macos_sse4a_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/macosSse4aTests.cpp" "${KYTY_SOURCE_DIR}/loader/x64InstructionEmulator.cpp" "${KYTY_SOURCE_DIR}/loader/guestInstructionPatcher.cpp" ) target_link_libraries(macos_sse4a_tests common fmt::fmt Zydis::Zydis xbyak::xbyak) target_include_directories(macos_sse4a_tests PRIVATE ${inc_headers}) if(BUILD_TESTING) add_test(NAME macos_sse4a COMMAND $) set_tests_properties(macos_sse4a PROPERTIES TIMEOUT 15) add_dependencies(kyty_tests macos_sse4a_tests) endif() endif() add_executable(kyty_emulator "${KYTY_SOURCE_DIR}/main.cpp" ${kyty_emulator_src}) configure_macos_guest_address_space(kyty_emulator) set(KYTY_TROPHY_UNLOCK_SOUND "${CMAKE_CURRENT_SOURCE_DIR}/assets/sounds/trophy-unlock.wav") add_custom_target(kyty_trophy_sound COMMAND ${CMAKE_COMMAND} -E make_directory "$/assets/sounds" COMMAND ${CMAKE_COMMAND} -E copy_if_different "${KYTY_TROPHY_UNLOCK_SOUND}" "$/assets/sounds/trophy-unlock.wav" VERBATIM) add_dependencies(kyty_emulator kyty_trophy_sound) install(FILES "${KYTY_TROPHY_UNLOCK_SOUND}" DESTINATION assets/sounds) target_link_libraries(kyty_emulator ${kyty_emulator_link_libraries}) if (WIN32) target_link_libraries(kyty_emulator opengl32) target_link_libraries(kyty_emulator iphlpapi) target_link_libraries(kyty_emulator setupapi) target_link_libraries(kyty_emulator ws2_32) endif() if (KYTY_CLANG_CL) target_link_libraries(kyty_emulator onecore) endif() if (CLANG AND NOT KYTY_CLANG_CL) target_link_libraries(kyty_emulator pthread) endif() # dlopen/dlsym/dladdr for RenderDoc. target_link_libraries(kyty_emulator ${CMAKE_DL_LIBS}) target_include_directories(kyty_emulator PRIVATE ${inc_headers}) clang_tidy_check(kyty_emulator "" "${check_headers}" "${inc_headers}") include_what_you_use(kyty_emulator "${inc_headers}") set(KYTY_EMULATOR_MAP_NAME "kyty_emulator_${KYTY_COMPILER_ID}_${KYTY_LINKER_ID}.map") set(KYTY_EMULATOR_MAP_LINK_PATH "${CMAKE_CURRENT_BINARY_DIR}/${KYTY_EMULATOR_MAP_NAME}") set(KYTY_EMULATOR_PDB_LINK_PATH "${CMAKE_CURRENT_BINARY_DIR}/kyty_emulator.pdb") if(KYTY_CLANG_CL) target_link_options(kyty_emulator PRIVATE "/DYNAMICBASE:NO" "/DEBUG:FULL" "/PDB:${KYTY_EMULATOR_PDB_LINK_PATH}" "/lldmap:${KYTY_EMULATOR_MAP_LINK_PATH}" ) add_custom_command(TARGET kyty_emulator POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${KYTY_THIRD_PARTY_DIR}/winpthread/bin/libwinpthread-1.dll" $/libwinpthread-1.dll) elseif(WIN32 OR LINUX) set_target_properties(kyty_emulator PROPERTIES LINK_FLAGS "${KYTY_LD_OPTIONS}") # LINK_FLAGS is a space-delimited string: a -Map path containing spaces would # be split into bogus arguments, so pass it as a discrete link option instead. target_link_options(kyty_emulator PRIVATE "-Wl,-Map=${KYTY_EMULATOR_MAP_LINK_PATH}") endif() if(LINUX) target_link_options(kyty_emulator PRIVATE $<$:-Wl,--strip-all> ) endif() if(APPLE) # The emulator writes x86-64 trampolines/PLT stubs into memory and executes them, and # runs guest code under Rosetta. That requires the JIT / unsigned-executable-memory # entitlements, so re-sign the binary after every link (an unsigned/relinked binary # reverts to the hardened defaults and aborts when it first executes written code). add_custom_command(TARGET kyty_emulator POST_BUILD COMMAND codesign -s - --force --options runtime --entitlements "${KYTY_SOURCE_DIR}/macos_jit.entitlements" $ COMMENT "Codesign kyty_emulator with JIT entitlements (macOS)") endif() install(TARGETS kyty_emulator DESTINATION .) if(KYTY_BUILD_LAUNCHER) add_subdirectory("${KYTY_SOURCE_DIR}/launcher" "${CMAKE_CURRENT_BINARY_DIR}/launcher") if(LINUX) target_link_options(launcher PRIVATE $<$:-Wl,--strip-all>) endif() endif() if(KYTY_CLANG_CL) install(FILES "${KYTY_THIRD_PARTY_DIR}/winpthread/bin/libwinpthread-1.dll" DESTINATION .) endif()