mirror of
https://github.com/jessicanataliagta/PSPRecomp
synced 2026-09-29 17:28:27 -04:00
296 lines
13 KiB
CMake
296 lines
13 KiB
CMake
set(VCS_PROFILE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
|
|
|
# Keep the enormous generated AOT corpus out of MSVC whole-program/LTCG IR by
|
|
# default. Stage 45.8/45.9 cross-unit state makes whole-program analysis of all
|
|
# 234 generated units extremely memory hungry on Windows. The AOT units are
|
|
# still fully optimized per translation unit; host/runtime code may still use
|
|
# PSPRECOMP_LTO.
|
|
option(PSPRECOMP_VCS_AOT_LTO
|
|
"Include generated VCS AOT units in MSVC whole-program optimization" OFF)
|
|
|
|
option(PSPRECOMP_PROFILE_GUIDED_AOT
|
|
"Optimize the measured VCS hot AOT units above the base generated level" ON)
|
|
set(PSPRECOMP_HOT_GENERATED_OPT_LEVEL "2" CACHE STRING
|
|
"Optimization level for profile-guided VCS AOT units (0, 1, 2 or 3)")
|
|
set_property(CACHE PSPRECOMP_HOT_GENERATED_OPT_LEVEL PROPERTY STRINGS 0 1 2 3)
|
|
if(NOT PSPRECOMP_HOT_GENERATED_OPT_LEVEL MATCHES "^[0-3]$")
|
|
message(FATAL_ERROR "PSPRECOMP_HOT_GENERATED_OPT_LEVEL must be 0, 1, 2 or 3")
|
|
endif()
|
|
|
|
# Full /Ob3 is valuable at runtime but several large, cold units still make
|
|
# MSVC spend minutes and close to a gigabyte per compiler process. Keep those
|
|
# units buildable, then override this level only for the measured hot corpus.
|
|
set(PSPRECOMP_GENERATED_INLINE_LEVEL "0" CACHE STRING
|
|
"MSVC /Ob level for generated VCS AOT units (0, 1, 2 or 3)")
|
|
set_property(CACHE PSPRECOMP_GENERATED_INLINE_LEVEL PROPERTY STRINGS 0 1 2 3)
|
|
if(NOT PSPRECOMP_GENERATED_INLINE_LEVEL MATCHES "^[0-3]$")
|
|
message(FATAL_ERROR "PSPRECOMP_GENERATED_INLINE_LEVEL must be 0, 1, 2 or 3")
|
|
endif()
|
|
set(PSPRECOMP_HOT_GENERATED_INLINE_LEVEL "3" CACHE STRING
|
|
"MSVC /Ob level for measured hot VCS AOT units (0, 1, 2 or 3)")
|
|
set_property(CACHE PSPRECOMP_HOT_GENERATED_INLINE_LEVEL PROPERTY STRINGS 0 1 2 3)
|
|
if(NOT PSPRECOMP_HOT_GENERATED_INLINE_LEVEL MATCHES "^[0-3]$")
|
|
message(FATAL_ERROR "PSPRECOMP_HOT_GENERATED_INLINE_LEVEL must be 0, 1, 2 or 3")
|
|
endif()
|
|
|
|
file(GLOB VCS_GENERATED CONFIGURE_DEPENDS "${VCS_PROFILE_DIR}/generated/*.cpp")
|
|
if(MSVC)
|
|
if(PSPRECOMP_GENERATED_OPT_LEVEL STREQUAL "0")
|
|
set(VCS_GENERATED_MSVC_OPT "/Od")
|
|
elseif(PSPRECOMP_GENERATED_OPT_LEVEL STREQUAL "3")
|
|
set(VCS_GENERATED_MSVC_OPT "/Ox")
|
|
else()
|
|
set(VCS_GENERATED_MSVC_OPT "/O${PSPRECOMP_GENERATED_OPT_LEVEL}")
|
|
endif()
|
|
set(VCS_GENERATED_MSVC_OPTIONS
|
|
"${VCS_GENERATED_MSVC_OPT};/Ob${PSPRECOMP_GENERATED_INLINE_LEVEL};/bigobj;${PSPRECOMP_MSVC_MP_FLAG}")
|
|
if(PSPRECOMP_LTO AND NOT PSPRECOMP_VCS_AOT_LTO)
|
|
# CMAKE_INTERPROCEDURAL_OPTIMIZATION adds /GL at target scope. /GL- on
|
|
# these sources overrides it so the linker receives native .obj code
|
|
# instead of 234 giant LTCG IR modules.
|
|
string(APPEND VCS_GENERATED_MSVC_OPTIONS ";/GL-")
|
|
endif()
|
|
set_source_files_properties(${VCS_GENERATED} PROPERTIES COMPILE_OPTIONS
|
|
"${VCS_GENERATED_MSVC_OPTIONS}")
|
|
else()
|
|
set_source_files_properties(${VCS_GENERATED} PROPERTIES COMPILE_OPTIONS
|
|
"-O${PSPRECOMP_GENERATED_OPT_LEVEL};-g0")
|
|
endif()
|
|
|
|
if(PSPRECOMP_PROFILE_GUIDED_AOT)
|
|
# This unit is hot in the current capture and finishes /Ob3 without
|
|
# triggering MSVC's pathological optimizer growth. It also contains the
|
|
# validated native collision leaf at guest PC 0x088B1554. Other measured
|
|
# units remain /Ob0 until their oversized helpers are split/noinline.
|
|
set(VCS_HOT_UNIT_IDS
|
|
0043)
|
|
set(VCS_HOT_SOURCES)
|
|
foreach(VCS_UNIT_ID IN LISTS VCS_HOT_UNIT_IDS)
|
|
set(VCS_UNIT_SOURCE "${VCS_PROFILE_DIR}/generated/generated_unit_${VCS_UNIT_ID}.cpp")
|
|
if(NOT EXISTS "${VCS_UNIT_SOURCE}")
|
|
message(FATAL_ERROR "VCS profile-guided AOT unit is missing: ${VCS_UNIT_SOURCE}")
|
|
endif()
|
|
list(APPEND VCS_HOT_SOURCES "${VCS_UNIT_SOURCE}")
|
|
endforeach()
|
|
if(MSVC)
|
|
if(PSPRECOMP_HOT_GENERATED_OPT_LEVEL STREQUAL "0")
|
|
set(VCS_HOT_MSVC_OPT "/Od")
|
|
elseif(PSPRECOMP_HOT_GENERATED_OPT_LEVEL STREQUAL "3")
|
|
set(VCS_HOT_MSVC_OPT "/Ox")
|
|
else()
|
|
set(VCS_HOT_MSVC_OPT "/O${PSPRECOMP_HOT_GENERATED_OPT_LEVEL}")
|
|
endif()
|
|
set(VCS_HOT_MSVC_OPTIONS
|
|
"${VCS_HOT_MSVC_OPT};/Ob${PSPRECOMP_HOT_GENERATED_INLINE_LEVEL};/bigobj;${PSPRECOMP_MSVC_MP_FLAG}")
|
|
if(PSPRECOMP_LTO AND NOT PSPRECOMP_VCS_AOT_LTO)
|
|
string(APPEND VCS_HOT_MSVC_OPTIONS ";/GL-")
|
|
endif()
|
|
set_source_files_properties(${VCS_HOT_SOURCES} PROPERTIES COMPILE_OPTIONS
|
|
"${VCS_HOT_MSVC_OPTIONS}")
|
|
else()
|
|
set_source_files_properties(${VCS_HOT_SOURCES} PROPERTIES COMPILE_OPTIONS
|
|
"-O${PSPRECOMP_HOT_GENERATED_OPT_LEVEL};-g0")
|
|
endif()
|
|
endif()
|
|
|
|
if(MSVC AND PSPRECOMP_NATIVE_AVX2)
|
|
# MSVC 19.44's AVX2 optimizer crashes (C1001/c2.dll) on this translation
|
|
# unit, while the identical /Ox /Ob0 compile completes in ~3 s with AVX.
|
|
# Keep AVX2 for the host and the other AOT units; append the weaker ISA only
|
|
# to the known compiler-bug trigger (the last /arch switch wins in cl.exe).
|
|
set(PSPRECOMP_VCS_MSVC_AVX_FALLBACK_UNITS "0018;0022;0035;0089;0091;0117;0164" CACHE STRING
|
|
"Generated VCS units forced to AVX because MSVC 19.44 crashes with AVX2")
|
|
set(VCS_MSVC_AVX_FALLBACK_SOURCES)
|
|
foreach(VCS_UNIT_ID IN LISTS PSPRECOMP_VCS_MSVC_AVX_FALLBACK_UNITS)
|
|
set(VCS_UNIT_SOURCE "${VCS_PROFILE_DIR}/generated/generated_unit_${VCS_UNIT_ID}.cpp")
|
|
if(NOT EXISTS "${VCS_UNIT_SOURCE}")
|
|
message(FATAL_ERROR "VCS AVX fallback unit is missing: ${VCS_UNIT_SOURCE}")
|
|
endif()
|
|
list(APPEND VCS_MSVC_AVX_FALLBACK_SOURCES "${VCS_UNIT_SOURCE}")
|
|
endforeach()
|
|
set_property(SOURCE ${VCS_MSVC_AVX_FALLBACK_SOURCES} APPEND PROPERTY
|
|
COMPILE_OPTIONS "/arch:AVX")
|
|
endif()
|
|
|
|
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
|
set_source_files_properties("${VCS_PROFILE_DIR}/host/vcs_profile.cpp" PROPERTIES COMPILE_OPTIONS "-O2")
|
|
endif()
|
|
|
|
set(VCS_GPU_BACKEND_SOURCE host/ge_gpu_backend_dx12.cpp)
|
|
set(VCS_HDR_POST_SOURCE host/vcs_hdr_post_dx12_stub.cpp)
|
|
set(VCS_HOST_SOURCES
|
|
host/vcs_bootstrap_paths.cpp
|
|
host/vcs_profile.cpp
|
|
host/vcs_native_fast_paths.cpp
|
|
host/framebuffer_capture.cpp
|
|
host/display_window.cpp
|
|
host/audio_output.cpp
|
|
host/vcs_config.cpp
|
|
host/vcs_camera_input.cpp
|
|
host/vcs_vehicle_input.cpp
|
|
host/vcs_fps_overlay.cpp
|
|
host/vcs_media_decoder.cpp
|
|
host/vcs_project2dfx.cpp
|
|
host/vcs_project2dfx_lights.cpp
|
|
host/vcs_draw_distance_patch.cpp
|
|
host/vcs_runtime_log.cpp
|
|
${VCS_HDR_POST_SOURCE}
|
|
host/ge_renderer.cpp
|
|
${VCS_GPU_BACKEND_SOURCE}
|
|
host/dx12_presenter.cpp
|
|
)
|
|
|
|
function(vcs_target_common target)
|
|
target_include_directories(${target} PRIVATE
|
|
"${VCS_PROFILE_DIR}/host"
|
|
"${VCS_PROFILE_DIR}/generated"
|
|
"${VCS_PROFILE_DIR}/third_party/ffmpeg/include")
|
|
target_link_libraries(${target} PRIVATE psprecomp_core ${CMAKE_DL_LIBS})
|
|
if(WIN32)
|
|
foreach(VCS_FFMPEG_LIB avcodec avformat avutil swresample swscale)
|
|
target_link_libraries(${target} PRIVATE
|
|
"${VCS_PROFILE_DIR}/third_party/ffmpeg/lib/${VCS_FFMPEG_LIB}.lib")
|
|
endforeach()
|
|
target_link_libraries(${target} PRIVATE winmm d3d12 dxgi d3dcompiler dxguid)
|
|
else()
|
|
# The profile vendors FFmpeg 7 headers. Some validation hosts install only
|
|
# the versioned runtime sonames (without development symlinks), so accept
|
|
# the matching FFmpeg 7 ABI names as fallbacks.
|
|
set(VCS_FFMPEG_avcodec_NAMES avcodec libavcodec.so.61)
|
|
set(VCS_FFMPEG_avformat_NAMES avformat libavformat.so.61)
|
|
set(VCS_FFMPEG_avutil_NAMES avutil libavutil.so.59)
|
|
set(VCS_FFMPEG_swresample_NAMES swresample libswresample.so.5)
|
|
set(VCS_FFMPEG_swscale_NAMES swscale libswscale.so.8)
|
|
foreach(VCS_FFMPEG_LIB avcodec avformat avutil swresample swscale)
|
|
find_library(VCS_SYSTEM_${VCS_FFMPEG_LIB}
|
|
NAMES ${VCS_FFMPEG_${VCS_FFMPEG_LIB}_NAMES}
|
|
REQUIRED)
|
|
target_link_libraries(${target} PRIVATE ${VCS_SYSTEM_${VCS_FFMPEG_LIB}})
|
|
endforeach()
|
|
endif()
|
|
psprecomp_enable_host_avx(${target})
|
|
endfunction()
|
|
|
|
|
|
function(vcs_set_runtime_output target)
|
|
set_target_properties(${target} PROPERTIES
|
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$<CONFIG>")
|
|
endfunction()
|
|
|
|
set(VCS_APP_RESOURCES)
|
|
if(WIN32)
|
|
list(APPEND VCS_APP_RESOURCES resources/VCSNative.rc)
|
|
endif()
|
|
|
|
add_executable(VCSNative
|
|
${VCS_APP_RESOURCES}
|
|
host/main.cpp
|
|
${VCS_HOST_SOURCES}
|
|
${VCS_GENERATED}
|
|
)
|
|
vcs_target_common(VCSNative)
|
|
vcs_set_runtime_output(VCSNative)
|
|
if(MSVC)
|
|
# /Ob3 must stay off the target: target_compile_options lands in the vcxproj
|
|
# AdditionalOptions, which cl.exe sees *after* the per-source
|
|
# InlineFunctionExpansion, so a target-wide /Ob3 silently overrides the
|
|
# /Ob${PSPRECOMP_GENERATED_INLINE_LEVEL} set on the generated corpus above
|
|
# (MSVC reports this as "D9025: overriding '/Ob0' with '/Ob3'"). Apply it to
|
|
# the host sources only.
|
|
target_compile_options(VCSNative PRIVATE ${PSPRECOMP_MSVC_MP_FLAG})
|
|
set_source_files_properties(host/main.cpp ${VCS_HOST_SOURCES}
|
|
DIRECTORY "${VCS_PROFILE_DIR}" PROPERTIES COMPILE_OPTIONS
|
|
"$<$<CONFIG:Release>:/Ob3>;$<$<CONFIG:RelWithDebInfo>:/Ob3>")
|
|
target_link_options(VCSNative PRIVATE /STACK:67108864)
|
|
if(PSPRECOMP_LTO)
|
|
# Make the otherwise silent LTCG phase visible in the console.
|
|
target_link_options(VCSNative PRIVATE /LTCG:STATUS /INCREMENTAL:NO)
|
|
if(NOT PSPRECOMP_MSVC_CGTHREADS STREQUAL "0")
|
|
target_link_options(VCSNative PRIVATE "/CGTHREADS:${PSPRECOMP_MSVC_CGTHREADS}")
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
if(WIN32)
|
|
add_custom_command(TARGET VCSNative POST_BUILD
|
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
|
"${VCS_PROFILE_DIR}/third_party/ffmpeg/bin" "$<TARGET_FILE_DIR:VCSNative>"
|
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
|
"${VCS_PROFILE_DIR}/third_party/ffmpeg/COPYING.LGPLv2.1"
|
|
"$<TARGET_FILE_DIR:VCSNative>/COPYING.LGPLv2.1")
|
|
endif()
|
|
add_custom_command(TARGET VCSNative POST_BUILD
|
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
|
"${VCS_PROFILE_DIR}/config/VCSNative.ini" "$<TARGET_FILE_DIR:VCSNative>/VCSNative.ini"
|
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
|
"${VCS_PROFILE_DIR}/config/ProperShaders.ini" "$<TARGET_FILE_DIR:VCSNative>/ProperShaders.ini"
|
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
|
"${VCS_PROFILE_DIR}/data/VCSProject2DFX_Lights.bin"
|
|
"$<TARGET_FILE_DIR:VCSNative>/VCSProject2DFX_Lights.bin"
|
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
|
"${VCS_PROFILE_DIR}/third_party/project2dfx/ATTRIBUTION.md"
|
|
"$<TARGET_FILE_DIR:VCSNative>/PROJECT2DFX_ATTRIBUTION.md"
|
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
|
"${VCS_PROFILE_DIR}/third_party/project2dfx/LICENSE.txt"
|
|
"$<TARGET_FILE_DIR:VCSNative>/PROJECT2DFX_LICENSE.txt"
|
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
|
"${VCS_PROFILE_DIR}/third_party/cloudworks/ATTRIBUTION.md"
|
|
"$<TARGET_FILE_DIR:VCSNative>/CLOUDWORKS_ATTRIBUTION.md")
|
|
|
|
# Profile-specific generator. The root psp_recomp target stays game-neutral.
|
|
add_executable(vcs_recomp tools/vcs_codegen_main.cpp)
|
|
target_link_libraries(vcs_recomp PRIVATE psprecomp_core)
|
|
vcs_set_runtime_output(vcs_recomp)
|
|
|
|
if(PSPRECOMP_BUILD_PROFILE_TESTS)
|
|
if(NOT PSPRECOMP_BUILD_TESTS)
|
|
enable_testing()
|
|
endif()
|
|
add_executable(vcs_profile_tests tests/vcs_profile_tests.cpp ${VCS_HOST_SOURCES})
|
|
vcs_target_common(vcs_profile_tests)
|
|
vcs_set_runtime_output(vcs_profile_tests)
|
|
add_test(NAME vcs_profile_tests COMMAND vcs_profile_tests)
|
|
|
|
add_executable(vcs_config_tests
|
|
tests/vcs_config_tests.cpp
|
|
host/vcs_config.cpp
|
|
host/vcs_camera_input.cpp
|
|
host/vcs_vehicle_input.cpp)
|
|
target_include_directories(vcs_config_tests PRIVATE host)
|
|
add_test(NAME vcs_config_tests COMMAND vcs_config_tests)
|
|
|
|
add_executable(audio_resampler_tests tests/audio_resampler_tests.cpp)
|
|
target_include_directories(audio_resampler_tests PRIVATE host)
|
|
add_test(NAME audio_resampler_tests COMMAND audio_resampler_tests)
|
|
|
|
add_executable(vcs_bootstrap_paths_tests
|
|
tests/vcs_bootstrap_paths_tests.cpp host/vcs_bootstrap_paths.cpp)
|
|
target_include_directories(vcs_bootstrap_paths_tests PRIVATE host)
|
|
target_link_libraries(vcs_bootstrap_paths_tests PRIVATE psprecomp_core)
|
|
add_test(NAME vcs_bootstrap_paths_tests COMMAND vcs_bootstrap_paths_tests)
|
|
endif()
|
|
|
|
if(WIN32)
|
|
add_executable(vcs_dx12_probe
|
|
tools/dx12_probe_main.cpp
|
|
host/dx12_presenter.cpp
|
|
host/vcs_runtime_log.cpp
|
|
host/vcs_config.cpp
|
|
host/vcs_camera_input.cpp
|
|
host/vcs_vehicle_input.cpp)
|
|
target_include_directories(vcs_dx12_probe PRIVATE host "${PROJECT_SOURCE_DIR}/include")
|
|
target_link_libraries(vcs_dx12_probe PRIVATE d3d12 dxgi d3dcompiler dxguid)
|
|
vcs_set_runtime_output(vcs_dx12_probe)
|
|
|
|
add_executable(vcs_dx12_ge_probe
|
|
tools/dx12_ge_probe_main.cpp
|
|
host/ge_gpu_backend_dx12.cpp
|
|
host/vcs_runtime_log.cpp
|
|
host/vcs_config.cpp
|
|
host/vcs_camera_input.cpp
|
|
host/vcs_vehicle_input.cpp)
|
|
target_include_directories(vcs_dx12_ge_probe PRIVATE host "${PROJECT_SOURCE_DIR}/include")
|
|
target_link_libraries(vcs_dx12_ge_probe PRIVATE d3d12 dxgi d3dcompiler dxguid)
|
|
vcs_set_runtime_output(vcs_dx12_ge_probe)
|
|
endif()
|