diff options
225 files changed, 3899 insertions, 891 deletions
| diff --git a/.gitmodules b/.gitmodules index 8a90f4d15..8e98ee9cb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -27,7 +27,7 @@      url = https://github.com/KhronosGroup/Vulkan-Headers.git  [submodule "sirit"]      path = externals/sirit -    url = https://github.com/ReinUsesLisp/sirit +    url = https://github.com/yuzu-emu/sirit  [submodule "mbedtls"]      path = externals/mbedtls      url = https://github.com/yuzu-emu/mbedtls diff --git a/CMakeLists.txt b/CMakeLists.txt index b2fbe8806..cd59e7485 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,10 @@  cmake_minimum_required(VERSION 3.22) +# Dynarmic has cmake_minimum_required(3.12) and we may want to override +# some of its variables, which is only possible in 3.13+ +set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) +  list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")  list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")  list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/find-modules") @@ -27,8 +31,6 @@ CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSV  option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON) -option(YUZU_USE_BUNDLED_LIBUSB "Compile bundled libusb" OFF) -  option(YUZU_USE_BUNDLED_FFMPEG "Download/Build bundled FFmpeg" "${WIN32}")  option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF) @@ -39,10 +41,10 @@ option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)  option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF) -option(YUZU_USE_BUNDLED_OPUS "Compile bundled opus" ON) -  option(YUZU_TESTS "Compile tests" ON) +option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON) +  CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile Windows crash dump (Minidump) support" OFF "WIN32" OFF)  option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}") @@ -64,6 +66,21 @@ elseif(NOT "$ENV{VCPKG_TOOLCHAIN_FILE}" STREQUAL "")      include("$ENV{VCPKG_TOOLCHAIN_FILE}")  endif() +if (YUZU_USE_PRECOMPILED_HEADERS) +    if (MSVC AND CCACHE) +        # buildcache does not properly cache PCH files, leading to compilation errors. +        # See https://github.com/mbitsnbites/buildcache/discussions/230 +        message(WARNING "buildcache does not properly support Precompiled Headers. Disabling PCH") +        set(DYNARMIC_USE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE) +        set(YUZU_USE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE) +    endif() +endif() +if (YUZU_USE_PRECOMPILED_HEADERS) +    message(STATUS "Using Precompiled Headers.") +    set(CMAKE_PCH_INSTANTIATE_TEMPLATES ON) +endif() + +  # Default to a Release build  get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)  if (NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE) @@ -180,24 +197,40 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)  # System imported libraries  # ======================================================================= -find_package(fmt 8.0.1 REQUIRED CONFIG) -find_package(nlohmann_json 3.8 REQUIRED CONFIG) +find_package(enet 1.3) +find_package(fmt 9 REQUIRED) +find_package(inih) +find_package(libusb 1.0.24) +find_package(lz4 REQUIRED) +find_package(nlohmann_json 3.8 REQUIRED) +find_package(Opus 1.3) +find_package(Vulkan 1.3.213)  find_package(ZLIB 1.2 REQUIRED) +find_package(zstd 1.5 REQUIRED) + +if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) +    find_package(xbyak 6) +endif() + +if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) +    find_package(dynarmic 6.4.0) +endif() -# Search for config-only package first (for vcpkg), then try non-config -find_package(zstd 1.5 CONFIG) -if (NOT zstd_FOUND) -    find_package(zstd 1.5 REQUIRED) +if (ENABLE_CUBEB) +    find_package(cubeb)  endif() -# lz4 1.8 is required, but vcpkg's lz4-config.cmake does not have version info -find_package(lz4 CONFIG) -if (NOT lz4_FOUND) -    find_package(lz4 1.8 REQUIRED) +if (USE_DISCORD_PRESENCE) +    find_package(DiscordRPC) +endif() + +if (ENABLE_WEB_SERVICE) +    find_package(cpp-jwt 1.4) +    find_package(httplib 0.11)  endif()  if (YUZU_TESTS) -    find_package(Catch2 2.13.7 REQUIRED CONFIG) +    find_package(Catch2 2.13.7 REQUIRED)  endif()  find_package(Boost 1.73.0 COMPONENTS context) @@ -399,23 +432,13 @@ if (ENABLE_SDL2)          set(SDL2_LIBRARY "${SDL2_PREFIX}/lib/x64/SDL2.lib" CACHE PATH "Path to SDL2 library")          set(SDL2_DLL_DIR "${SDL2_PREFIX}/lib/x64/" CACHE PATH "Path to SDL2.dll") -        add_library(SDL2 INTERFACE) -        target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}") -        target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}") +        add_library(SDL2::SDL2 INTERFACE IMPORTED) +        target_link_libraries(SDL2::SDL2 INTERFACE "${SDL2_LIBRARY}") +        target_include_directories(SDL2::SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")      elseif (YUZU_USE_EXTERNAL_SDL2)          message(STATUS "Using SDL2 from externals.")      else()          find_package(SDL2 2.0.18 REQUIRED) - -        # Some installations don't set SDL2_LIBRARIES -        if("${SDL2_LIBRARIES}" STREQUAL "") -            message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2") -            set(SDL2_LIBRARIES "SDL2::SDL2") -        endif() - -        include_directories(SYSTEM ${SDL2_INCLUDE_DIRS}) -        add_library(SDL2 INTERFACE) -        target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}")      endif()  endif() @@ -427,25 +450,6 @@ if (TARGET Boost::boost)      add_library(boost ALIAS Boost::boost)  endif() -# Ensure libusb is properly configured (based on dolphin libusb include) -if(NOT APPLE AND NOT YUZU_USE_BUNDLED_LIBUSB) -    find_package(PkgConfig) -    if (PKG_CONFIG_FOUND AND NOT CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD") -        pkg_check_modules(LIBUSB QUIET libusb-1.0>=1.0.24) -    else() -        find_package(LibUSB) -    endif() - -    if (LIBUSB_FOUND) -        add_library(usb INTERFACE) -        target_include_directories(usb INTERFACE "${LIBUSB_INCLUDE_DIRS}") -        target_link_libraries(usb INTERFACE "${LIBUSB_LIBRARIES}") -    else() -        message(WARNING "libusb not found, falling back to externals") -        set(YUZU_USE_BUNDLED_LIBUSB ON) -    endif() -endif() -  # List of all FFmpeg components required  set(FFmpeg_COMPONENTS      avcodec diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 9740e017c..4ffafd18c 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -6,18 +6,16 @@ list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/externals/find-modules")  include(DownloadExternals)  # xbyak -if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) -    add_subdirectory(xbyak) +if ((ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) AND NOT TARGET xbyak::xbyak) +    add_subdirectory(xbyak EXCLUDE_FROM_ALL)  endif()  # Dynarmic -if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) -    if (ARCHITECTURE_arm64) -       set(DYNARMIC_FRONTENDS "A32") -    endif() +if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) AND NOT TARGET dynarmic::dynarmic)      set(DYNARMIC_NO_BUNDLED_FMT ON)      set(DYNARMIC_IGNORE_ASSERTS ON CACHE BOOL "" FORCE) -    add_subdirectory(dynarmic) +    add_subdirectory(dynarmic EXCLUDE_FROM_ALL) +    add_library(dynarmic::dynarmic ALIAS dynarmic)  endif()  # getopt @@ -29,7 +27,9 @@ endif()  add_subdirectory(glad)  # inih -add_subdirectory(inih) +if (NOT TARGET inih::INIReader) +    add_subdirectory(inih) +endif()  # mbedtls  add_subdirectory(mbedtls EXCLUDE_FROM_ALL) @@ -45,8 +45,8 @@ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12" AND CMAKE_CXX_COMPILER  endif()  # libusb -if (NOT LIBUSB_FOUND OR YUZU_USE_BUNDLED_LIBUSB) -    add_subdirectory(libusb) +if (NOT TARGET libusb::usb) +    add_subdirectory(libusb EXCLUDE_FROM_ALL)  endif()  # SDL2 @@ -67,30 +67,38 @@ if (YUZU_USE_EXTERNAL_SDL2)      endif()      set(SDL_STATIC ON)      set(SDL_SHARED OFF) +    if (APPLE) +        set(SDL_FILE ON) +    endif()      add_subdirectory(SDL EXCLUDE_FROM_ALL)  endif()  # ENet -add_subdirectory(enet) -target_include_directories(enet INTERFACE ./enet/include) +if (NOT TARGET enet::enet) +    add_subdirectory(enet EXCLUDE_FROM_ALL) +    target_include_directories(enet INTERFACE ./enet/include) +    add_library(enet::enet ALIAS enet) +endif()  # Cubeb -if(ENABLE_CUBEB) +if (ENABLE_CUBEB AND NOT TARGET cubeb::cubeb)      set(BUILD_TESTS OFF CACHE BOOL "")      add_subdirectory(cubeb EXCLUDE_FROM_ALL) +    add_library(cubeb::cubeb ALIAS cubeb)  endif()  # DiscordRPC -if (USE_DISCORD_PRESENCE) +if (USE_DISCORD_PRESENCE AND NOT TARGET DiscordRPC::discord-rpc)      add_subdirectory(discord-rpc EXCLUDE_FROM_ALL)      target_include_directories(discord-rpc INTERFACE ./discord-rpc/include) +    add_library(DiscordRPC::discord-rpc ALIAS discord-rpc)  endif()  # Sirit -add_subdirectory(sirit) +add_subdirectory(sirit EXCLUDE_FROM_ALL) -if (ENABLE_WEB_SERVICE) +if (ENABLE_WEB_SERVICE AND NOT TARGET httplib::httplib)      if (NOT WIN32)          find_package(OpenSSL 1.1)          if (OPENSSL_FOUND) @@ -118,18 +126,20 @@ if (ENABLE_WEB_SERVICE)      if (WIN32)          target_link_libraries(httplib INTERFACE crypt32 cryptui ws2_32)      endif() -	 -    # cpp-jwt +    add_library(httplib::httplib ALIAS httplib) +endif() + +# cpp-jwt +if (ENABLE_WEB_SERVICE AND NOT TARGET cpp-jwt::cpp-jwt)      add_library(cpp-jwt INTERFACE)      target_include_directories(cpp-jwt INTERFACE ./cpp-jwt/include)      target_compile_definitions(cpp-jwt INTERFACE CPP_JWT_USE_VENDORED_NLOHMANN_JSON) +    add_library(cpp-jwt::cpp-jwt ALIAS cpp-jwt)  endif()  # Opus -if (YUZU_USE_BUNDLED_OPUS) +if (NOT TARGET Opus::opus)      add_subdirectory(opus EXCLUDE_FROM_ALL) -else() -    find_package(Opus 1.3 REQUIRED)  endif()  # FFMpeg @@ -140,3 +150,8 @@ if (YUZU_USE_BUNDLED_FFMPEG)      set(FFmpeg_LIBRARIES "${FFmpeg_LIBRARIES}" PARENT_SCOPE)      set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE)  endif() + +# Vulkan-Headers +if (NOT TARGET Vulkan::Headers) +    add_subdirectory(Vulkan-Headers EXCLUDE_FROM_ALL) +endif() diff --git a/externals/SDL b/externals/SDL -Subproject b424665e0899769b200231ba943353a5fee1b6b +Subproject f17058b562c8a1090c0c996b42982721ace9090 diff --git a/externals/Vulkan-Headers b/externals/Vulkan-Headers -Subproject 33d4dd987fc8fc6475ff9ca2b4f0c3cc6e79333 +Subproject 2826791bed6a793f164bf534cd859968f13df8a diff --git a/externals/dynarmic b/externals/dynarmic -Subproject 07c614f91b0af5335e1f9c0653c2d75e7b5f53b +Subproject bd570e093ca1d1206961296b90df65cda7de8e8 diff --git a/externals/find-modules/FindDiscordRPC.cmake b/externals/find-modules/FindDiscordRPC.cmake new file mode 100644 index 000000000..44ca9904f --- /dev/null +++ b/externals/find-modules/FindDiscordRPC.cmake @@ -0,0 +1,27 @@ +# SPDX-FileCopyrightText: 2022 Alexandre Bouvier <contact@amb.tf> +# +# SPDX-License-Identifier: GPL-3.0-or-later + +find_path(DiscordRPC_INCLUDE_DIR discord_rpc.h) + +find_library(DiscordRPC_LIBRARY discord-rpc) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(DiscordRPC +    REQUIRED_VARS +        DiscordRPC_LIBRARY +        DiscordRPC_INCLUDE_DIR +) + +if (DiscordRPC_FOUND AND NOT TARGET DiscordRPC::discord-rpc) +    add_library(DiscordRPC::discord-rpc UNKNOWN IMPORTED) +    set_target_properties(DiscordRPC::discord-rpc PROPERTIES +        IMPORTED_LOCATION "${DiscordRPC_LIBRARY}" +        INTERFACE_INCLUDE_DIRECTORIES "${DiscordRPC_INCLUDE_DIR}" +    ) +endif() + +mark_as_advanced( +    DiscordRPC_INCLUDE_DIR +    DiscordRPC_LIBRARY +) diff --git a/externals/find-modules/FindLibUSB.cmake b/externals/find-modules/FindLibUSB.cmake deleted file mode 100644 index 617daf9a5..000000000 --- a/externals/find-modules/FindLibUSB.cmake +++ /dev/null @@ -1,44 +0,0 @@ -# SPDX-FileCopyrightText: 2009 Michal Cihar <michal@cihar.com> -# SPDX-License-Identifier: GPL-2.0-or-later - -# - Find libusb-1.0 library -# This module defines -#  LIBUSB_INCLUDE_DIR, where to find bluetooth.h -#  LIBUSB_LIBRARIES, the libraries needed to use libusb-1.0. -#  LIBUSB_FOUND, If false, do not try to use libusb-1.0. -# -# vim: expandtab sw=4 ts=4 sts=4: - -if(ANDROID) -       set(LIBUSB_FOUND FALSE CACHE INTERNAL "libusb-1.0 found") -       message(STATUS "libusb-1.0 not found.") -elseif (NOT LIBUSB_FOUND) -    pkg_check_modules (LIBUSB_PKG libusb-1.0) - -    find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h -       PATHS -       ${LIBUSB_PKG_INCLUDE_DIRS} -       /usr/include/libusb-1.0 -       /usr/include -       /usr/local/include/libusb-1.0 -       /usr/local/include -    ) - -    find_library(LIBUSB_LIBRARIES NAMES usb-1.0 usb -       PATHS -       ${LIBUSB_PKG_LIBRARY_DIRS} -       /usr/lib -       /usr/local/lib -    ) - -    if(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) -       set(LIBUSB_FOUND TRUE CACHE INTERNAL "libusb-1.0 found") -       message(STATUS "Found libusb-1.0: ${LIBUSB_INCLUDE_DIR}, ${LIBUSB_LIBRARIES}") -    else(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) -       set(LIBUSB_FOUND FALSE CACHE INTERNAL "libusb-1.0 found") -       message(STATUS "libusb-1.0 not found.") -    endif(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) - -    mark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES) -endif () - diff --git a/externals/find-modules/FindOpus.cmake b/externals/find-modules/FindOpus.cmake index b68a6046b..2ba515352 100644 --- a/externals/find-modules/FindOpus.cmake +++ b/externals/find-modules/FindOpus.cmake @@ -1,19 +1,17 @@  # SPDX-FileCopyrightText: 2022 yuzu Emulator Project  # SPDX-License-Identifier: GPL-2.0-or-later -find_package(PkgConfig) - +find_package(PkgConfig QUIET)  if (PKG_CONFIG_FOUND) -    pkg_search_module(opus IMPORTED_TARGET GLOBAL opus) -    if (opus_FOUND) -        add_library(Opus::opus ALIAS PkgConfig::opus) -    endif() +    pkg_search_module(OPUS QUIET IMPORTED_TARGET opus)  endif()  include(FindPackageHandleStandardArgs)  find_package_handle_standard_args(Opus -    REQUIRED_VARS -        opus_LINK_LIBRARIES -        opus_FOUND -    VERSION_VAR opus_VERSION +    REQUIRED_VARS OPUS_LINK_LIBRARIES +    VERSION_VAR OPUS_VERSION  ) + +if (Opus_FOUND AND NOT TARGET Opus::opus) +    add_library(Opus::opus ALIAS PkgConfig::OPUS) +endif() diff --git a/externals/find-modules/Findenet.cmake b/externals/find-modules/Findenet.cmake new file mode 100644 index 000000000..6dae76f4c --- /dev/null +++ b/externals/find-modules/Findenet.cmake @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2022 Alexandre Bouvier <contact@amb.tf> +# +# SPDX-License-Identifier: GPL-3.0-or-later + +find_package(PkgConfig QUIET) +if (PKG_CONFIG_FOUND) +    pkg_search_module(ENET QUIET IMPORTED_TARGET libenet) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(enet +    REQUIRED_VARS ENET_LINK_LIBRARIES +    VERSION_VAR ENET_VERSION +) + +if (enet_FOUND AND NOT TARGET enet::enet) +    add_library(enet::enet ALIAS PkgConfig::ENET) +endif() diff --git a/externals/find-modules/Findhttplib.cmake b/externals/find-modules/Findhttplib.cmake new file mode 100644 index 000000000..b72bad076 --- /dev/null +++ b/externals/find-modules/Findhttplib.cmake @@ -0,0 +1,23 @@ +# SPDX-FileCopyrightText: 2022 Andrea Pappacoda <andrea@pappacoda.it> +# +# SPDX-License-Identifier: GPL-2.0-or-later + +include(FindPackageHandleStandardArgs) + +find_package(httplib QUIET CONFIG) +if (httplib_FOUND) +    find_package_handle_standard_args(httplib CONFIG_MODE) +else() +    find_package(PkgConfig QUIET) +    if (PKG_CONFIG_FOUND) +        pkg_search_module(HTTPLIB QUIET IMPORTED_TARGET cpp-httplib) +    endif() +    find_package_handle_standard_args(httplib +        REQUIRED_VARS HTTPLIB_INCLUDEDIR +        VERSION_VAR HTTPLIB_VERSION +    ) +endif() + +if (httplib_FOUND AND NOT TARGET httplib::httplib) +    add_library(httplib::httplib ALIAS PkgConfig::HTTPLIB) +endif() diff --git a/externals/find-modules/Findinih.cmake b/externals/find-modules/Findinih.cmake new file mode 100644 index 000000000..8d1a07243 --- /dev/null +++ b/externals/find-modules/Findinih.cmake @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2022 Alexandre Bouvier <contact@amb.tf> +# +# SPDX-License-Identifier: GPL-3.0-or-later + +find_package(PkgConfig QUIET) +if (PKG_CONFIG_FOUND) +    pkg_search_module(INIREADER QUIET IMPORTED_TARGET INIReader) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(inih +    REQUIRED_VARS INIREADER_LINK_LIBRARIES +    VERSION_VAR INIREADER_VERSION +) + +if (inih_FOUND AND NOT TARGET inih::INIReader) +    add_library(inih::INIReader ALIAS PkgConfig::INIREADER) +endif() diff --git a/externals/find-modules/Findlibusb.cmake b/externals/find-modules/Findlibusb.cmake new file mode 100644 index 000000000..66f61001c --- /dev/null +++ b/externals/find-modules/Findlibusb.cmake @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2022 Alexandre Bouvier <contact@amb.tf> +# +# SPDX-License-Identifier: GPL-3.0-or-later + +find_package(PkgConfig QUIET) +if (PKG_CONFIG_FOUND) +    pkg_search_module(LIBUSB QUIET IMPORTED_TARGET libusb-1.0) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(libusb +    REQUIRED_VARS LIBUSB_LINK_LIBRARIES +    VERSION_VAR LIBUSB_VERSION +) + +if (libusb_FOUND AND NOT TARGET libusb::usb) +    add_library(libusb::usb ALIAS PkgConfig::LIBUSB) +endif() diff --git a/externals/find-modules/Findlz4.cmake b/externals/find-modules/Findlz4.cmake index 13ca5de66..f4c7005ba 100644 --- a/externals/find-modules/Findlz4.cmake +++ b/externals/find-modules/Findlz4.cmake @@ -1,19 +1,28 @@  # SPDX-FileCopyrightText: 2022 yuzu Emulator Project  # SPDX-License-Identifier: GPL-2.0-or-later -find_package(PkgConfig) +include(FindPackageHandleStandardArgs) -if (PKG_CONFIG_FOUND) -    pkg_search_module(liblz4 IMPORTED_TARGET GLOBAL liblz4) -    if (liblz4_FOUND) -        add_library(lz4::lz4 ALIAS PkgConfig::liblz4) +find_package(lz4 QUIET CONFIG) +if (lz4_FOUND) +    find_package_handle_standard_args(lz4 CONFIG_MODE) +else() +    find_package(PkgConfig QUIET) +    if (PKG_CONFIG_FOUND) +        pkg_search_module(LZ4 QUIET IMPORTED_TARGET liblz4)      endif() +    find_package_handle_standard_args(lz4 +        REQUIRED_VARS LZ4_LINK_LIBRARIES +        VERSION_VAR LZ4_VERSION +    )  endif() -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(lz4 -    REQUIRED_VARS -        liblz4_LINK_LIBRARIES -        liblz4_FOUND -    VERSION_VAR liblz4_VERSION -) +if (lz4_FOUND AND NOT TARGET lz4::lz4) +    if (TARGET LZ4::lz4_shared) +        add_library(lz4::lz4 ALIAS LZ4::lz4_shared) +    elseif (TARGET LZ4::lz4_static) +        add_library(lz4::lz4 ALIAS LZ4::lz4_static) +    else() +        add_library(lz4::lz4 ALIAS PkgConfig::LZ4) +    endif() +endif() diff --git a/externals/find-modules/Findzstd.cmake b/externals/find-modules/Findzstd.cmake index f4031eb70..1aacc41d0 100644 --- a/externals/find-modules/Findzstd.cmake +++ b/externals/find-modules/Findzstd.cmake @@ -1,19 +1,28 @@  # SPDX-FileCopyrightText: 2022 yuzu Emulator Project  # SPDX-License-Identifier: GPL-2.0-or-later -find_package(PkgConfig) +include(FindPackageHandleStandardArgs) -if (PKG_CONFIG_FOUND) -    pkg_search_module(libzstd IMPORTED_TARGET GLOBAL libzstd) -    if (libzstd_FOUND) -        add_library(zstd::zstd ALIAS PkgConfig::libzstd) +find_package(zstd QUIET CONFIG) +if (zstd_FOUND) +    find_package_handle_standard_args(zstd CONFIG_MODE) +else() +    find_package(PkgConfig QUIET) +    if (PKG_CONFIG_FOUND) +        pkg_search_module(ZSTD QUIET IMPORTED_TARGET libzstd)      endif() +    find_package_handle_standard_args(zstd +        REQUIRED_VARS ZSTD_LINK_LIBRARIES +        VERSION_VAR ZSTD_VERSION +    )  endif() -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(zstd -    REQUIRED_VARS -        libzstd_LINK_LIBRARIES -        libzstd_FOUND -    VERSION_VAR libzstd_VERSION -) +if (zstd_FOUND AND NOT TARGET zstd::zstd) +    if (TARGET zstd::libzstd_shared) +        add_library(zstd::zstd ALIAS zstd::libzstd_shared) +    elseif (TARGET zstd::libzstd_static) +        add_library(zstd::zstd ALIAS zstd::libzstd_static) +    else() +        add_library(zstd::zstd ALIAS PkgConfig::ZSTD) +    endif() +endif() diff --git a/externals/inih/CMakeLists.txt b/externals/inih/CMakeLists.txt index b686e3cf5..ebb60a976 100644 --- a/externals/inih/CMakeLists.txt +++ b/externals/inih/CMakeLists.txt @@ -9,4 +9,5 @@ add_library(inih  )  create_target_directory_groups(inih) -target_include_directories(inih INTERFACE .) +target_include_directories(inih INTERFACE inih/cpp) +add_library(inih::INIReader ALIAS inih) diff --git a/externals/libusb/CMakeLists.txt b/externals/libusb/CMakeLists.txt index 3cb1b3687..6317ea807 100644 --- a/externals/libusb/CMakeLists.txt +++ b/externals/libusb/CMakeLists.txt @@ -273,3 +273,5 @@ else() # MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux")      configure_file(config.h.in config.h)  endif() # MINGW OR (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + +add_library(libusb::usb ALIAS usb) diff --git a/externals/sirit b/externals/sirit -Subproject aa292d56650bc28f2b2d75973fab2e61d0136f9 +Subproject d7ad93a88864bda94e282e95028f90b5784e4d2 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0ac3d254e..140415474 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -82,8 +82,9 @@ if (MSVC)          /wd4324 # 'struct_name': structure was padded due to __declspec(align())      ) -    if (USE_CCACHE) +    if (USE_CCACHE OR YUZU_USE_PRECOMPILED_HEADERS)      # when caching, we need to use /Z7 to downgrade debug info to use an older but more cachable format +    # Precompiled headers are deleted if not using /Z7. See https://github.com/nanoant/CMakePCHCompiler/issues/21          add_compile_options(/Z7)      else()          add_compile_options(/Zi) @@ -112,6 +113,8 @@ else()          $<$<CXX_COMPILER_ID:Clang>:-Wno-braced-scalar-init>          $<$<CXX_COMPILER_ID:Clang>:-Wno-unused-private-field> +        $<$<CXX_COMPILER_ID:AppleClang>:-Wno-braced-scalar-init> +        $<$<CXX_COMPILER_ID:AppleClang>:-Wno-unused-private-field>      )      if (ARCHITECTURE_x86_64) diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index 75416c53a..420ba62e0 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt @@ -31,6 +31,7 @@ add_library(audio_core STATIC      out/audio_out.h      out/audio_out_system.cpp      out/audio_out_system.h +    precompiled_headers.h      renderer/adsp/adsp.cpp      renderer/adsp/adsp.h      renderer/adsp/audio_renderer.cpp @@ -218,18 +219,18 @@ endif()  target_link_libraries(audio_core PUBLIC common core)  if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) -    target_link_libraries(audio_core PRIVATE dynarmic) +    target_link_libraries(audio_core PRIVATE dynarmic::dynarmic)  endif()  if(ENABLE_CUBEB) -    target_link_libraries(audio_core PRIVATE cubeb) +    target_link_libraries(audio_core PRIVATE cubeb::cubeb)      target_compile_definitions(audio_core PRIVATE -DHAVE_CUBEB=1)  endif()  if(ENABLE_SDL2) -    if (YUZU_USE_EXTERNAL_SDL2) -        target_link_libraries(audio_core PRIVATE SDL2-static) -    else() -        target_link_libraries(audio_core PRIVATE SDL2) -    endif() +    target_link_libraries(audio_core PRIVATE SDL2::SDL2)      target_compile_definitions(audio_core PRIVATE HAVE_SDL2)  endif() + +if (YUZU_USE_PRECOMPILED_HEADERS) +    target_precompile_headers(audio_core PRIVATE precompiled_headers.h) +endif() diff --git a/src/audio_core/audio_event.cpp b/src/audio_core/audio_event.cpp index 424049c7a..d15568e1f 100644 --- a/src/audio_core/audio_event.cpp +++ b/src/audio_core/audio_event.cpp @@ -3,6 +3,7 @@  #include "audio_core/audio_event.h"  #include "common/assert.h" +#include "common/polyfill_ranges.h"  namespace AudioCore { diff --git a/src/audio_core/audio_manager.h b/src/audio_core/audio_manager.h index abf077de4..02270242a 100644 --- a/src/audio_core/audio_manager.h +++ b/src/audio_core/audio_manager.h @@ -9,6 +9,8 @@  #include <mutex>  #include <thread> +#include "common/polyfill_thread.h" +  #include "audio_core/audio_event.h"  union Result; diff --git a/src/audio_core/audio_render_manager.h b/src/audio_core/audio_render_manager.h index bf4837190..fffa5944d 100644 --- a/src/audio_core/audio_render_manager.h +++ b/src/audio_core/audio_render_manager.h @@ -7,6 +7,8 @@  #include <memory>  #include <mutex> +#include "common/polyfill_thread.h" +  #include "audio_core/common/common.h"  #include "audio_core/renderer/system_manager.h"  #include "core/hle/service/audio/errors.h" diff --git a/src/audio_core/common/feature_support.h b/src/audio_core/common/feature_support.h index 55c9e690d..e71905ae8 100644 --- a/src/audio_core/common/feature_support.h +++ b/src/audio_core/common/feature_support.h @@ -10,6 +10,7 @@  #include "common/assert.h"  #include "common/common_funcs.h"  #include "common/common_types.h" +#include "common/polyfill_ranges.h"  namespace AudioCore {  constexpr u32 CurrentRevision = 11; diff --git a/src/audio_core/precompiled_headers.h b/src/audio_core/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/audio_core/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp b/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp index c4bf3943a..2187d8a65 100644 --- a/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp +++ b/src/audio_core/renderer/command/effect/i3dl2_reverb.cpp @@ -5,6 +5,7 @@  #include "audio_core/renderer/adsp/command_list_processor.h"  #include "audio_core/renderer/command/effect/i3dl2_reverb.h" +#include "common/polyfill_ranges.h"  namespace AudioCore::AudioRenderer { diff --git a/src/audio_core/renderer/command/effect/reverb.cpp b/src/audio_core/renderer/command/effect/reverb.cpp index fe2b1eb43..427489214 100644 --- a/src/audio_core/renderer/command/effect/reverb.cpp +++ b/src/audio_core/renderer/command/effect/reverb.cpp @@ -6,6 +6,7 @@  #include "audio_core/renderer/adsp/command_list_processor.h"  #include "audio_core/renderer/command/effect/reverb.h" +#include "common/polyfill_ranges.h"  namespace AudioCore::AudioRenderer { diff --git a/src/audio_core/renderer/mix/mix_context.cpp b/src/audio_core/renderer/mix/mix_context.cpp index 2427c83ed..35b748ede 100644 --- a/src/audio_core/renderer/mix/mix_context.cpp +++ b/src/audio_core/renderer/mix/mix_context.cpp @@ -5,6 +5,7 @@  #include "audio_core/renderer/mix/mix_context.h"  #include "audio_core/renderer/splitter/splitter_context.h" +#include "common/polyfill_ranges.h"  namespace AudioCore::AudioRenderer { diff --git a/src/audio_core/renderer/voice/voice_context.cpp b/src/audio_core/renderer/voice/voice_context.cpp index a501a677d..16a3e839d 100644 --- a/src/audio_core/renderer/voice/voice_context.cpp +++ b/src/audio_core/renderer/voice/voice_context.cpp @@ -4,6 +4,7 @@  #include <ranges>  #include "audio_core/renderer/voice/voice_context.h" +#include "common/polyfill_ranges.h"  namespace AudioCore::AudioRenderer { diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp index 67e194e3c..06c2a876e 100644 --- a/src/audio_core/sink/sink_stream.cpp +++ b/src/audio_core/sink/sink_stream.cpp @@ -170,8 +170,8 @@ void SinkStream::ProcessAudioIn(std::span<const s16> input_buffer, std::size_t n          // Get the minimum frames available between the currently playing buffer, and the          // amount we have left to fill -        size_t frames_available{std::min(playing_buffer.frames - playing_buffer.frames_played, -                                         num_frames - frames_written)}; +        size_t frames_available{std::min<u64>(playing_buffer.frames - playing_buffer.frames_played, +                                              num_frames - frames_written)};          samples_buffer.Push(&input_buffer[frames_written * frame_size],                              frames_available * frame_size); @@ -241,8 +241,8 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz          // Get the minimum frames available between the currently playing buffer, and the          // amount we have left to fill -        size_t frames_available{std::min(playing_buffer.frames - playing_buffer.frames_played, -                                         num_frames - frames_written)}; +        size_t frames_available{std::min<u64>(playing_buffer.frames - playing_buffer.frames_played, +                                              num_frames - frames_written)};          samples_buffer.Pop(&output_buffer[frames_written * frame_size],                             frames_available * frame_size); diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index b7c15c191..6bdffcb7a 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -37,6 +37,7 @@ add_library(common STATIC      cache_management.cpp      cache_management.h      common_funcs.h +    common_precompiled_headers.h      common_types.h      concepts.h      div_ceil.h @@ -95,6 +96,7 @@ add_library(common STATIC      param_package.h      parent_of_member.h      point.h +    precompiled_headers.h      quaternion.h      reader_writer_queue.h      ring_buffer.h @@ -147,7 +149,7 @@ if(ARCHITECTURE_x86_64)              x64/xbyak_abi.h              x64/xbyak_util.h      ) -    target_link_libraries(common PRIVATE xbyak) +    target_link_libraries(common PRIVATE xbyak::xbyak)  endif()  if (MSVC) @@ -172,14 +174,8 @@ endif()  create_target_directory_groups(common)  target_link_libraries(common PUBLIC ${Boost_LIBRARIES} fmt::fmt microprofile Threads::Threads) -if (TARGET lz4::lz4) -  target_link_libraries(common PRIVATE lz4::lz4) -else() -  target_link_libraries(common PRIVATE LZ4::lz4_shared) -endif() -if (TARGET zstd::zstd) -  target_link_libraries(common PRIVATE zstd::zstd) -else() -  target_link_libraries(common PRIVATE -    $<IF:$<TARGET_EXISTS:zstd::libzstd_shared>,zstd::libzstd_shared,zstd::libzstd_static>) +target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd) + +if (YUZU_USE_PRECOMPILED_HEADERS) +    target_precompile_headers(common PRIVATE precompiled_headers.h)  endif() diff --git a/src/common/common_precompiled_headers.h b/src/common/common_precompiled_headers.h new file mode 100644 index 000000000..be7e5b5f9 --- /dev/null +++ b/src/common/common_precompiled_headers.h @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <algorithm> +#include <array> +#include <chrono> +#include <memory> + +#include <fmt/format.h> + +#include "common/assert.h" +#include "common/common_types.h" diff --git a/src/common/fs/file.cpp b/src/common/fs/file.cpp index fa8422c41..656b03cc5 100644 --- a/src/common/fs/file.cpp +++ b/src/common/fs/file.cpp @@ -1,6 +1,8 @@  // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project  // SPDX-License-Identifier: GPL-2.0-or-later +#include <vector> +  #include "common/fs/file.h"  #include "common/fs/fs.h"  #include "common/logging/log.h" diff --git a/src/common/fs/fs_util.cpp b/src/common/fs/fs_util.cpp index eb4ac1deb..813a713c3 100644 --- a/src/common/fs/fs_util.cpp +++ b/src/common/fs/fs_util.cpp @@ -4,6 +4,7 @@  #include <algorithm>  #include "common/fs/fs_util.h" +#include "common/polyfill_ranges.h"  namespace Common::FS { diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index 1074f2421..defa3e918 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp @@ -2,6 +2,7 @@  // SPDX-License-Identifier: GPL-2.0-or-later  #include <algorithm> +#include <sstream>  #include <unordered_map>  #include "common/fs/fs.h" diff --git a/src/common/input.h b/src/common/input.h index 449e0193f..fc14fd7bf 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -8,6 +8,7 @@  #include <string>  #include <unordered_map>  #include <utility> +#include <vector>  #include "common/logging/log.h"  #include "common/param_package.h"  #include "common/uuid.h" diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 15d92505e..2a3bded40 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -4,7 +4,6 @@  #include <atomic>  #include <chrono>  #include <climits> -#include <stop_token>  #include <thread>  #include <fmt/format.h> @@ -18,6 +17,7 @@  #include "common/fs/fs_paths.h"  #include "common/fs/path_util.h"  #include "common/literals.h" +#include "common/polyfill_thread.h"  #include "common/thread.h"  #include "common/logging/backend.h" diff --git a/src/common/polyfill_ranges.h b/src/common/polyfill_ranges.h new file mode 100644 index 000000000..ca44bfaef --- /dev/null +++ b/src/common/polyfill_ranges.h @@ -0,0 +1,530 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +// +// TODO: remove this file when ranges are supported by all compilation targets +// + +#pragma once + +#include <algorithm> +#include <utility> +#include <version> + +#ifndef __cpp_lib_ranges + +namespace std { +namespace ranges { + +template <typename T> +concept range = requires(T& t) { +    begin(t); +    end(t); +}; + +template <typename T> +concept input_range = range<T>; + +template <typename T> +concept output_range = range<T>; + +template <range R> +using range_difference_t = ptrdiff_t; + +// +// find, find_if, find_if_not +// + +struct find_fn { +    template <typename Iterator, typename T, typename Proj = std::identity> +    constexpr Iterator operator()(Iterator first, Iterator last, const T& value, +                                  Proj proj = {}) const { +        for (; first != last; ++first) { +            if (std::invoke(proj, *first) == value) { +                return first; +            } +        } +        return first; +    } + +    template <ranges::input_range R, typename T, typename Proj = std::identity> +    constexpr ranges::iterator_t<R> operator()(R&& r, const T& value, Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), value, std::ref(proj)); +    } +}; + +struct find_if_fn { +    template <typename Iterator, typename Proj = std::identity, typename Pred> +    constexpr Iterator operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const { +        for (; first != last; ++first) { +            if (std::invoke(pred, std::invoke(proj, *first))) { +                return first; +            } +        } +        return first; +    } + +    template <ranges::input_range R, typename Proj = std::identity, typename Pred> +    constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj)); +    } +}; + +struct find_if_not_fn { +    template <typename Iterator, typename Proj = std::identity, typename Pred> +    constexpr Iterator operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const { +        for (; first != last; ++first) { +            if (!std::invoke(pred, std::invoke(proj, *first))) { +                return first; +            } +        } +        return first; +    } + +    template <ranges::input_range R, typename Proj = std::identity, typename Pred> +    constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj)); +    } +}; + +inline constexpr find_fn find; +inline constexpr find_if_fn find_if; +inline constexpr find_if_not_fn find_if_not; + +// +// any_of, all_of, none_of +// + +struct all_of_fn { +    template <typename Iterator, typename Proj = std::identity, typename Pred> +    constexpr bool operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const { +        return ranges::find_if_not(first, last, std::ref(pred), std::ref(proj)) == last; +    } + +    template <ranges::input_range R, typename Proj = std::identity, typename Pred> +    constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj)); +    } +}; + +struct any_of_fn { +    template <typename Iterator, typename Proj = std::identity, typename Pred> +    constexpr bool operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const { +        return ranges::find_if(first, last, std::ref(pred), std::ref(proj)) != last; +    } + +    template <ranges::input_range R, typename Proj = std::identity, typename Pred> +    constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj)); +    } +}; + +struct none_of_fn { +    template <typename Iterator, typename Proj = std::identity, typename Pred> +    constexpr bool operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const { +        return ranges::find_if(first, last, std::ref(pred), std::ref(proj)) == last; +    } + +    template <ranges::input_range R, typename Proj = std::identity, typename Pred> +    constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj)); +    } +}; + +inline constexpr any_of_fn any_of; +inline constexpr all_of_fn all_of; +inline constexpr none_of_fn none_of; + +// +// count, count_if +// + +struct count_fn { +    template <typename Iterator, typename T, typename Proj = std::identity> +    constexpr ptrdiff_t operator()(Iterator first, Iterator last, const T& value, +                                   Proj proj = {}) const { +        ptrdiff_t counter = 0; +        for (; first != last; ++first) +            if (std::invoke(proj, *first) == value) +                ++counter; +        return counter; +    } + +    template <ranges::input_range R, typename T, typename Proj = std::identity> +    constexpr ptrdiff_t operator()(R&& r, const T& value, Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), value, std::ref(proj)); +    } +}; + +struct count_if_fn { +    template <typename Iterator, typename Proj = std::identity, typename Pred> +    constexpr ptrdiff_t operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const { +        ptrdiff_t counter = 0; +        for (; first != last; ++first) +            if (std::invoke(pred, std::invoke(proj, *first))) +                ++counter; +        return counter; +    } + +    template <ranges::input_range R, typename Proj = std::identity, typename Pred> +    constexpr ptrdiff_t operator()(R&& r, Pred pred, Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj)); +    } +}; + +inline constexpr count_fn count; +inline constexpr count_if_fn count_if; + +// +// transform +// + +struct transform_fn { +    template <typename InputIterator, typename OutputIterator, typename F, +              typename Proj = std::identity> +    constexpr void operator()(InputIterator first1, InputIterator last1, OutputIterator result, +                              F op, Proj proj = {}) const { +        for (; first1 != last1; ++first1, (void)++result) { +            *result = std::invoke(op, std::invoke(proj, *first1)); +        } +    } + +    template <ranges::input_range R, typename OutputIterator, typename F, +              typename Proj = std::identity> +    constexpr void operator()(R&& r, OutputIterator result, F op, Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), result, std::ref(op), std::ref(proj)); +    } +}; + +inline constexpr transform_fn transform; + +// +// sort +// + +struct sort_fn { +    template <typename Iterator, typename Comp = ranges::less, typename Proj = std::identity> +    constexpr void operator()(Iterator first, Iterator last, Comp comp = {}, Proj proj = {}) const { +        if (first == last) +            return; + +        Iterator last_iter = ranges::next(first, last); +        std::sort(first, last_iter, +                  [&](auto& lhs, auto& rhs) { return comp(proj(lhs), proj(rhs)); }); +    } + +    template <ranges::input_range R, typename Comp = ranges::less, typename Proj = std::identity> +    constexpr void operator()(R&& r, Comp comp = {}, Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), std::move(comp), std::move(proj)); +    } +}; + +inline constexpr sort_fn sort; + +// +// fill +// + +struct fill_fn { +    template <typename T, typename OutputIterator> +    constexpr OutputIterator operator()(OutputIterator first, OutputIterator last, +                                        const T& value) const { +        while (first != last) { +            *first++ = value; +        } + +        return first; +    } + +    template <typename T, ranges::output_range R> +    constexpr ranges::iterator_t<R> operator()(R&& r, const T& value) const { +        return operator()(ranges::begin(r), ranges::end(r), value); +    } +}; + +inline constexpr fill_fn fill; + +// +// for_each +// + +struct for_each_fn { +    template <typename Iterator, typename Proj = std::identity, typename Fun> +    constexpr void operator()(Iterator first, Iterator last, Fun f, Proj proj = {}) const { +        for (; first != last; ++first) { +            std::invoke(f, std::invoke(proj, *first)); +        } +    } + +    template <ranges::input_range R, typename Proj = std::identity, typename Fun> +    constexpr void operator()(R&& r, Fun f, Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), std::move(f), std::ref(proj)); +    } +}; + +inline constexpr for_each_fn for_each; + +// +// min_element, max_element +// + +struct min_element_fn { +    template <typename Iterator, typename Proj = std::identity, typename Comp = ranges::less> +    constexpr Iterator operator()(Iterator first, Iterator last, Comp comp = {}, +                                  Proj proj = {}) const { +        if (first == last) { +            return last; +        } + +        auto smallest = first; +        ++first; +        for (; first != last; ++first) { +            if (!std::invoke(comp, std::invoke(proj, *smallest), std::invoke(proj, *first))) { +                smallest = first; +            } +        } +        return smallest; +    } + +    template <ranges::input_range R, typename Proj = std::identity, typename Comp = ranges::less> +    constexpr ranges::iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), std::ref(comp), std::ref(proj)); +    } +}; + +struct max_element_fn { +    template <typename Iterator, typename Proj = std::identity, typename Comp = ranges::less> +    constexpr Iterator operator()(Iterator first, Iterator last, Comp comp = {}, +                                  Proj proj = {}) const { +        if (first == last) { +            return last; +        } + +        auto largest = first; +        ++first; +        for (; first != last; ++first) { +            if (std::invoke(comp, std::invoke(proj, *largest), std::invoke(proj, *first))) { +                largest = first; +            } +        } +        return largest; +    } + +    template <ranges::input_range R, typename Proj = std::identity, typename Comp = ranges::less> +    constexpr ranges::iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), std::ref(comp), std::ref(proj)); +    } +}; + +inline constexpr min_element_fn min_element; +inline constexpr max_element_fn max_element; + +// +// replace, replace_if +// + +struct replace_fn { +    template <typename Iterator, typename T1, typename T2, typename Proj = std::identity> +    constexpr Iterator operator()(Iterator first, Iterator last, const T1& old_value, +                                  const T2& new_value, Proj proj = {}) const { +        for (; first != last; ++first) { +            if (old_value == std::invoke(proj, *first)) { +                *first = new_value; +            } +        } +        return first; +    } + +    template <ranges::input_range R, typename T1, typename T2, typename Proj = std::identity> +    constexpr ranges::iterator_t<R> operator()(R&& r, const T1& old_value, const T2& new_value, +                                               Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), old_value, new_value, std::move(proj)); +    } +}; + +struct replace_if_fn { +    template <typename Iterator, typename T, typename Proj = std::identity, typename Pred> +    constexpr Iterator operator()(Iterator first, Iterator last, Pred pred, const T& new_value, +                                  Proj proj = {}) const { +        for (; first != last; ++first) { +            if (!!std::invoke(pred, std::invoke(proj, *first))) { +                *first = new_value; +            } +        } +        return std::move(first); +    } + +    template <ranges::input_range R, typename T, typename Proj = std::identity, typename Pred> +    constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred, const T& new_value, +                                               Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), std::move(pred), new_value, +                          std::move(proj)); +    } +}; + +inline constexpr replace_fn replace; +inline constexpr replace_if_fn replace_if; + +// +// copy, copy_if +// + +struct copy_fn { +    template <typename InputIterator, typename OutputIterator> +    constexpr void operator()(InputIterator first, InputIterator last, +                              OutputIterator result) const { +        for (; first != last; ++first, (void)++result) { +            *result = *first; +        } +    } + +    template <ranges::input_range R, typename OutputIterator> +    constexpr void operator()(R&& r, OutputIterator result) const { +        return operator()(ranges::begin(r), ranges::end(r), std::move(result)); +    } +}; + +struct copy_if_fn { +    template <typename InputIterator, typename OutputIterator, typename Proj = std::identity, +              typename Pred> +    constexpr void operator()(InputIterator first, InputIterator last, OutputIterator result, +                              Pred pred, Proj proj = {}) const { +        for (; first != last; ++first) { +            if (std::invoke(pred, std::invoke(proj, *first))) { +                *result = *first; +                ++result; +            } +        } +    } + +    template <ranges::input_range R, typename OutputIterator, typename Proj = std::identity, +              typename Pred> +    constexpr void operator()(R&& r, OutputIterator result, Pred pred, Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), std::move(result), std::ref(pred), +                          std::ref(proj)); +    } +}; + +inline constexpr copy_fn copy; +inline constexpr copy_if_fn copy_if; + +// +// generate +// + +struct generate_fn { +    template <typename Iterator, typename F> +    constexpr Iterator operator()(Iterator first, Iterator last, F gen) const { +        for (; first != last; *first = std::invoke(gen), ++first) +            ; +        return first; +    } + +    template <typename R, std::copy_constructible F> +    requires std::invocable<F&> && ranges::output_range<R> +    constexpr ranges::iterator_t<R> operator()(R&& r, F gen) const { +        return operator()(ranges::begin(r), ranges::end(r), std::move(gen)); +    } +}; + +inline constexpr generate_fn generate; + +// +// lower_bound, upper_bound +// + +struct lower_bound_fn { +    template <typename Iterator, typename T, typename Proj = std::identity, +              typename Comp = ranges::less> +    constexpr Iterator operator()(Iterator first, Iterator last, const T& value, Comp comp = {}, +                                  Proj proj = {}) const { +        Iterator it; +        std::ptrdiff_t _count, _step; +        _count = std::distance(first, last); + +        while (_count > 0) { +            it = first; +            _step = _count / 2; +            ranges::advance(it, _step, last); +            if (comp(std::invoke(proj, *it), value)) { +                first = ++it; +                _count -= _step + 1; +            } else { +                _count = _step; +            } +        } +        return first; +    } + +    template <ranges::input_range R, typename T, typename Proj = std::identity, +              typename Comp = ranges::less> +    constexpr ranges::iterator_t<R> operator()(R&& r, const T& value, Comp comp = {}, +                                               Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), value, std::ref(comp), std::ref(proj)); +    } +}; + +struct upper_bound_fn { +    template <typename Iterator, typename T, typename Proj = std::identity, +              typename Comp = ranges::less> +    constexpr Iterator operator()(Iterator first, Iterator last, const T& value, Comp comp = {}, +                                  Proj proj = {}) const { +        Iterator it; +        std::ptrdiff_t _count, _step; +        _count = std::distance(first, last); + +        while (_count > 0) { +            it = first; +            _step = _count / 2; +            ranges::advance(it, _step, last); +            if (!comp(value, std::invoke(proj, *it))) { +                first = ++it; +                _count -= _step + 1; +            } else { +                _count = _step; +            } +        } +        return first; +    } + +    template <ranges::input_range R, typename T, typename Proj = std::identity, +              typename Comp = ranges::less> +    constexpr ranges::iterator_t<R> operator()(R&& r, const T& value, Comp comp = {}, +                                               Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), value, std::ref(comp), std::ref(proj)); +    } +}; + +inline constexpr lower_bound_fn lower_bound; +inline constexpr upper_bound_fn upper_bound; + +// +// adjacent_find +// + +struct adjacent_find_fn { +    template <typename Iterator, typename Proj = std::identity, typename Pred = ranges::equal_to> +    constexpr Iterator operator()(Iterator first, Iterator last, Pred pred = {}, +                                  Proj proj = {}) const { +        if (first == last) +            return first; +        auto _next = ranges::next(first); +        for (; _next != last; ++_next, ++first) +            if (std::invoke(pred, std::invoke(proj, *first), std::invoke(proj, *_next))) +                return first; +        return _next; +    } + +    template <ranges::input_range R, typename Proj = std::identity, +              typename Pred = ranges::equal_to> +    constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred = {}, Proj proj = {}) const { +        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj)); +    } +}; + +inline constexpr adjacent_find_fn adjacent_find; + +} // namespace ranges +} // namespace std + +#endif diff --git a/src/common/polyfill_thread.h b/src/common/polyfill_thread.h new file mode 100644 index 000000000..5a8d1ce08 --- /dev/null +++ b/src/common/polyfill_thread.h @@ -0,0 +1,323 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +// +// TODO: remove this file when jthread is supported by all compilation targets +// + +#pragma once + +#include <version> + +#ifdef __cpp_lib_jthread + +#include <stop_token> +#include <thread> + +namespace Common { + +template <typename Condvar, typename Lock, typename Pred> +void CondvarWait(Condvar& cv, Lock& lock, std::stop_token token, Pred&& pred) { +    cv.wait(lock, token, std::move(pred)); +} + +} // namespace Common + +#else + +#include <atomic> +#include <functional> +#include <list> +#include <memory> +#include <mutex> +#include <optional> +#include <thread> +#include <type_traits> + +namespace std { +namespace polyfill { + +using stop_state_callbacks = list<function<void()>>; + +class stop_state { +public: +    stop_state() = default; +    ~stop_state() = default; + +    bool request_stop() { +        stop_state_callbacks callbacks; + +        { +            scoped_lock lk{m_lock}; + +            if (m_stop_requested.load()) { +                // Already set, nothing to do +                return false; +            } + +            // Set as requested +            m_stop_requested = true; + +            // Copy callback list +            callbacks = m_callbacks; +        } + +        for (auto callback : callbacks) { +            callback(); +        } + +        return true; +    } + +    bool stop_requested() const { +        return m_stop_requested.load(); +    } + +    stop_state_callbacks::const_iterator insert_callback(function<void()> f) { +        stop_state_callbacks::const_iterator ret{}; +        bool should_run{}; + +        { +            scoped_lock lk{m_lock}; +            should_run = m_stop_requested.load(); +            m_callbacks.push_front(f); +            ret = m_callbacks.begin(); +        } + +        if (should_run) { +            f(); +        } + +        return ret; +    } + +    void remove_callback(stop_state_callbacks::const_iterator it) { +        scoped_lock lk{m_lock}; +        m_callbacks.erase(it); +    } + +private: +    mutex m_lock; +    atomic<bool> m_stop_requested; +    stop_state_callbacks m_callbacks; +}; + +} // namespace polyfill + +class stop_token; +class stop_source; +struct nostopstate_t { +    explicit nostopstate_t() = default; +}; +inline constexpr nostopstate_t nostopstate{}; + +template <class Callback> +class stop_callback; + +class stop_token { +public: +    stop_token() noexcept = default; + +    stop_token(const stop_token&) noexcept = default; +    stop_token(stop_token&&) noexcept = default; +    stop_token& operator=(const stop_token&) noexcept = default; +    stop_token& operator=(stop_token&&) noexcept = default; +    ~stop_token() = default; + +    void swap(stop_token& other) noexcept { +        m_stop_state.swap(other.m_stop_state); +    } + +    [[nodiscard]] bool stop_requested() const noexcept { +        return m_stop_state && m_stop_state->stop_requested(); +    } +    [[nodiscard]] bool stop_possible() const noexcept { +        return m_stop_state != nullptr; +    } + +private: +    friend class stop_source; +    template <typename Callback> +    friend class stop_callback; +    stop_token(shared_ptr<polyfill::stop_state> stop_state) : m_stop_state(move(stop_state)) {} + +private: +    shared_ptr<polyfill::stop_state> m_stop_state; +}; + +class stop_source { +public: +    stop_source() : m_stop_state(make_shared<polyfill::stop_state>()) {} +    explicit stop_source(nostopstate_t) noexcept {} + +    stop_source(const stop_source&) noexcept = default; +    stop_source(stop_source&&) noexcept = default; +    stop_source& operator=(const stop_source&) noexcept = default; +    stop_source& operator=(stop_source&&) noexcept = default; +    ~stop_source() = default; +    void swap(stop_source& other) noexcept { +        m_stop_state.swap(other.m_stop_state); +    } + +    [[nodiscard]] stop_token get_token() const noexcept { +        return stop_token(m_stop_state); +    } +    [[nodiscard]] bool stop_possible() const noexcept { +        return m_stop_state != nullptr; +    } +    [[nodiscard]] bool stop_requested() const noexcept { +        return m_stop_state && m_stop_state->stop_requested(); +    } +    bool request_stop() noexcept { +        return m_stop_state && m_stop_state->request_stop(); +    } + +private: +    friend class jthread; +    explicit stop_source(shared_ptr<polyfill::stop_state> stop_state) +        : m_stop_state(move(stop_state)) {} + +private: +    shared_ptr<polyfill::stop_state> m_stop_state; +}; + +template <typename Callback> +class stop_callback { +    static_assert(is_nothrow_destructible_v<Callback>); +    static_assert(is_invocable_v<Callback>); + +public: +    using callback_type = Callback; + +    template <typename C> +    requires constructible_from<Callback, C> +    explicit stop_callback(const stop_token& st, +                           C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>) +        : m_stop_state(st.m_stop_state) { +        if (m_stop_state) { +            m_callback = m_stop_state->insert_callback(move(cb)); +        } +    } +    template <typename C> +    requires constructible_from<Callback, C> +    explicit stop_callback(stop_token&& st, +                           C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>) +        : m_stop_state(move(st.m_stop_state)) { +        if (m_stop_state) { +            m_callback = m_stop_state->insert_callback(move(cb)); +        } +    } +    ~stop_callback() { +        if (m_stop_state && m_callback) { +            m_stop_state->remove_callback(*m_callback); +        } +    } + +    stop_callback(const stop_callback&) = delete; +    stop_callback(stop_callback&&) = delete; +    stop_callback& operator=(const stop_callback&) = delete; +    stop_callback& operator=(stop_callback&&) = delete; + +private: +    shared_ptr<polyfill::stop_state> m_stop_state; +    optional<polyfill::stop_state_callbacks::const_iterator> m_callback; +}; + +template <typename Callback> +stop_callback(stop_token, Callback) -> stop_callback<Callback>; + +class jthread { +public: +    using id = thread::id; +    using native_handle_type = thread::native_handle_type; + +    jthread() noexcept = default; + +    template <typename F, typename... Args, +              typename = enable_if_t<!is_same_v<remove_cvref_t<F>, jthread>>> +    explicit jthread(F&& f, Args&&... args) +        : m_stop_state(make_shared<polyfill::stop_state>()), +          m_thread(make_thread(move(f), move(args)...)) {} + +    ~jthread() { +        if (joinable()) { +            request_stop(); +            join(); +        } +    } + +    jthread(const jthread&) = delete; +    jthread(jthread&&) noexcept = default; +    jthread& operator=(const jthread&) = delete; + +    jthread& operator=(jthread&& other) noexcept { +        m_thread.swap(other.m_thread); +        m_stop_state.swap(other.m_stop_state); +        return *this; +    } + +    void swap(jthread& other) noexcept { +        m_thread.swap(other.m_thread); +        m_stop_state.swap(other.m_stop_state); +    } +    [[nodiscard]] bool joinable() const noexcept { +        return m_thread.joinable(); +    } +    void join() { +        m_thread.join(); +    } +    void detach() { +        m_thread.detach(); +        m_stop_state.reset(); +    } + +    [[nodiscard]] id get_id() const noexcept { +        return m_thread.get_id(); +    } +    [[nodiscard]] native_handle_type native_handle() { +        return m_thread.native_handle(); +    } +    [[nodiscard]] stop_source get_stop_source() noexcept { +        return stop_source(m_stop_state); +    } +    [[nodiscard]] stop_token get_stop_token() const noexcept { +        return stop_source(m_stop_state).get_token(); +    } +    bool request_stop() noexcept { +        return get_stop_source().request_stop(); +    } +    [[nodiscard]] static unsigned int hardware_concurrency() noexcept { +        return thread::hardware_concurrency(); +    } + +private: +    template <typename F, typename... Args> +    thread make_thread(F&& f, Args&&... args) { +        if constexpr (is_invocable_v<decay_t<F>, stop_token, decay_t<Args>...>) { +            return thread(move(f), get_stop_token(), move(args)...); +        } else { +            return thread(move(f), move(args)...); +        } +    } + +    shared_ptr<polyfill::stop_state> m_stop_state; +    thread m_thread; +}; + +} // namespace std + +namespace Common { + +template <typename Condvar, typename Lock, typename Pred> +void CondvarWait(Condvar& cv, Lock& lock, std::stop_token token, Pred pred) { +    if (token.stop_requested()) { +        return; +    } + +    std::stop_callback callback(token, [&] { cv.notify_all(); }); +    cv.wait(lock, [&] { return pred() || token.stop_requested(); }); +} + +} // namespace Common + +#endif diff --git a/src/common/precompiled_headers.h b/src/common/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/common/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/common/settings.h b/src/common/settings.h index c29d6f98b..29b730cff 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -19,6 +19,7 @@ namespace Settings {  enum class RendererBackend : u32 {      OpenGL = 0,      Vulkan = 1, +    Null = 2,  };  enum class ShaderBackend : u32 { @@ -412,7 +413,7 @@ struct Values {      // Renderer      SwitchableSetting<RendererBackend, true> renderer_backend{ -        RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"}; +        RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null, "backend"};      Setting<bool> renderer_debug{false, "debug"};      Setting<bool> renderer_shader_feedback{false, "shader_feedback"};      Setting<bool> enable_nsight_aftermath{false, "nsight_aftermath"}; diff --git a/src/common/settings_input.h b/src/common/settings_input.h index 485e4ad22..46f38c703 100644 --- a/src/common/settings_input.h +++ b/src/common/settings_input.h @@ -391,6 +391,7 @@ struct PlayerInput {      u32 body_color_right;      u32 button_color_left;      u32 button_color_right; +    std::string profile_name;  };  struct TouchscreenInput { diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 7a495bc79..b26db4796 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -141,7 +141,7 @@ static std::wstring CPToUTF16(u32 code_page, const std::string& input) {          MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), nullptr, 0);      if (size == 0) { -        return L""; +        return {};      }      std::wstring output(size, L'\0'); @@ -158,7 +158,7 @@ std::string UTF16ToUTF8(const std::wstring& input) {      const auto size = WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()),                                            nullptr, 0, nullptr, nullptr);      if (size == 0) { -        return ""; +        return {};      }      std::string output(size, '\0'); diff --git a/src/common/thread_worker.h b/src/common/thread_worker.h index 62c60f724..260ad44e4 100644 --- a/src/common/thread_worker.h +++ b/src/common/thread_worker.h @@ -7,13 +7,13 @@  #include <condition_variable>  #include <functional>  #include <mutex> -#include <stop_token>  #include <string>  #include <thread>  #include <type_traits>  #include <vector>  #include <queue> +#include "common/polyfill_thread.h"  #include "common/thread.h"  #include "common/unique_function.h" @@ -47,7 +47,8 @@ public:                          if (requests.empty()) {                              wait_condition.notify_all();                          } -                        condition.wait(lock, stop_token, [this] { return !requests.empty(); }); +                        Common::CondvarWait(condition, lock, stop_token, +                                            [this] { return !requests.empty(); });                          if (stop_token.stop_requested()) {                              break;                          } diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h index 053798e79..2ef1da064 100644 --- a/src/common/threadsafe_queue.h +++ b/src/common/threadsafe_queue.h @@ -12,6 +12,8 @@  #include <mutex>  #include <utility> +#include "common/polyfill_thread.h" +  namespace Common {  template <typename T, bool with_stop_token = false>  class SPSCQueue { @@ -97,7 +99,7 @@ public:      T PopWait(std::stop_token stop_token) {          if (Empty()) {              std::unique_lock lock{cv_mutex}; -            cv.wait(lock, stop_token, [this] { return !Empty(); }); +            Common::CondvarWait(cv, lock, stop_token, [this] { return !Empty(); });          }          if (stop_token.stop_requested()) {              return T{}; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 5629980d9..c6b5ac196 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -528,6 +528,8 @@ add_library(core STATIC      hle/service/mnpp/mnpp_app.h      hle/service/ncm/ncm.cpp      hle/service/ncm/ncm.h +    hle/service/nfc/mifare_user.cpp +    hle/service/nfc/mifare_user.h      hle/service/nfc/nfc.cpp      hle/service/nfc/nfc.h      hle/service/nfc/nfc_device.cpp @@ -771,6 +773,7 @@ add_library(core STATIC      memory.h      perf_stats.cpp      perf_stats.h +    precompiled_headers.h      reporter.cpp      reporter.h      telemetry_session.cpp @@ -823,5 +826,9 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)          hle/service/jit/jit.cpp          hle/service/jit/jit.h      ) -    target_link_libraries(core PRIVATE dynarmic) +    target_link_libraries(core PRIVATE dynarmic::dynarmic) +endif() + +if (YUZU_USE_PRECOMPILED_HEADERS) +    target_precompile_headers(core PRIVATE precompiled_headers.h)  endif() diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index 95ea3ef39..374367468 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h @@ -10,6 +10,7 @@  #include <thread>  #include "common/fiber.h" +#include "common/polyfill_thread.h"  #include "common/thread.h"  #include "core/hardware_properties.h" diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp index 1a8e02e6a..a9675df76 100644 --- a/src/core/debugger/debugger.cpp +++ b/src/core/debugger/debugger.cpp @@ -9,6 +9,7 @@  #include <boost/process/async_pipe.hpp>  #include "common/logging/log.h" +#include "common/polyfill_thread.h"  #include "common/thread.h"  #include "core/core.h"  #include "core/debugger/debugger.h" diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index 78e56bbbd..50303fe42 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp @@ -7,6 +7,7 @@  #include <utility>  #include "common/logging/log.h" +#include "common/polyfill_ranges.h"  #include "core/crypto/aes_util.h"  #include "core/crypto/ctr_encryption_layer.h"  #include "core/crypto/key_manager.h" diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index 6c230f619..52919484e 100644 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp @@ -16,7 +16,7 @@ DefaultControllerApplet::DefaultControllerApplet(HID::HIDCore& hid_core_) : hid_  DefaultControllerApplet::~DefaultControllerApplet() = default; -void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callback, +void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callback,                                                       const ControllerParameters& parameters) const {      LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!"); diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h index 1d2850ad5..adb2feefd 100644 --- a/src/core/frontend/applets/controller.h +++ b/src/core/frontend/applets/controller.h @@ -4,6 +4,7 @@  #pragma once  #include <functional> +#include <vector>  #include "common/common_types.h" @@ -35,9 +36,11 @@ struct ControllerParameters {  class ControllerApplet {  public: +    using ReconfigureCallback = std::function<void()>; +      virtual ~ControllerApplet(); -    virtual void ReconfigureControllers(std::function<void()> callback, +    virtual void ReconfigureControllers(ReconfigureCallback callback,                                          const ControllerParameters& parameters) const = 0;  }; @@ -46,7 +49,7 @@ public:      explicit DefaultControllerApplet(HID::HIDCore& hid_core_);      ~DefaultControllerApplet() override; -    void ReconfigureControllers(std::function<void()> callback, +    void ReconfigureControllers(ReconfigureCallback callback,                                  const ControllerParameters& parameters) const override;  private: diff --git a/src/core/frontend/applets/error.cpp b/src/core/frontend/applets/error.cpp index f8b961098..69c2b2b4d 100644 --- a/src/core/frontend/applets/error.cpp +++ b/src/core/frontend/applets/error.cpp @@ -8,13 +8,13 @@ namespace Core::Frontend {  ErrorApplet::~ErrorApplet() = default; -void DefaultErrorApplet::ShowError(Result error, std::function<void()> finished) const { +void DefaultErrorApplet::ShowError(Result error, FinishedCallback finished) const {      LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})",                   error.module.Value(), error.description.Value(), error.raw);  }  void DefaultErrorApplet::ShowErrorWithTimestamp(Result error, std::chrono::seconds time, -                                                std::function<void()> finished) const { +                                                FinishedCallback finished) const {      LOG_CRITICAL(          Service_Fatal,          "Application requested error display: {:04X}-{:04X} (raw={:08X}) with timestamp={:016X}", @@ -23,7 +23,7 @@ void DefaultErrorApplet::ShowErrorWithTimestamp(Result error, std::chrono::secon  void DefaultErrorApplet::ShowCustomErrorText(Result error, std::string main_text,                                               std::string detail_text, -                                             std::function<void()> finished) const { +                                             FinishedCallback finished) const {      LOG_CRITICAL(Service_Fatal,                   "Application requested custom error with error_code={:04X}-{:04X} (raw={:08X})",                   error.module.Value(), error.description.Value(), error.raw); diff --git a/src/core/frontend/applets/error.h b/src/core/frontend/applets/error.h index f378f8805..884f2f653 100644 --- a/src/core/frontend/applets/error.h +++ b/src/core/frontend/applets/error.h @@ -12,25 +12,27 @@ namespace Core::Frontend {  class ErrorApplet {  public: +    using FinishedCallback = std::function<void()>; +      virtual ~ErrorApplet(); -    virtual void ShowError(Result error, std::function<void()> finished) const = 0; +    virtual void ShowError(Result error, FinishedCallback finished) const = 0;      virtual void ShowErrorWithTimestamp(Result error, std::chrono::seconds time, -                                        std::function<void()> finished) const = 0; +                                        FinishedCallback finished) const = 0;      virtual void ShowCustomErrorText(Result error, std::string dialog_text,                                       std::string fullscreen_text, -                                     std::function<void()> finished) const = 0; +                                     FinishedCallback finished) const = 0;  };  class DefaultErrorApplet final : public ErrorApplet {  public: -    void ShowError(Result error, std::function<void()> finished) const override; +    void ShowError(Result error, FinishedCallback finished) const override;      void ShowErrorWithTimestamp(Result error, std::chrono::seconds time, -                                std::function<void()> finished) const override; +                                FinishedCallback finished) const override;      void ShowCustomErrorText(Result error, std::string main_text, std::string detail_text, -                             std::function<void()> finished) const override; +                             FinishedCallback finished) const override;  };  } // namespace Core::Frontend diff --git a/src/core/frontend/applets/mii_edit.cpp b/src/core/frontend/applets/mii_edit.cpp index d37b5368a..bc8c57067 100644 --- a/src/core/frontend/applets/mii_edit.cpp +++ b/src/core/frontend/applets/mii_edit.cpp @@ -8,7 +8,7 @@ namespace Core::Frontend {  MiiEditApplet::~MiiEditApplet() = default; -void DefaultMiiEditApplet::ShowMiiEdit(const std::function<void()>& callback) const { +void DefaultMiiEditApplet::ShowMiiEdit(const MiiEditCallback& callback) const {      LOG_WARNING(Service_AM, "(STUBBED) called");      callback(); diff --git a/src/core/frontend/applets/mii_edit.h b/src/core/frontend/applets/mii_edit.h index 58fa2039b..d828f06ec 100644 --- a/src/core/frontend/applets/mii_edit.h +++ b/src/core/frontend/applets/mii_edit.h @@ -9,14 +9,16 @@ namespace Core::Frontend {  class MiiEditApplet {  public: +    using MiiEditCallback = std::function<void()>; +      virtual ~MiiEditApplet(); -    virtual void ShowMiiEdit(const std::function<void()>& callback) const = 0; +    virtual void ShowMiiEdit(const MiiEditCallback& callback) const = 0;  };  class DefaultMiiEditApplet final : public MiiEditApplet {  public: -    void ShowMiiEdit(const std::function<void()>& callback) const override; +    void ShowMiiEdit(const MiiEditCallback& callback) const override;  };  } // namespace Core::Frontend diff --git a/src/core/frontend/applets/profile_select.cpp b/src/core/frontend/applets/profile_select.cpp index d11fbce0a..da4cfbf87 100644 --- a/src/core/frontend/applets/profile_select.cpp +++ b/src/core/frontend/applets/profile_select.cpp @@ -9,8 +9,7 @@ namespace Core::Frontend {  ProfileSelectApplet::~ProfileSelectApplet() = default; -void DefaultProfileSelectApplet::SelectProfile( -    std::function<void(std::optional<Common::UUID>)> callback) const { +void DefaultProfileSelectApplet::SelectProfile(SelectProfileCallback callback) const {      Service::Account::ProfileManager manager;      callback(manager.GetUser(Settings::values.current_user.GetValue()).value_or(Common::UUID{}));      LOG_INFO(Service_ACC, "called, selecting current user instead of prompting..."); diff --git a/src/core/frontend/applets/profile_select.h b/src/core/frontend/applets/profile_select.h index 8d6ee5279..138429533 100644 --- a/src/core/frontend/applets/profile_select.h +++ b/src/core/frontend/applets/profile_select.h @@ -11,14 +11,16 @@ namespace Core::Frontend {  class ProfileSelectApplet {  public: +    using SelectProfileCallback = std::function<void(std::optional<Common::UUID>)>; +      virtual ~ProfileSelectApplet(); -    virtual void SelectProfile(std::function<void(std::optional<Common::UUID>)> callback) const = 0; +    virtual void SelectProfile(SelectProfileCallback callback) const = 0;  };  class DefaultProfileSelectApplet final : public ProfileSelectApplet {  public: -    void SelectProfile(std::function<void(std::optional<Common::UUID>)> callback) const override; +    void SelectProfile(SelectProfileCallback callback) const override;  };  } // namespace Core::Frontend diff --git a/src/core/frontend/applets/software_keyboard.cpp b/src/core/frontend/applets/software_keyboard.cpp index 020c7fa5e..a3720f4d7 100644 --- a/src/core/frontend/applets/software_keyboard.cpp +++ b/src/core/frontend/applets/software_keyboard.cpp @@ -15,10 +15,7 @@ DefaultSoftwareKeyboardApplet::~DefaultSoftwareKeyboardApplet() = default;  void DefaultSoftwareKeyboardApplet::InitializeKeyboard(      bool is_inline, KeyboardInitializeParameters initialize_parameters, -    std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)> -        submit_normal_callback_, -    std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)> -        submit_inline_callback_) { +    SubmitNormalCallback submit_normal_callback_, SubmitInlineCallback submit_inline_callback_) {      if (is_inline) {          LOG_WARNING(              Service_AM, diff --git a/src/core/frontend/applets/software_keyboard.h b/src/core/frontend/applets/software_keyboard.h index 094d1e713..8aef103d3 100644 --- a/src/core/frontend/applets/software_keyboard.h +++ b/src/core/frontend/applets/software_keyboard.h @@ -54,14 +54,17 @@ struct InlineTextParameters {  class SoftwareKeyboardApplet {  public: +    using SubmitInlineCallback = +        std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>; +    using SubmitNormalCallback = +        std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>; +      virtual ~SoftwareKeyboardApplet(); -    virtual void InitializeKeyboard( -        bool is_inline, KeyboardInitializeParameters initialize_parameters, -        std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)> -            submit_normal_callback_, -        std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)> -            submit_inline_callback_) = 0; +    virtual void InitializeKeyboard(bool is_inline, +                                    KeyboardInitializeParameters initialize_parameters, +                                    SubmitNormalCallback submit_normal_callback_, +                                    SubmitInlineCallback submit_inline_callback_) = 0;      virtual void ShowNormalKeyboard() const = 0; @@ -81,12 +84,9 @@ class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet {  public:      ~DefaultSoftwareKeyboardApplet() override; -    void InitializeKeyboard( -        bool is_inline, KeyboardInitializeParameters initialize_parameters, -        std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)> -            submit_normal_callback_, -        std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)> -            submit_inline_callback_) override; +    void InitializeKeyboard(bool is_inline, KeyboardInitializeParameters initialize_parameters, +                            SubmitNormalCallback submit_normal_callback_, +                            SubmitInlineCallback submit_inline_callback_) override;      void ShowNormalKeyboard() const override; @@ -105,12 +105,10 @@ private:      void SubmitNormalText(std::u16string text) const;      void SubmitInlineText(std::u16string_view text) const; -    KeyboardInitializeParameters parameters; +    KeyboardInitializeParameters parameters{}; -    mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)> -        submit_normal_callback; -    mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)> -        submit_inline_callback; +    mutable SubmitNormalCallback submit_normal_callback; +    mutable SubmitInlineCallback submit_inline_callback;  };  } // namespace Core::Frontend diff --git a/src/core/frontend/applets/web_browser.cpp b/src/core/frontend/applets/web_browser.cpp index 27c7086be..b09cb7102 100644 --- a/src/core/frontend/applets/web_browser.cpp +++ b/src/core/frontend/applets/web_browser.cpp @@ -10,18 +10,17 @@ WebBrowserApplet::~WebBrowserApplet() = default;  DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default; -void DefaultWebBrowserApplet::OpenLocalWebPage( -    const std::string& local_url, std::function<void()> extract_romfs_callback, -    std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const { +void DefaultWebBrowserApplet::OpenLocalWebPage(const std::string& local_url, +                                               ExtractROMFSCallback extract_romfs_callback, +                                               OpenWebPageCallback callback) const {      LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open local web page at {}",                  local_url);      callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/");  } -void DefaultWebBrowserApplet::OpenExternalWebPage( -    const std::string& external_url, -    std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const { +void DefaultWebBrowserApplet::OpenExternalWebPage(const std::string& external_url, +                                                  OpenWebPageCallback callback) const {      LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open external web page at {}",                  external_url); diff --git a/src/core/frontend/applets/web_browser.h b/src/core/frontend/applets/web_browser.h index 1411274f8..4f72284ad 100644 --- a/src/core/frontend/applets/web_browser.h +++ b/src/core/frontend/applets/web_browser.h @@ -11,29 +11,29 @@ namespace Core::Frontend {  class WebBrowserApplet {  public: +    using ExtractROMFSCallback = std::function<void()>; +    using OpenWebPageCallback = +        std::function<void(Service::AM::Applets::WebExitReason, std::string)>; +      virtual ~WebBrowserApplet(); -    virtual void OpenLocalWebPage( -        const std::string& local_url, std::function<void()> extract_romfs_callback, -        std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const = 0; +    virtual void OpenLocalWebPage(const std::string& local_url, +                                  ExtractROMFSCallback extract_romfs_callback, +                                  OpenWebPageCallback callback) const = 0; -    virtual void OpenExternalWebPage( -        const std::string& external_url, -        std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const = 0; +    virtual void OpenExternalWebPage(const std::string& external_url, +                                     OpenWebPageCallback callback) const = 0;  };  class DefaultWebBrowserApplet final : public WebBrowserApplet {  public:      ~DefaultWebBrowserApplet() override; -    void OpenLocalWebPage(const std::string& local_url, -                          std::function<void()> extract_romfs_callback, -                          std::function<void(Service::AM::Applets::WebExitReason, std::string)> -                              callback) const override; +    void OpenLocalWebPage(const std::string& local_url, ExtractROMFSCallback extract_romfs_callback, +                          OpenWebPageCallback callback) const override;      void OpenExternalWebPage(const std::string& external_url, -                             std::function<void(Service::AM::Applets::WebExitReason, std::string)> -                                 callback) const override; +                             OpenWebPageCallback callback) const override;  };  } // namespace Core::Frontend diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index ac1906d5e..95363b645 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -17,6 +17,8 @@ enum class WindowSystemType {      Windows,      X11,      Wayland, +    Cocoa, +    Android,  };  /** diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index b6c8cc58d..30c2e9d17 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -37,7 +37,7 @@ void EmulatedConsole::SetTouchParams() {          touchscreen_param.Set("axis_x", i * 2);          touchscreen_param.Set("axis_y", (i * 2) + 1);          touchscreen_param.Set("button", i); -        touch_params[index++] = touchscreen_param; +        touch_params[index++] = std::move(touchscreen_param);      }      const auto button_index = @@ -59,7 +59,7 @@ void EmulatedConsole::SetTouchParams() {          touch_button_params.Set("button", params.Serialize());          touch_button_params.Set("x", x);          touch_button_params.Set("y", y); -        touch_params[index] = touch_button_params; +        touch_params[index] = std::move(touch_button_params);          index++;      }  } @@ -131,7 +131,7 @@ Common::ParamPackage EmulatedConsole::GetMotionParam() const {  }  void EmulatedConsole::SetMotionParam(Common::ParamPackage param) { -    motion_params = param; +    motion_params = std::move(param);      ReloadInput();  } @@ -199,7 +199,7 @@ void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, st      if (is_new_input) {          touch_value.pressed.value = true; -        touch_value.id = static_cast<u32>(index); +        touch_value.id = static_cast<int>(index);      }      touch_value.x = touch_input.x; @@ -284,7 +284,7 @@ void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {  int EmulatedConsole::SetCallback(ConsoleUpdateCallback update_callback) {      std::scoped_lock lock{callback_mutex}; -    callback_list.insert_or_assign(last_callback_key, update_callback); +    callback_list.insert_or_assign(last_callback_key, std::move(update_callback));      return last_callback_key++;  } diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index c96d9eef3..67969e938 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -3,6 +3,7 @@  #include <algorithm> +#include "common/polyfill_ranges.h"  #include "common/thread.h"  #include "core/hid/emulated_controller.h"  #include "core/hid/input_converter.h" @@ -109,10 +110,9 @@ void EmulatedController::ReloadFromSettings() {          original_npad_type = npad_type;      } +    Disconnect();      if (player.connected) {          Connect(); -    } else { -        Disconnect();      }      ReloadInput(); @@ -424,15 +424,14 @@ void EmulatedController::RestoreConfig() {      ReloadFromSettings();  } -std::vector<Common::ParamPackage> EmulatedController::GetMappedDevices( -    EmulatedDeviceIndex device_index) const { +std::vector<Common::ParamPackage> EmulatedController::GetMappedDevices() const {      std::vector<Common::ParamPackage> devices;      for (const auto& param : button_params) {          if (!param.Has("engine")) {              continue;          }          const auto devices_it = std::find_if( -            devices.begin(), devices.end(), [param](const Common::ParamPackage param_) { +            devices.begin(), devices.end(), [¶m](const Common::ParamPackage& param_) {                  return param.Get("engine", "") == param_.Get("engine", "") &&                         param.Get("guid", "") == param_.Get("guid", "") &&                         param.Get("port", 0) == param_.Get("port", 0) && @@ -441,12 +440,12 @@ std::vector<Common::ParamPackage> EmulatedController::GetMappedDevices(          if (devices_it != devices.end()) {              continue;          } -        Common::ParamPackage device{}; + +        auto& device = devices.emplace_back();          device.Set("engine", param.Get("engine", ""));          device.Set("guid", param.Get("guid", ""));          device.Set("port", param.Get("port", 0));          device.Set("pad", param.Get("pad", 0)); -        devices.push_back(device);      }      for (const auto& param : stick_params) { @@ -457,7 +456,7 @@ std::vector<Common::ParamPackage> EmulatedController::GetMappedDevices(              continue;          }          const auto devices_it = std::find_if( -            devices.begin(), devices.end(), [param](const Common::ParamPackage param_) { +            devices.begin(), devices.end(), [¶m](const Common::ParamPackage& param_) {                  return param.Get("engine", "") == param_.Get("engine", "") &&                         param.Get("guid", "") == param_.Get("guid", "") &&                         param.Get("port", 0) == param_.Get("port", 0) && @@ -466,12 +465,12 @@ std::vector<Common::ParamPackage> EmulatedController::GetMappedDevices(          if (devices_it != devices.end()) {              continue;          } -        Common::ParamPackage device{}; + +        auto& device = devices.emplace_back();          device.Set("engine", param.Get("engine", ""));          device.Set("guid", param.Get("guid", ""));          device.Set("port", param.Get("port", 0));          device.Set("pad", param.Get("pad", 0)); -        devices.push_back(device);      }      return devices;  } diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index d004ca56a..fa7a34278 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -8,6 +8,7 @@  #include <memory>  #include <mutex>  #include <unordered_map> +#include <vector>  #include "common/common_types.h"  #include "common/input.h" @@ -243,7 +244,7 @@ public:      void RestoreConfig();      /// Returns a vector of mapped devices from the mapped button and stick parameters -    std::vector<Common::ParamPackage> GetMappedDevices(EmulatedDeviceIndex device_index) const; +    std::vector<Common::ParamPackage> GetMappedDevices() const;      // Returns the current mapped button device      Common::ParamPackage GetButtonParam(std::size_t index) const; diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index 4149eeced..4cdbf9dc6 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -8,6 +8,7 @@  #include <memory>  #include <mutex>  #include <unordered_map> +#include <vector>  #include "common/common_types.h"  #include "common/input.h" diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h index 3b6e7baff..87ca65592 100644 --- a/src/core/hle/kernel/k_memory_block.h +++ b/src/core/hle/kernel/k_memory_block.h @@ -280,18 +280,19 @@ struct KMemoryInfo {  class KMemoryBlock : public Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock> {  private: -    u16 m_device_disable_merge_left_count; -    u16 m_device_disable_merge_right_count; -    VAddr m_address; -    size_t m_num_pages; -    KMemoryState m_memory_state; -    u16 m_ipc_lock_count; -    u16 m_device_use_count; -    u16 m_ipc_disable_merge_count; -    KMemoryPermission m_permission; -    KMemoryPermission m_original_permission; -    KMemoryAttribute m_attribute; -    KMemoryBlockDisableMergeAttribute m_disable_merge_attribute; +    u16 m_device_disable_merge_left_count{}; +    u16 m_device_disable_merge_right_count{}; +    VAddr m_address{}; +    size_t m_num_pages{}; +    KMemoryState m_memory_state{KMemoryState::None}; +    u16 m_ipc_lock_count{}; +    u16 m_device_use_count{}; +    u16 m_ipc_disable_merge_count{}; +    KMemoryPermission m_permission{KMemoryPermission::None}; +    KMemoryPermission m_original_permission{KMemoryPermission::None}; +    KMemoryAttribute m_attribute{KMemoryAttribute::None}; +    KMemoryBlockDisableMergeAttribute m_disable_merge_attribute{ +        KMemoryBlockDisableMergeAttribute::None};  public:      static constexpr int Compare(const KMemoryBlock& lhs, const KMemoryBlock& rhs) { @@ -367,12 +368,8 @@ public:      constexpr KMemoryBlock(VAddr addr, size_t np, KMemoryState ms, KMemoryPermission p,                             KMemoryAttribute attr) -        : Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock>(), -          m_device_disable_merge_left_count(), m_device_disable_merge_right_count(), -          m_address(addr), m_num_pages(np), m_memory_state(ms), m_ipc_lock_count(0), -          m_device_use_count(0), m_ipc_disable_merge_count(), m_permission(p), -          m_original_permission(KMemoryPermission::None), m_attribute(attr), -          m_disable_merge_attribute() {} +        : Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock>(), m_address(addr), m_num_pages(np), +          m_memory_state(ms), m_permission(p), m_attribute(attr) {}      constexpr void Initialize(VAddr addr, size_t np, KMemoryState ms, KMemoryPermission p,                                KMemoryAttribute attr) { diff --git a/src/core/hle/kernel/k_memory_block_manager.h b/src/core/hle/kernel/k_memory_block_manager.h index 9b5873883..d382722a6 100644 --- a/src/core/hle/kernel/k_memory_block_manager.h +++ b/src/core/hle/kernel/k_memory_block_manager.h @@ -3,6 +3,7 @@  #pragma once +#include <array>  #include <functional>  #include "common/common_funcs.h" @@ -17,9 +18,9 @@ public:      static constexpr size_t MaxBlocks = 2;  private: -    KMemoryBlock* m_blocks[MaxBlocks]; -    size_t m_index; -    KMemoryBlockSlabManager* m_slab_manager; +    std::array<KMemoryBlock*, MaxBlocks> m_blocks{}; +    size_t m_index{MaxBlocks}; +    KMemoryBlockSlabManager* m_slab_manager{};  private:      Result Initialize(size_t num_blocks) { @@ -41,7 +42,7 @@ private:  public:      KMemoryBlockManagerUpdateAllocator(Result* out_result, KMemoryBlockSlabManager* sm,                                         size_t num_blocks = MaxBlocks) -        : m_blocks(), m_index(MaxBlocks), m_slab_manager(sm) { +        : m_slab_manager(sm) {          *out_result = this->Initialize(num_blocks);      } diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp index c4bf306e8..bd33571da 100644 --- a/src/core/hle/kernel/k_memory_manager.cpp +++ b/src/core/hle/kernel/k_memory_manager.cpp @@ -225,8 +225,8 @@ Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages,      ON_RESULT_FAILURE {          for (const auto& it : out->Nodes()) {              auto& manager = this->GetManager(it.GetAddress()); -            const size_t node_num_pages = -                std::min(it.GetNumPages(), (manager.GetEndAddress() - it.GetAddress()) / PageSize); +            const size_t node_num_pages = std::min<u64>( +                it.GetNumPages(), (manager.GetEndAddress() - it.GetAddress()) / PageSize);              manager.Free(it.GetAddress(), node_num_pages);          }          out->Finalize(); diff --git a/src/core/hle/kernel/k_shared_memory.h b/src/core/hle/kernel/k_shared_memory.h index 5620c3660..a96c55a3e 100644 --- a/src/core/hle/kernel/k_shared_memory.h +++ b/src/core/hle/kernel/k_shared_memory.h @@ -74,7 +74,7 @@ public:      static void PostDestroy([[maybe_unused]] uintptr_t arg) {}  private: -    Core::DeviceMemory* device_memory; +    Core::DeviceMemory* device_memory{};      KProcess* owner_process{};      KPageGroup page_list;      Svc::MemoryPermission owner_permission{}; diff --git a/src/core/hle/kernel/k_slab_heap.h b/src/core/hle/kernel/k_slab_heap.h index a8c77a7d4..68469b041 100644 --- a/src/core/hle/kernel/k_slab_heap.h +++ b/src/core/hle/kernel/k_slab_heap.h @@ -6,6 +6,7 @@  #include <atomic>  #include "common/assert.h" +#include "common/atomic_ops.h"  #include "common/common_funcs.h"  #include "common/common_types.h"  #include "common/spin_lock.h" @@ -82,16 +83,13 @@ private:  private:      void UpdatePeakImpl(uintptr_t obj) { -        static_assert(std::atomic_ref<uintptr_t>::is_always_lock_free); -        std::atomic_ref<uintptr_t> peak_ref(m_peak); -          const uintptr_t alloc_peak = obj + this->GetObjectSize();          uintptr_t cur_peak = m_peak;          do {              if (alloc_peak <= cur_peak) {                  break;              } -        } while (!peak_ref.compare_exchange_strong(cur_peak, alloc_peak)); +        } while (!Common::AtomicCompareAndSwap(&m_peak, alloc_peak, cur_peak, cur_peak));      }  public: diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index f38c92bff..dc52b4ed3 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -784,8 +784,8 @@ private:      std::vector<KSynchronizationObject*> wait_objects_for_debugging;      VAddr mutex_wait_address_for_debugging{};      ThreadWaitReasonForDebugging wait_reason_for_debugging{}; -    uintptr_t argument; -    VAddr stack_top; +    uintptr_t argument{}; +    VAddr stack_top{};  public:      using ConditionVariableThreadTreeType = ConditionVariableThreadTree; diff --git a/src/core/hle/kernel/k_thread_local_page.h b/src/core/hle/kernel/k_thread_local_page.h index 5d466ace7..fe0cff084 100644 --- a/src/core/hle/kernel/k_thread_local_page.h +++ b/src/core/hle/kernel/k_thread_local_page.h @@ -10,6 +10,7 @@  #include "common/assert.h"  #include "common/common_types.h"  #include "common/intrusive_red_black_tree.h" +#include "common/polyfill_ranges.h"  #include "core/hle/kernel/memory_types.h"  #include "core/hle/kernel/slab_helpers.h"  #include "core/hle/result.h" diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b77723503..288f97df5 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -891,7 +891,7 @@ struct KernelCore::Impl {      Common::ThreadWorker service_threads_manager;      Common::Barrier service_thread_barrier; -    std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads; +    std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads{};      std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};      bool is_multicore{}; diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index 2fc8d4be2..fb2ba4c6b 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -85,7 +85,7 @@ private:      std::mutex guard;      std::condition_variable on_interrupt;      std::unique_ptr<Core::ARM_Interface> arm_interface; -    bool is_interrupted; +    bool is_interrupted{};  };  } // namespace Kernel diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp index e6e41ac34..e72c3d35d 100644 --- a/src/core/hle/kernel/service_thread.cpp +++ b/src/core/hle/kernel/service_thread.cpp @@ -7,6 +7,7 @@  #include <thread>  #include <vector> +#include "common/polyfill_thread.h"  #include "common/scope_exit.h"  #include "common/thread.h"  #include "core/hle/ipc_helpers.h" @@ -35,14 +36,14 @@ public:  private:      KernelCore& kernel; - -    std::jthread m_host_thread; -    std::mutex m_session_mutex; -    std::map<KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions; -    KEvent* m_wakeup_event; -    KThread* m_thread; -    std::atomic<bool> m_shutdown_requested;      const std::string m_service_name; + +    std::jthread m_host_thread{}; +    std::mutex m_session_mutex{}; +    std::map<KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions{}; +    KEvent* m_wakeup_event{}; +    KThread* m_thread{}; +    std::atomic<bool> m_shutdown_requested{};  };  void ServiceThread::Impl::WaitAndProcessImpl() { diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 3730937fe..1ea8c7fbc 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -82,7 +82,7 @@ void SvcWrap64(Core::System& system) {  }  // Used by ControlCodeMemory -template <Result func(Core::System&, Handle, u32, u64, u64, Svc::MemoryPermission)> +template <Result func(Core::System&, Handle, u32, VAddr, size_t, Svc::MemoryPermission)>  void SvcWrap64(Core::System& system) {      FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)),                              static_cast<u32>(Param(system, 1)), Param(system, 2), Param(system, 3), @@ -327,7 +327,7 @@ void SvcWrap64(Core::System& system) {  }  // Used by CreateCodeMemory -template <Result func(Core::System&, Handle*, u64, u64)> +template <Result func(Core::System&, Handle*, VAddr, size_t)>  void SvcWrap64(Core::System& system) {      u32 param_1 = 0;      const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2)).raw; diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 85a3f0802..6d1084fd1 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -7,6 +7,7 @@  #include "common/fs/file.h"  #include "common/fs/path_util.h"  #include "common/logging/log.h" +#include "common/polyfill_ranges.h"  #include "common/string_util.h"  #include "common/swap.h"  #include "core/constants.h" diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 481e0d141..97f7c6688 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp @@ -9,6 +9,7 @@  #include "common/fs/file.h"  #include "common/fs/fs.h"  #include "common/fs/path_util.h" +#include "common/polyfill_ranges.h"  #include "common/settings.h"  #include "core/hle/service/acc/profile_manager.h" diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 8ea7fd760..22999c942 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -1125,7 +1125,7 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {      const u64 offset{rp.Pop<u64>()};      const std::vector<u8> data{ctx.ReadBuffer()}; -    const std::size_t size{std::min(data.size(), backing.GetSize() - offset)}; +    const std::size_t size{std::min<u64>(data.size(), backing.GetSize() - offset)};      LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); @@ -1149,7 +1149,7 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx};      const u64 offset{rp.Pop<u64>()}; -    const std::size_t size{std::min(ctx.GetWriteBufferSize(), backing.GetSize() - offset)}; +    const std::size_t size{std::min<u64>(ctx.GetWriteBufferSize(), backing.GetSize() - offset)};      LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp index 053e8f9dd..26dec7147 100644 --- a/src/core/hle/service/audio/audin_u.cpp +++ b/src/core/hle/service/audio/audin_u.cpp @@ -203,9 +203,8 @@ private:  };  AudInU::AudInU(Core::System& system_) -    : ServiceFramework{system_, "audin:u", ServiceThreadType::CreateNew}, -      service_context{system_, "AudInU"}, impl{std::make_unique<AudioCore::AudioIn::Manager>( -                                              system_)} { +    : ServiceFramework{system_, "audin:u"}, service_context{system_, "AudInU"}, +      impl{std::make_unique<AudioCore::AudioIn::Manager>(system_)} {      // clang-format off      static const FunctionInfo functions[] = {          {0, &AudInU::ListAudioIns, "ListAudioIns"}, diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 29751f075..991e30ba1 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -26,9 +26,8 @@ public:      explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager,                         size_t session_id, const std::string& device_name,                         const AudioOutParameter& in_params, u32 handle, u64 applet_resource_user_id) -        : ServiceFramework{system_, "IAudioOut", ServiceThreadType::CreateNew}, -          service_context{system_, "IAudioOut"}, event{service_context.CreateEvent( -                                                     "AudioOutEvent")}, +        : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"}, +          event{service_context.CreateEvent("AudioOutEvent")},            impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} {          // clang-format off @@ -221,9 +220,8 @@ private:  };  AudOutU::AudOutU(Core::System& system_) -    : ServiceFramework{system_, "audout:u", ServiceThreadType::CreateNew}, -      service_context{system_, "AudOutU"}, impl{std::make_unique<AudioCore::AudioOut::Manager>( -                                               system_)} { +    : ServiceFramework{system_, "audout:u"}, service_context{system_, "AudOutU"}, +      impl{std::make_unique<AudioCore::AudioOut::Manager>(system_)} {      // clang-format off      static const FunctionInfo functions[] = {          {0, &AudOutU::ListAudioOuts, "ListAudioOuts"}, diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 034ee273f..ead16c321 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -14,6 +14,7 @@  #include "common/bit_util.h"  #include "common/common_funcs.h"  #include "common/logging/log.h" +#include "common/polyfill_ranges.h"  #include "common/string_util.h"  #include "core/core.h"  #include "core/hle/ipc_helpers.h" @@ -34,10 +35,9 @@ public:                              AudioCore::AudioRendererParameterInternal& params,                              Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,                              u32 process_handle, u64 applet_resource_user_id, s32 session_id) -        : ServiceFramework{system_, "IAudioRenderer", ServiceThreadType::CreateNew}, -          service_context{system_, "IAudioRenderer"}, rendered_event{service_context.CreateEvent( -                                                          "IAudioRendererEvent")}, -          manager{manager_}, impl{std::make_unique<Renderer>(system_, manager, rendered_event)} { +        : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"}, +          rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_}, +          impl{std::make_unique<Renderer>(system_, manager, rendered_event)} {          // clang-format off          static const FunctionInfo functions[] = {              {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, @@ -242,10 +242,8 @@ class IAudioDevice final : public ServiceFramework<IAudioDevice> {  public:      explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,                            u32 device_num) -        : ServiceFramework{system_, "IAudioDevice", ServiceThreadType::CreateNew}, -          service_context{system_, "IAudioDevice"}, impl{std::make_unique<AudioDevice>( -                                                        system_, applet_resource_user_id, -                                                        revision)}, +        : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"}, +          impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)},            event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {          static const FunctionInfo functions[] = {              {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, @@ -420,7 +418,7 @@ private:  };  AudRenU::AudRenU(Core::System& system_) -    : ServiceFramework{system_, "audren:u", ServiceThreadType::CreateNew}, +    : ServiceFramework{system_, "audren:u"},        service_context{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} {      // clang-format off      static const FunctionInfo functions[] = { diff --git a/src/core/hle/service/nfc/mifare_user.cpp b/src/core/hle/service/nfc/mifare_user.cpp new file mode 100644 index 000000000..51523a3ae --- /dev/null +++ b/src/core/hle/service/nfc/mifare_user.cpp @@ -0,0 +1,400 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "core/core.h" +#include "core/hid/hid_types.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/service/nfc/mifare_user.h" +#include "core/hle/service/nfc/nfc_device.h" +#include "core/hle/service/nfc/nfc_result.h" + +namespace Service::NFC { + +MFIUser::MFIUser(Core::System& system_) +    : ServiceFramework{system_, "NFC::MFIUser"}, service_context{system_, service_name} { +    static const FunctionInfo functions[] = { +        {0, &MFIUser::Initialize, "Initialize"}, +        {1, &MFIUser::Finalize, "Finalize"}, +        {2, &MFIUser::ListDevices, "ListDevices"}, +        {3, &MFIUser::StartDetection, "StartDetection"}, +        {4, &MFIUser::StopDetection, "StopDetection"}, +        {5, &MFIUser::Read, "Read"}, +        {6, &MFIUser::Write, "Write"}, +        {7, &MFIUser::GetTagInfo, "GetTagInfo"}, +        {8, &MFIUser::GetActivateEventHandle, "GetActivateEventHandle"}, +        {9, &MFIUser::GetDeactivateEventHandle, "GetDeactivateEventHandle"}, +        {10, &MFIUser::GetState, "GetState"}, +        {11, &MFIUser::GetDeviceState, "GetDeviceState"}, +        {12, &MFIUser::GetNpadId, "GetNpadId"}, +        {13, &MFIUser::GetAvailabilityChangeEventHandle, "GetAvailabilityChangeEventHandle"}, +    }; +    RegisterHandlers(functions); + +    availability_change_event = service_context.CreateEvent("MFIUser:AvailabilityChangeEvent"); + +    for (u32 device_index = 0; device_index < 10; device_index++) { +        devices[device_index] = +            std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system, +                                        service_context, availability_change_event); +    } +} + +MFIUser ::~MFIUser() { +    availability_change_event->Close(); +} + +void MFIUser::Initialize(Kernel::HLERequestContext& ctx) { +    LOG_INFO(Service_NFC, "called"); + +    state = State::Initialized; + +    for (auto& device : devices) { +        device->Initialize(); +    } + +    IPC::ResponseBuilder rb{ctx, 2, 0}; +    rb.Push(ResultSuccess); +} + +void MFIUser::Finalize(Kernel::HLERequestContext& ctx) { +    LOG_INFO(Service_NFC, "called"); + +    state = State::NonInitialized; + +    for (auto& device : devices) { +        device->Finalize(); +    } + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(ResultSuccess); +} + +void MFIUser::ListDevices(Kernel::HLERequestContext& ctx) { +    LOG_DEBUG(Service_NFC, "called"); + +    if (state == State::NonInitialized) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareNfcDisabled); +        return; +    } + +    if (!ctx.CanWriteBuffer()) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareInvalidArgument); +        return; +    } + +    if (ctx.GetWriteBufferSize() == 0) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareInvalidArgument); +        return; +    } + +    std::vector<u64> nfp_devices; +    const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>(); + +    for (const auto& device : devices) { +        if (nfp_devices.size() >= max_allowed_devices) { +            continue; +        } +        if (device->GetCurrentState() != NFP::DeviceState::Unavailable) { +            nfp_devices.push_back(device->GetHandle()); +        } +    } + +    if (nfp_devices.empty()) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareDeviceNotFound); +        return; +    } + +    ctx.WriteBuffer(nfp_devices); + +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(ResultSuccess); +    rb.Push(static_cast<s32>(nfp_devices.size())); +} + +void MFIUser::StartDetection(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto device_handle{rp.Pop<u64>()}; +    LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); + +    if (state == State::NonInitialized) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareNfcDisabled); +        return; +    } + +    auto device = GetNfcDevice(device_handle); + +    if (!device.has_value()) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareDeviceNotFound); +        return; +    } + +    const auto result = device.value()->StartDetection(NFP::TagProtocol::All); +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(result); +} + +void MFIUser::StopDetection(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto device_handle{rp.Pop<u64>()}; +    LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); + +    if (state == State::NonInitialized) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareNfcDisabled); +        return; +    } + +    auto device = GetNfcDevice(device_handle); + +    if (!device.has_value()) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareDeviceNotFound); +        return; +    } + +    const auto result = device.value()->StopDetection(); +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(result); +} + +void MFIUser::Read(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto device_handle{rp.Pop<u64>()}; +    const auto buffer{ctx.ReadBuffer()}; +    const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareReadBlockParameter>()}; +    std::vector<NFP::MifareReadBlockParameter> read_commands(number_of_commands); + +    memcpy(read_commands.data(), buffer.data(), +           number_of_commands * sizeof(NFP::MifareReadBlockParameter)); + +    LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}", +             device_handle, number_of_commands); + +    if (state == State::NonInitialized) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareNfcDisabled); +        return; +    } + +    auto device = GetNfcDevice(device_handle); + +    if (!device.has_value()) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareDeviceNotFound); +        return; +    } + +    Result result = ResultSuccess; +    std::vector<NFP::MifareReadBlockData> out_data(number_of_commands); +    for (std::size_t i = 0; i < number_of_commands; i++) { +        result = device.value()->MifareRead(read_commands[i], out_data[i]); +        if (result.IsError()) { +            break; +        } +    } + +    ctx.WriteBuffer(out_data); +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(result); +} + +void MFIUser::Write(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto device_handle{rp.Pop<u64>()}; +    const auto buffer{ctx.ReadBuffer()}; +    const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareWriteBlockParameter>()}; +    std::vector<NFP::MifareWriteBlockParameter> write_commands(number_of_commands); + +    memcpy(write_commands.data(), buffer.data(), +           number_of_commands * sizeof(NFP::MifareWriteBlockParameter)); + +    LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, write_commands_size={}", +             device_handle, number_of_commands); + +    if (state == State::NonInitialized) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareNfcDisabled); +        return; +    } + +    auto device = GetNfcDevice(device_handle); + +    if (!device.has_value()) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareDeviceNotFound); +        return; +    } + +    Result result = ResultSuccess; +    std::vector<NFP::MifareReadBlockData> out_data(number_of_commands); +    for (std::size_t i = 0; i < number_of_commands; i++) { +        result = device.value()->MifareWrite(write_commands[i]); +        if (result.IsError()) { +            break; +        } +    } + +    if (result.IsSuccess()) { +        result = device.value()->Flush(); +    } + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(result); +} + +void MFIUser::GetTagInfo(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto device_handle{rp.Pop<u64>()}; +    LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); + +    if (state == State::NonInitialized) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareNfcDisabled); +        return; +    } + +    auto device = GetNfcDevice(device_handle); + +    if (!device.has_value()) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareDeviceNotFound); +        return; +    } + +    NFP::TagInfo tag_info{}; +    const auto result = device.value()->GetTagInfo(tag_info, true); +    ctx.WriteBuffer(tag_info); +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(result); +} + +void MFIUser::GetActivateEventHandle(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto device_handle{rp.Pop<u64>()}; +    LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); + +    if (state == State::NonInitialized) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareNfcDisabled); +        return; +    } + +    auto device = GetNfcDevice(device_handle); + +    if (!device.has_value()) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareDeviceNotFound); +        return; +    } + +    IPC::ResponseBuilder rb{ctx, 2, 1}; +    rb.Push(ResultSuccess); +    rb.PushCopyObjects(device.value()->GetActivateEvent()); +} + +void MFIUser::GetDeactivateEventHandle(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto device_handle{rp.Pop<u64>()}; +    LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); + +    if (state == State::NonInitialized) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareNfcDisabled); +        return; +    } + +    auto device = GetNfcDevice(device_handle); + +    if (!device.has_value()) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareDeviceNotFound); +        return; +    } + +    IPC::ResponseBuilder rb{ctx, 2, 1}; +    rb.Push(ResultSuccess); +    rb.PushCopyObjects(device.value()->GetDeactivateEvent()); +} + +void MFIUser::GetState(Kernel::HLERequestContext& ctx) { +    LOG_DEBUG(Service_NFC, "called"); + +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(ResultSuccess); +    rb.PushEnum(state); +} + +void MFIUser::GetDeviceState(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto device_handle{rp.Pop<u64>()}; +    LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); + +    auto device = GetNfcDevice(device_handle); + +    if (!device.has_value()) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareDeviceNotFound); +        return; +    } + +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(ResultSuccess); +    rb.PushEnum(device.value()->GetCurrentState()); +} + +void MFIUser::GetNpadId(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto device_handle{rp.Pop<u64>()}; +    LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); + +    if (state == State::NonInitialized) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareNfcDisabled); +        return; +    } + +    auto device = GetNfcDevice(device_handle); + +    if (!device.has_value()) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareDeviceNotFound); +        return; +    } + +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(ResultSuccess); +    rb.PushEnum(device.value()->GetNpadId()); +} + +void MFIUser::GetAvailabilityChangeEventHandle(Kernel::HLERequestContext& ctx) { +    LOG_INFO(Service_NFC, "called"); + +    if (state == State::NonInitialized) { +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(MifareNfcDisabled); +        return; +    } + +    IPC::ResponseBuilder rb{ctx, 2, 1}; +    rb.Push(ResultSuccess); +    rb.PushCopyObjects(availability_change_event->GetReadableEvent()); +} + +std::optional<std::shared_ptr<NfcDevice>> MFIUser::GetNfcDevice(u64 handle) { +    for (auto& device : devices) { +        if (device->GetHandle() == handle) { +            return device; +        } +    } +    return std::nullopt; +} + +} // namespace Service::NFC diff --git a/src/core/hle/service/nfc/mifare_user.h b/src/core/hle/service/nfc/mifare_user.h new file mode 100644 index 000000000..0e0638cb6 --- /dev/null +++ b/src/core/hle/service/nfc/mifare_user.h @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <array> +#include <memory> +#include <optional> + +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/service.h" + +namespace Service::NFC { +class NfcDevice; + +class MFIUser final : public ServiceFramework<MFIUser> { +public: +    explicit MFIUser(Core::System& system_); +    ~MFIUser(); + +private: +    enum class State : u32 { +        NonInitialized, +        Initialized, +    }; + +    void Initialize(Kernel::HLERequestContext& ctx); +    void Finalize(Kernel::HLERequestContext& ctx); +    void ListDevices(Kernel::HLERequestContext& ctx); +    void StartDetection(Kernel::HLERequestContext& ctx); +    void StopDetection(Kernel::HLERequestContext& ctx); +    void Read(Kernel::HLERequestContext& ctx); +    void Write(Kernel::HLERequestContext& ctx); +    void GetTagInfo(Kernel::HLERequestContext& ctx); +    void GetActivateEventHandle(Kernel::HLERequestContext& ctx); +    void GetDeactivateEventHandle(Kernel::HLERequestContext& ctx); +    void GetState(Kernel::HLERequestContext& ctx); +    void GetDeviceState(Kernel::HLERequestContext& ctx); +    void GetNpadId(Kernel::HLERequestContext& ctx); +    void GetAvailabilityChangeEventHandle(Kernel::HLERequestContext& ctx); + +    std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle); + +    KernelHelpers::ServiceContext service_context; + +    std::array<std::shared_ptr<NfcDevice>, 10> devices{}; + +    State state{State::NonInitialized}; +    Kernel::KEvent* availability_change_event; +}; + +} // namespace Service::NFC diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp index 2f4bacb3b..b17b18ab9 100644 --- a/src/core/hle/service/nfc/nfc.cpp +++ b/src/core/hle/service/nfc/nfc.cpp @@ -6,6 +6,7 @@  #include "common/logging/log.h"  #include "common/settings.h"  #include "core/hle/ipc_helpers.h" +#include "core/hle/service/nfc/mifare_user.h"  #include "core/hle/service/nfc/nfc.h"  #include "core/hle/service/nfc/nfc_user.h"  #include "core/hle/service/service.h" @@ -50,32 +51,6 @@ private:      }  }; -class MFIUser final : public ServiceFramework<MFIUser> { -public: -    explicit MFIUser(Core::System& system_) : ServiceFramework{system_, "NFC::MFIUser"} { -        // clang-format off -        static const FunctionInfo functions[] = { -            {0, nullptr, "Initialize"}, -            {1, nullptr, "Finalize"}, -            {2, nullptr, "ListDevices"}, -            {3, nullptr, "StartDetection"}, -            {4, nullptr, "StopDetection"}, -            {5, nullptr, "Read"}, -            {6, nullptr, "Write"}, -            {7, nullptr, "GetTagInfo"}, -            {8, nullptr, "GetActivateEventHandle"}, -            {9, nullptr, "GetDeactivateEventHandle"}, -            {10, nullptr, "GetState"}, -            {11, nullptr, "GetDeviceState"}, -            {12, nullptr, "GetNpadId"}, -            {13, nullptr, "GetAvailabilityChangeEventHandle"}, -        }; -        // clang-format on - -        RegisterHandlers(functions); -    } -}; -  class NFC_MF_U final : public ServiceFramework<NFC_MF_U> {  public:      explicit NFC_MF_U(Core::System& system_) : ServiceFramework{system_, "nfc:mf:u"} { diff --git a/src/core/hle/service/nfc/nfc_device.cpp b/src/core/hle/service/nfc/nfc_device.cpp index 4d514cf5f..78578f723 100644 --- a/src/core/hle/service/nfc/nfc_device.cpp +++ b/src/core/hle/service/nfc/nfc_device.cpp @@ -77,11 +77,13 @@ bool NfcDevice::LoadNfcTag(std::span<const u8> data) {          return false;      } -    if (data.size() != sizeof(NFP::EncryptedNTAG215File)) { +    if (data.size() < sizeof(NFP::EncryptedNTAG215File)) {          LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size());          return false;      } +    tag_data.resize(data.size()); +    memcpy(tag_data.data(), data.data(), data.size());      memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));      device_state = NFP::DeviceState::TagFound; @@ -121,7 +123,7 @@ void NfcDevice::Finalize() {      device_state = NFP::DeviceState::Unavailable;  } -Result NfcDevice::StartDetection(s32 protocol_) { +Result NfcDevice::StartDetection(NFP::TagProtocol allowed_protocol) {      if (device_state != NFP::DeviceState::Initialized &&          device_state != NFP::DeviceState::TagRemoved) {          LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); @@ -134,7 +136,7 @@ Result NfcDevice::StartDetection(s32 protocol_) {      }      device_state = NFP::DeviceState::SearchingForTag; -    protocol = protocol_; +    allowed_protocols = allowed_protocol;      return ResultSuccess;  } @@ -160,7 +162,7 @@ Result NfcDevice::StopDetection() {      return WrongDeviceState;  } -Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const { +Result NfcDevice::Flush() {      if (device_state != NFP::DeviceState::TagFound &&          device_state != NFP::DeviceState::TagMounted) {          LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); @@ -170,6 +172,34 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const {          return WrongDeviceState;      } +    if (!npad_device->WriteNfc(tag_data)) { +        LOG_ERROR(Service_NFP, "Error writing to file"); +        return MifareReadError; +    } + +    return ResultSuccess; +} + +Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const { +    if (device_state != NFP::DeviceState::TagFound && +        device_state != NFP::DeviceState::TagMounted) { +        LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); +        if (device_state == NFP::DeviceState::TagRemoved) { +            return TagRemoved; +        } +        return WrongDeviceState; +    } + +    if (is_mifare) { +        tag_info = { +            .uuid = encrypted_tag_data.uuid.uid, +            .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()), +            .protocol = NFP::TagProtocol::TypeA, +            .tag_type = NFP::TagType::Type4, +        }; +        return ResultSuccess; +    } +      // Protocol and tag type may change here      tag_info = {          .uuid = encrypted_tag_data.uuid.uid, @@ -181,6 +211,52 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const {      return ResultSuccess;  } +Result NfcDevice::MifareRead(const NFP::MifareReadBlockParameter& parameter, +                             NFP::MifareReadBlockData& read_block_data) { +    const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock); +    read_block_data.sector_number = parameter.sector_number; + +    if (device_state != NFP::DeviceState::TagFound && +        device_state != NFP::DeviceState::TagMounted) { +        LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); +        if (device_state == NFP::DeviceState::TagRemoved) { +            return TagRemoved; +        } +        return WrongDeviceState; +    } + +    if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) { +        return MifareReadError; +    } + +    // TODO: Use parameter.sector_key to read encrypted data +    memcpy(read_block_data.data.data(), tag_data.data() + sector_index, sizeof(NFP::DataBlock)); + +    return ResultSuccess; +} + +Result NfcDevice::MifareWrite(const NFP::MifareWriteBlockParameter& parameter) { +    const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock); + +    if (device_state != NFP::DeviceState::TagFound && +        device_state != NFP::DeviceState::TagMounted) { +        LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); +        if (device_state == NFP::DeviceState::TagRemoved) { +            return TagRemoved; +        } +        return WrongDeviceState; +    } + +    if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) { +        return MifareReadError; +    } + +    // TODO: Use parameter.sector_key to encrypt the data +    memcpy(tag_data.data() + sector_index, parameter.data.data(), sizeof(NFP::DataBlock)); + +    return ResultSuccess; +} +  u64 NfcDevice::GetHandle() const {      // Generate a handle based of the npad id      return static_cast<u64>(npad_id); diff --git a/src/core/hle/service/nfc/nfc_device.h b/src/core/hle/service/nfc/nfc_device.h index fa1348f1a..a6e114d36 100644 --- a/src/core/hle/service/nfc/nfc_device.h +++ b/src/core/hle/service/nfc/nfc_device.h @@ -34,10 +34,16 @@ public:      void Initialize();      void Finalize(); -    Result StartDetection(s32 protocol_); +    Result StartDetection(NFP::TagProtocol allowed_protocol);      Result StopDetection(); +    Result Flush(); -    Result GetTagInfo(NFP::TagInfo& tag_info) const; +    Result GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const; + +    Result MifareRead(const NFP::MifareReadBlockParameter& parameter, +                      NFP::MifareReadBlockData& read_block_data); + +    Result MifareWrite(const NFP::MifareWriteBlockParameter& parameter);      u64 GetHandle() const;      NFP::DeviceState GetCurrentState() const; @@ -61,10 +67,11 @@ private:      Kernel::KEvent* deactivate_event = nullptr;      Kernel::KEvent* availability_change_event = nullptr; -    s32 protocol{}; +    NFP::TagProtocol allowed_protocols{};      NFP::DeviceState device_state{NFP::DeviceState::Unavailable};      NFP::EncryptedNTAG215File encrypted_tag_data{}; +    std::vector<u8> tag_data{};  };  } // namespace Service::NFC diff --git a/src/core/hle/service/nfc/nfc_result.h b/src/core/hle/service/nfc/nfc_result.h index 537dc15f4..146b8ba61 100644 --- a/src/core/hle/service/nfc/nfc_result.h +++ b/src/core/hle/service/nfc/nfc_result.h @@ -12,6 +12,12 @@ constexpr Result InvalidArgument(ErrorModule::NFC, 65);  constexpr Result WrongDeviceState(ErrorModule::NFC, 73);  constexpr Result NfcDisabled(ErrorModule::NFC, 80);  constexpr Result TagRemoved(ErrorModule::NFC, 97); -constexpr Result CorruptedData(ErrorModule::NFC, 144); + +constexpr Result MifareDeviceNotFound(ErrorModule::NFCMifare, 64); +constexpr Result MifareInvalidArgument(ErrorModule::NFCMifare, 65); +constexpr Result MifareWrongDeviceState(ErrorModule::NFCMifare, 73); +constexpr Result MifareNfcDisabled(ErrorModule::NFCMifare, 80); +constexpr Result MifareTagRemoved(ErrorModule::NFCMifare, 97); +constexpr Result MifareReadError(ErrorModule::NFCMifare, 288);  } // namespace Service::NFC diff --git a/src/core/hle/service/nfc/nfc_user.cpp b/src/core/hle/service/nfc/nfc_user.cpp index ced2d560b..4615697e2 100644 --- a/src/core/hle/service/nfc/nfc_user.cpp +++ b/src/core/hle/service/nfc/nfc_user.cpp @@ -201,7 +201,7 @@ void IUser::AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) {  void IUser::StartDetection(Kernel::HLERequestContext& ctx) {      IPC::RequestParser rp{ctx};      const auto device_handle{rp.Pop<u64>()}; -    const auto nfp_protocol{rp.Pop<s32>()}; +    const auto nfp_protocol{rp.PopEnum<NFP::TagProtocol>()};      LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);      if (state == State::NonInitialized) { @@ -267,7 +267,7 @@ void IUser::GetTagInfo(Kernel::HLERequestContext& ctx) {      }      NFP::TagInfo tag_info{}; -    const auto result = device.value()->GetTagInfo(tag_info); +    const auto result = device.value()->GetTagInfo(tag_info, false);      ctx.WriteBuffer(tag_info);      IPC::ResponseBuilder rb{ctx, 2};      rb.Push(result); diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index 69858096a..fc228c2b2 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h @@ -106,11 +106,24 @@ enum class CabinetMode : u8 {      StartFormatter,  }; +enum class MifareCmd : u8 { +    AuthA = 0x60, +    AuthB = 0x61, +    Read = 0x30, +    Write = 0xA0, +    Transfer = 0xB0, +    Decrement = 0xC0, +    Increment = 0xC1, +    Store = 0xC2 +}; +  using UniqueSerialNumber = std::array<u8, 7>;  using LockBytes = std::array<u8, 2>;  using HashData = std::array<u8, 0x20>;  using ApplicationArea = std::array<u8, 0xD8>;  using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>; +using DataBlock = std::array<u8, 0x10>; +using KeyData = std::array<u8, 0x6>;  struct TagUuid {      UniqueSerialNumber uid; @@ -323,4 +336,37 @@ struct RegisterInfo {  };  static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); +struct SectorKey { +    MifareCmd command; +    u8 unknown; // Usually 1 +    INSERT_PADDING_BYTES(0x6); +    KeyData sector_key; +    INSERT_PADDING_BYTES(0x2); +}; +static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size"); + +struct MifareReadBlockParameter { +    u8 sector_number; +    INSERT_PADDING_BYTES(0x7); +    SectorKey sector_key; +}; +static_assert(sizeof(MifareReadBlockParameter) == 0x18, +              "MifareReadBlockParameter is an invalid size"); + +struct MifareReadBlockData { +    DataBlock data; +    u8 sector_number; +    INSERT_PADDING_BYTES(0x7); +}; +static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size"); + +struct MifareWriteBlockParameter { +    DataBlock data; +    u8 sector_number; +    INSERT_PADDING_BYTES(0x7); +    SectorKey sector_key; +}; +static_assert(sizeof(MifareWriteBlockParameter) == 0x28, +              "MifareWriteBlockParameter is an invalid size"); +  } // namespace Service::NFP diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index e3ef06481..4fa9f51a6 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -129,6 +129,9 @@ static_assert(sizeof(NifmNetworkProfileData) == 0x18E,                "NifmNetworkProfileData has incorrect size.");  #pragma pack(pop) +constexpr Result ResultPendingConnection{ErrorModule::NIFM, 111}; +constexpr Result ResultNetworkCommunicationDisabled{ErrorModule::NIFM, 1111}; +  class IScanRequest final : public ServiceFramework<IScanRequest> {  public:      explicit IScanRequest(Core::System& system_) : ServiceFramework{system_, "IScanRequest"} { @@ -192,6 +195,10 @@ private:      void Submit(Kernel::HLERequestContext& ctx) {          LOG_WARNING(Service_NIFM, "(STUBBED) called"); +        if (state == RequestState::NotSubmitted) { +            UpdateState(RequestState::Pending); +        } +          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(ResultSuccess);      } @@ -201,19 +208,32 @@ private:          IPC::ResponseBuilder rb{ctx, 3};          rb.Push(ResultSuccess); - -        if (Network::GetHostIPv4Address().has_value()) { -            rb.PushEnum(RequestState::Connected); -        } else { -            rb.PushEnum(RequestState::NotSubmitted); -        } +        rb.PushEnum(state);      }      void GetResult(Kernel::HLERequestContext& ctx) {          LOG_WARNING(Service_NIFM, "(STUBBED) called"); +        const auto result = [this] { +            const auto has_connection = Network::GetHostIPv4Address().has_value(); +            switch (state) { +            case RequestState::NotSubmitted: +                return has_connection ? ResultSuccess : ResultNetworkCommunicationDisabled; +            case RequestState::Pending: +                if (has_connection) { +                    UpdateState(RequestState::Connected); +                } else { +                    UpdateState(RequestState::Error); +                } +                return ResultPendingConnection; +            case RequestState::Connected: +            default: +                return ResultSuccess; +            } +        }(); +          IPC::ResponseBuilder rb{ctx, 2}; -        rb.Push(ResultSuccess); +        rb.Push(result);      }      void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) { @@ -252,8 +272,15 @@ private:          rb.Push<u32>(0);      } +    void UpdateState(RequestState new_state) { +        state = new_state; +        event1->Signal(); +    } +      KernelHelpers::ServiceContext service_context; +    RequestState state; +      Kernel::KEvent* event1;      Kernel::KEvent* event2;  }; diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 460bef976..9b22397db 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -11,6 +11,7 @@  #include <vector>  #include "common/common_types.h" +#include "common/polyfill_thread.h"  #include "core/hle/result.h"  #include "core/hle/service/kernel_helpers.h" diff --git a/src/core/internal_network/network_interface.cpp b/src/core/internal_network/network_interface.cpp index 057fd3661..7b8e510a2 100644 --- a/src/core/internal_network/network_interface.cpp +++ b/src/core/internal_network/network_interface.cpp @@ -9,6 +9,7 @@  #include "common/bit_cast.h"  #include "common/common_types.h"  #include "common/logging/log.h" +#include "common/polyfill_ranges.h"  #include "common/settings.h"  #include "common/string_util.h"  #include "core/internal_network/network_interface.h" diff --git a/src/core/precompiled_headers.h b/src/core/precompiled_headers.h new file mode 100644 index 000000000..30a31001d --- /dev/null +++ b/src/core/precompiled_headers.h @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <boost/container/flat_map.hpp> // used by service.h which is heavily included +#include <boost/intrusive/rbtree.hpp>   // used by k_auto_object.h which is heavily included + +#include "common/common_precompiled_headers.h" + +#include "core/hle/kernel/k_process.h" diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp index 6e21296f6..77821e047 100644 --- a/src/core/reporter.cpp +++ b/src/core/reporter.cpp @@ -38,7 +38,7 @@ std::string GetTimestamp() {  using namespace nlohmann; -void SaveToFile(json json, const std::filesystem::path& filename) { +void SaveToFile(const json& json, const std::filesystem::path& filename) {      if (!Common::FS::CreateParentDirs(filename)) {          LOG_ERROR(Core, "Failed to create path for '{}' to save report!",                    Common::FS::PathToUTF8String(filename)); @@ -81,8 +81,8 @@ json GetReportCommonData(u64 title_id, Result result, const std::string& timesta  }  json GetProcessorStateData(const std::string& architecture, u64 entry_point, u64 sp, u64 pc, -                           u64 pstate, std::array<u64, 31> registers, -                           std::optional<std::array<u64, 32>> backtrace = {}) { +                           u64 pstate, const std::array<u64, 31>& registers, +                           const std::optional<std::array<u64, 32>>& backtrace = {}) {      auto out = json{          {"entry_point", fmt::format("{:016X}", entry_point)},          {"sp", fmt::format("{:016X}", sp)}, @@ -224,11 +224,11 @@ void Reporter::SaveCrashReport(u64 title_id, Result result, u64 set_flags, u64 e      out["processor_state"] = std::move(proc_out); -    SaveToFile(std::move(out), GetPath("crash_report", title_id, timestamp)); +    SaveToFile(out, GetPath("crash_report", title_id, timestamp));  }  void Reporter::SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64 info2, -                                  std::optional<std::vector<u8>> resolved_buffer) const { +                                  const std::optional<std::vector<u8>>& resolved_buffer) const {      if (!IsReportingEnabled()) {          return;      } @@ -250,7 +250,7 @@ void Reporter::SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64      out["svc_break"] = std::move(break_out); -    SaveToFile(std::move(out), GetPath("svc_break_report", title_id, timestamp)); +    SaveToFile(out, GetPath("svc_break_report", title_id, timestamp));  }  void Reporter::SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u32 command_id, @@ -271,13 +271,13 @@ void Reporter::SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u      out["function"] = std::move(function_out); -    SaveToFile(std::move(out), GetPath("unimpl_func_report", title_id, timestamp)); +    SaveToFile(out, GetPath("unimpl_func_report", title_id, timestamp));  }  void Reporter::SaveUnimplementedAppletReport(      u32 applet_id, u32 common_args_version, u32 library_version, u32 theme_color, -    bool startup_sound, u64 system_tick, std::vector<std::vector<u8>> normal_channel, -    std::vector<std::vector<u8>> interactive_channel) const { +    bool startup_sound, u64 system_tick, const std::vector<std::vector<u8>>& normal_channel, +    const std::vector<std::vector<u8>>& interactive_channel) const {      if (!IsReportingEnabled()) {          return;      } @@ -308,10 +308,11 @@ void Reporter::SaveUnimplementedAppletReport(      out["applet_normal_data"] = std::move(normal_out);      out["applet_interactive_data"] = std::move(interactive_out); -    SaveToFile(std::move(out), GetPath("unimpl_applet_report", title_id, timestamp)); +    SaveToFile(out, GetPath("unimpl_applet_report", title_id, timestamp));  } -void Reporter::SavePlayReport(PlayReportType type, u64 title_id, std::vector<std::vector<u8>> data, +void Reporter::SavePlayReport(PlayReportType type, u64 title_id, +                              const std::vector<std::vector<u8>>& data,                                std::optional<u64> process_id, std::optional<u128> user_id) const {      if (!IsReportingEnabled()) {          return; @@ -335,12 +336,12 @@ void Reporter::SavePlayReport(PlayReportType type, u64 title_id, std::vector<std      out["play_report_type"] = fmt::format("{:02}", static_cast<u8>(type));      out["play_report_data"] = std::move(data_out); -    SaveToFile(std::move(out), GetPath("play_report", title_id, timestamp)); +    SaveToFile(out, GetPath("play_report", title_id, timestamp));  }  void Reporter::SaveErrorReport(u64 title_id, Result result, -                               std::optional<std::string> custom_text_main, -                               std::optional<std::string> custom_text_detail) const { +                               const std::optional<std::string>& custom_text_main, +                               const std::optional<std::string>& custom_text_detail) const {      if (!IsReportingEnabled()) {          return;      } @@ -354,11 +355,11 @@ void Reporter::SaveErrorReport(u64 title_id, Result result,      out["backtrace"] = GetBacktraceData(system);      out["error_custom_text"] = { -        {"main", *custom_text_main}, -        {"detail", *custom_text_detail}, +        {"main", custom_text_main.value_or("")}, +        {"detail", custom_text_detail.value_or("")},      }; -    SaveToFile(std::move(out), GetPath("error_report", title_id, timestamp)); +    SaveToFile(out, GetPath("error_report", title_id, timestamp));  }  void Reporter::SaveFSAccessLog(std::string_view log_message) const { diff --git a/src/core/reporter.h b/src/core/reporter.h index 68755cbde..9fdb9d6c1 100644 --- a/src/core/reporter.h +++ b/src/core/reporter.h @@ -36,7 +36,7 @@ public:      // Used by syscall svcBreak      void SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64 info2, -                            std::optional<std::vector<u8>> resolved_buffer = {}) const; +                            const std::optional<std::vector<u8>>& resolved_buffer = {}) const;      // Used by HLE service handler      void SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u32 command_id, @@ -44,10 +44,10 @@ public:                                           const std::string& service_name) const;      // Used by stub applet implementation -    void SaveUnimplementedAppletReport(u32 applet_id, u32 common_args_version, u32 library_version, -                                       u32 theme_color, bool startup_sound, u64 system_tick, -                                       std::vector<std::vector<u8>> normal_channel, -                                       std::vector<std::vector<u8>> interactive_channel) const; +    void SaveUnimplementedAppletReport( +        u32 applet_id, u32 common_args_version, u32 library_version, u32 theme_color, +        bool startup_sound, u64 system_tick, const std::vector<std::vector<u8>>& normal_channel, +        const std::vector<std::vector<u8>>& interactive_channel) const;      enum class PlayReportType {          Old, @@ -56,13 +56,13 @@ public:          System,      }; -    void SavePlayReport(PlayReportType type, u64 title_id, std::vector<std::vector<u8>> data, +    void SavePlayReport(PlayReportType type, u64 title_id, const std::vector<std::vector<u8>>& data,                          std::optional<u64> process_id = {}, std::optional<u128> user_id = {}) const;      // Used by error applet      void SaveErrorReport(u64 title_id, Result result, -                         std::optional<std::string> custom_text_main = {}, -                         std::optional<std::string> custom_text_detail = {}) const; +                         const std::optional<std::string>& custom_text_main = {}, +                         const std::optional<std::string>& custom_text_detail = {}) const;      void SaveFSAccessLog(std::string_view log_message) const; diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index abcf6eb11..8d5f2be2f 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -55,6 +55,8 @@ static const char* TranslateRenderer(Settings::RendererBackend backend) {          return "OpenGL";      case Settings::RendererBackend::Vulkan:          return "Vulkan"; +    case Settings::RendererBackend::Null: +        return "Null";      }      return "Unknown";  } diff --git a/src/dedicated_room/CMakeLists.txt b/src/dedicated_room/CMakeLists.txt index 2d9731f19..5bbe1d4b5 100644 --- a/src/dedicated_room/CMakeLists.txt +++ b/src/dedicated_room/CMakeLists.txt @@ -4,6 +4,7 @@  set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules)  add_executable(yuzu-room +    precompiled_headers.h      yuzu_room.cpp      yuzu_room.rc  ) @@ -25,3 +26,7 @@ target_link_libraries(yuzu-room PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)  if(UNIX AND NOT APPLE)      install(TARGETS yuzu-room)  endif() + +if (YUZU_USE_PRECOMPILED_HEADERS) +    target_precompile_headers(yuzu-room PRIVATE precompiled_headers.h) +endif() diff --git a/src/dedicated_room/precompiled_headers.h b/src/dedicated_room/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/dedicated_room/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 193127d0a..7932aaab0 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -34,6 +34,7 @@ add_library(input_common STATIC      input_poller.h      main.cpp      main.h +    precompiled_headers.h  )  if (MSVC) @@ -55,15 +56,13 @@ if (ENABLE_SDL2)          drivers/sdl_driver.cpp          drivers/sdl_driver.h      ) -    if (YUZU_USE_EXTERNAL_SDL2) -        target_link_libraries(input_common PRIVATE SDL2-static) -    else() -        target_link_libraries(input_common PRIVATE SDL2) -    endif() +    target_link_libraries(input_common PRIVATE SDL2::SDL2)      target_compile_definitions(input_common PRIVATE HAVE_SDL2)  endif() -target_link_libraries(input_common PRIVATE usb) -  create_target_directory_groups(input_common) -target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost) +target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost libusb::usb) + +if (YUZU_USE_PRECOMPILED_HEADERS) +    target_precompile_headers(input_common PRIVATE precompiled_headers.h) +endif() diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index 7f81767f7..b5270fd0b 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -5,10 +5,10 @@  #include <array>  #include <memory> -#include <stop_token>  #include <string>  #include <thread> +#include "common/polyfill_thread.h"  #include "input_common/input_engine.h"  struct libusb_context; diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 98c3157a8..faf9cbdc3 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -1,7 +1,6 @@  // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project  // SPDX-License-Identifier: GPL-2.0-or-later -#include <stop_token>  #include <thread>  #include <fmt/format.h> diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index 286ce1cf6..72073cc23 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -3,9 +3,9 @@  #pragma once -#include <stop_token>  #include <thread> +#include "common/polyfill_thread.h"  #include "common/vector_math.h"  #include "input_common/input_engine.h" diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 21c6ed405..f3ade90da 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -2,6 +2,7 @@  // SPDX-License-Identifier: GPL-2.0-or-later  #include <cstring> +#include <sstream>  #include <fmt/format.h>  #include "common/fs/file.h" diff --git a/src/input_common/drivers/virtual_amiibo.cpp b/src/input_common/drivers/virtual_amiibo.cpp index 564a188e5..63ffaca67 100644 --- a/src/input_common/drivers/virtual_amiibo.cpp +++ b/src/input_common/drivers/virtual_amiibo.cpp @@ -47,20 +47,20 @@ Common::Input::NfcState VirtualAmiibo::SupportsNfc(  Common::Input::NfcState VirtualAmiibo::WriteNfcData(      [[maybe_unused]] const PadIdentifier& identifier_, const std::vector<u8>& data) { -    const Common::FS::IOFile amiibo_file{file_path, Common::FS::FileAccessMode::ReadWrite, -                                         Common::FS::FileType::BinaryFile}; +    const Common::FS::IOFile nfc_file{file_path, Common::FS::FileAccessMode::ReadWrite, +                                      Common::FS::FileType::BinaryFile}; -    if (!amiibo_file.IsOpen()) { +    if (!nfc_file.IsOpen()) {          LOG_ERROR(Core, "Amiibo is already on use");          return Common::Input::NfcState::WriteFailed;      } -    if (!amiibo_file.Write(data)) { +    if (!nfc_file.Write(data)) {          LOG_ERROR(Service_NFP, "Error writting to file");          return Common::Input::NfcState::WriteFailed;      } -    amiibo_data = data; +    nfc_data = data;      return Common::Input::NfcState::Success;  } @@ -70,32 +70,44 @@ VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const {  }  VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(const std::string& filename) { -    const Common::FS::IOFile amiibo_file{filename, Common::FS::FileAccessMode::Read, -                                         Common::FS::FileType::BinaryFile}; +    const Common::FS::IOFile nfc_file{filename, Common::FS::FileAccessMode::Read, +                                      Common::FS::FileType::BinaryFile};      if (state != State::WaitingForAmiibo) {          return Info::WrongDeviceState;      } -    if (!amiibo_file.IsOpen()) { +    if (!nfc_file.IsOpen()) {          return Info::UnableToLoad;      } -    amiibo_data.resize(amiibo_size); - -    if (amiibo_file.Read(amiibo_data) < amiibo_size_without_password) { +    switch (nfc_file.GetSize()) { +    case AmiiboSize: +    case AmiiboSizeWithoutPassword: +        nfc_data.resize(AmiiboSize); +        if (nfc_file.Read(nfc_data) < AmiiboSizeWithoutPassword) { +            return Info::NotAnAmiibo; +        } +        break; +    case MifareSize: +        nfc_data.resize(MifareSize); +        if (nfc_file.Read(nfc_data) < MifareSize) { +            return Info::NotAnAmiibo; +        } +        break; +    default:          return Info::NotAnAmiibo;      }      file_path = filename;      state = State::AmiiboIsOpen; -    SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, amiibo_data}); +    SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data});      return Info::Success;  }  VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() {      if (state == State::AmiiboIsOpen) { -        SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, amiibo_data}); +        SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data});          return Info::Success;      } diff --git a/src/input_common/drivers/virtual_amiibo.h b/src/input_common/drivers/virtual_amiibo.h index 9baeb3997..0f9dad333 100644 --- a/src/input_common/drivers/virtual_amiibo.h +++ b/src/input_common/drivers/virtual_amiibo.h @@ -53,12 +53,13 @@ public:      std::string GetLastFilePath() const;  private: -    static constexpr std::size_t amiibo_size = 0x21C; -    static constexpr std::size_t amiibo_size_without_password = amiibo_size - 0x8; +    static constexpr std::size_t AmiiboSize = 0x21C; +    static constexpr std::size_t AmiiboSizeWithoutPassword = AmiiboSize - 0x8; +    static constexpr std::size_t MifareSize = 0x400;      std::string file_path{};      State state{State::Initialized}; -    std::vector<u8> amiibo_data; +    std::vector<u8> nfc_data;      Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Pasive};  };  } // namespace InputCommon diff --git a/src/input_common/precompiled_headers.h b/src/input_common/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/input_common/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 6f8ca4b90..1ab52da59 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(network STATIC      network.h      packet.cpp      packet.h +    precompiled_headers.h      room.cpp      room.h      room_member.cpp @@ -18,8 +19,12 @@ add_library(network STATIC  create_target_directory_groups(network) -target_link_libraries(network PRIVATE common enet Boost::boost) +target_link_libraries(network PRIVATE common enet::enet Boost::boost)  if (ENABLE_WEB_SERVICE)      target_compile_definitions(network PRIVATE -DENABLE_WEB_SERVICE)      target_link_libraries(network PRIVATE web_service)  endif() + +if (YUZU_USE_PRECOMPILED_HEADERS) +    target_precompile_headers(network PRIVATE precompiled_headers.h) +endif() diff --git a/src/network/precompiled_headers.h b/src/network/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/network/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt index 545d69c7e..525b2363c 100644 --- a/src/shader_recompiler/CMakeLists.txt +++ b/src/shader_recompiler/CMakeLists.txt @@ -221,6 +221,7 @@ add_library(shader_recompiler STATIC      ir_opt/dual_vertex_pass.cpp      ir_opt/global_memory_to_storage_buffer_pass.cpp      ir_opt/identity_removal_pass.cpp +    ir_opt/layer_pass.cpp      ir_opt/lower_fp16_to_fp32.cpp      ir_opt/lower_int64_to_int32.cpp      ir_opt/passes.h @@ -230,6 +231,7 @@ add_library(shader_recompiler STATIC      ir_opt/texture_pass.cpp      ir_opt/verification_pass.cpp      object_pool.h +    precompiled_headers.h      profile.h      program_header.h      runtime_info.h @@ -254,7 +256,12 @@ else()          # Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6.          # And this in turns limits the size of a std::array.          $<$<CXX_COMPILER_ID:Clang>:-fbracket-depth=1024> +        $<$<CXX_COMPILER_ID:AppleClang>:-fbracket-depth=1024>      )  endif()  create_target_directory_groups(shader_recompiler) + +if (YUZU_USE_PRECOMPILED_HEADERS) +    target_precompile_headers(shader_recompiler PRIVATE precompiled_headers.h) +endif() diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 265ac9c85..0f86a8004 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp @@ -402,8 +402,10 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct          ctx.AddCapability(spv::Capability::SparseResidency);      }      if (info.uses_demote_to_helper_invocation && profile.support_demote_to_helper_invocation) { -        ctx.AddExtension("SPV_EXT_demote_to_helper_invocation"); -        ctx.AddCapability(spv::Capability::DemoteToHelperInvocationEXT); +        if (profile.supported_spirv < 0x00010600) { +            ctx.AddExtension("SPV_EXT_demote_to_helper_invocation"); +        } +        ctx.AddCapability(spv::Capability::DemoteToHelperInvocation);      }      if (info.stores[IR::Attribute::ViewportIndex]) {          ctx.AddCapability(spv::Capability::MultiViewport); @@ -426,12 +428,11 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct      if ((info.uses_subgroup_vote || info.uses_subgroup_invocation_id ||           info.uses_subgroup_shuffles) &&          profile.support_vote) { -        ctx.AddExtension("SPV_KHR_shader_ballot"); -        ctx.AddCapability(spv::Capability::SubgroupBallotKHR); +        ctx.AddCapability(spv::Capability::GroupNonUniformBallot); +        ctx.AddCapability(spv::Capability::GroupNonUniformShuffle);          if (!profile.warp_size_potentially_larger_than_guest) {              // vote ops are only used when not taking the long path -            ctx.AddExtension("SPV_KHR_subgroup_vote"); -            ctx.AddCapability(spv::Capability::SubgroupVoteKHR); +            ctx.AddCapability(spv::Capability::GroupNonUniformVote);          }      }      if (info.uses_int64_bit_atomics && profile.support_int64_atomics) { diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp index 7ad0b08ac..fb2c792c1 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_control_flow.cpp @@ -12,7 +12,7 @@ void EmitJoin(EmitContext&) {  void EmitDemoteToHelperInvocation(EmitContext& ctx) {      if (ctx.profile.support_demote_to_helper_invocation) { -        ctx.OpDemoteToHelperInvocationEXT(); +        ctx.OpDemoteToHelperInvocation();      } else {          const Id kill_label{ctx.OpLabel()};          const Id impossible_label{ctx.OpLabel()}; diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp index 7cbbbfaa6..2c90f2368 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_warp.cpp @@ -6,6 +6,10 @@  namespace Shader::Backend::SPIRV {  namespace { +Id SubgroupScope(EmitContext& ctx) { +    return ctx.Const(static_cast<u32>(spv::Scope::Subgroup)); +} +  Id GetThreadId(EmitContext& ctx) {      return ctx.OpLoad(ctx.U32[1], ctx.subgroup_local_invocation_id);  } @@ -49,8 +53,9 @@ Id GetMaxThreadId(EmitContext& ctx, Id thread_id, Id clamp, Id segmentation_mask  }  Id SelectValue(EmitContext& ctx, Id in_range, Id value, Id src_thread_id) { -    return ctx.OpSelect(ctx.U32[1], in_range, -                        ctx.OpSubgroupReadInvocationKHR(ctx.U32[1], value, src_thread_id), value); +    return ctx.OpSelect( +        ctx.U32[1], in_range, +        ctx.OpGroupNonUniformShuffle(ctx.U32[1], SubgroupScope(ctx), value, src_thread_id), value);  }  Id GetUpperClamp(EmitContext& ctx, Id invocation_id, Id clamp) { @@ -71,40 +76,46 @@ Id EmitLaneId(EmitContext& ctx) {  Id EmitVoteAll(EmitContext& ctx, Id pred) {      if (!ctx.profile.warp_size_potentially_larger_than_guest) { -        return ctx.OpSubgroupAllKHR(ctx.U1, pred); +        return ctx.OpGroupNonUniformAll(ctx.U1, SubgroupScope(ctx), pred);      } -    const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; +    const Id mask_ballot{ +        ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)};      const Id active_mask{WarpExtract(ctx, mask_ballot)}; -    const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; +    const Id ballot{ +        WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))};      const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)};      return ctx.OpIEqual(ctx.U1, lhs, active_mask);  }  Id EmitVoteAny(EmitContext& ctx, Id pred) {      if (!ctx.profile.warp_size_potentially_larger_than_guest) { -        return ctx.OpSubgroupAnyKHR(ctx.U1, pred); +        return ctx.OpGroupNonUniformAny(ctx.U1, SubgroupScope(ctx), pred);      } -    const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; +    const Id mask_ballot{ +        ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)};      const Id active_mask{WarpExtract(ctx, mask_ballot)}; -    const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; +    const Id ballot{ +        WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))};      const Id lhs{ctx.OpBitwiseAnd(ctx.U32[1], ballot, active_mask)};      return ctx.OpINotEqual(ctx.U1, lhs, ctx.u32_zero_value);  }  Id EmitVoteEqual(EmitContext& ctx, Id pred) {      if (!ctx.profile.warp_size_potentially_larger_than_guest) { -        return ctx.OpSubgroupAllEqualKHR(ctx.U1, pred); +        return ctx.OpGroupNonUniformAllEqual(ctx.U1, SubgroupScope(ctx), pred);      } -    const Id mask_ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], ctx.true_value)}; +    const Id mask_ballot{ +        ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), ctx.true_value)};      const Id active_mask{WarpExtract(ctx, mask_ballot)}; -    const Id ballot{WarpExtract(ctx, ctx.OpSubgroupBallotKHR(ctx.U32[4], pred))}; +    const Id ballot{ +        WarpExtract(ctx, ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred))};      const Id lhs{ctx.OpBitwiseXor(ctx.U32[1], ballot, active_mask)};      return ctx.OpLogicalOr(ctx.U1, ctx.OpIEqual(ctx.U1, lhs, ctx.u32_zero_value),                             ctx.OpIEqual(ctx.U1, lhs, active_mask));  }  Id EmitSubgroupBallot(EmitContext& ctx, Id pred) { -    const Id ballot{ctx.OpSubgroupBallotKHR(ctx.U32[4], pred)}; +    const Id ballot{ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred)};      if (!ctx.profile.warp_size_potentially_larger_than_guest) {          return ctx.OpCompositeExtract(ctx.U32[1], ballot, 0U);      } diff --git a/src/shader_recompiler/frontend/ir/opcodes.h b/src/shader_recompiler/frontend/ir/opcodes.h index e70d7745c..d155afd0f 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.h +++ b/src/shader_recompiler/frontend/ir/opcodes.h @@ -8,6 +8,7 @@  #include <fmt/format.h> +#include "common/polyfill_ranges.h"  #include "shader_recompiler/frontend/ir/type.h"  namespace Shader::IR { diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h index e8bbb93a5..8b34356fd 100644 --- a/src/shader_recompiler/frontend/ir/value.h +++ b/src/shader_recompiler/frontend/ir/value.h @@ -23,7 +23,6 @@  #include "shader_recompiler/frontend/ir/pred.h"  #include "shader_recompiler/frontend/ir/reg.h"  #include "shader_recompiler/frontend/ir/type.h" -#include "shader_recompiler/frontend/ir/value.h"  namespace Shader::IR { diff --git a/src/shader_recompiler/frontend/maxwell/control_flow.cpp b/src/shader_recompiler/frontend/maxwell/control_flow.cpp index 6939692cd..dce414cb4 100644 --- a/src/shader_recompiler/frontend/maxwell/control_flow.cpp +++ b/src/shader_recompiler/frontend/maxwell/control_flow.cpp @@ -9,6 +9,7 @@  #include <fmt/format.h> +#include "common/polyfill_ranges.h"  #include "shader_recompiler/exception.h"  #include "shader_recompiler/frontend/maxwell/control_flow.h"  #include "shader_recompiler/frontend/maxwell/decode.h" diff --git a/src/shader_recompiler/frontend/maxwell/decode.cpp b/src/shader_recompiler/frontend/maxwell/decode.cpp index 455c91470..774f65bc5 100644 --- a/src/shader_recompiler/frontend/maxwell/decode.cpp +++ b/src/shader_recompiler/frontend/maxwell/decode.cpp @@ -7,6 +7,7 @@  #include <memory>  #include "common/common_types.h" +#include "common/polyfill_ranges.h"  #include "shader_recompiler/exception.h"  #include "shader_recompiler/frontend/maxwell/decode.h"  #include "shader_recompiler/frontend/maxwell/opcodes.h" diff --git a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp index ce42475d4..80c90fe6a 100644 --- a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp +++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp @@ -12,6 +12,7 @@  #include <boost/intrusive/list.hpp> +#include "common/polyfill_ranges.h"  #include "shader_recompiler/environment.h"  #include "shader_recompiler/frontend/ir/basic_block.h"  #include "shader_recompiler/frontend/ir/ir_emitter.h" diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp index 4942878b9..85c18d942 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp @@ -176,12 +176,13 @@ void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a) {          (f2i.src_format == SrcFormat::F64) != (f2i.dest_format == DestFormat::I64);      if (special_nan_cases) {          if (f2i.dest_format == DestFormat::I32) { +            constexpr u32 nan_value = 0x8000'0000U;              handled_special_case = true; -            result = IR::U32{v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm32(0x8000'0000U), result)}; +            result = IR::U32{v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm32(nan_value), result)};          } else if (f2i.dest_format == DestFormat::I64) { +            constexpr u64 nan_value = 0x8000'0000'0000'0000ULL;              handled_special_case = true; -            result = IR::U64{ -                v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm64(0x8000'0000'0000'0000UL), result)}; +            result = IR::U64{v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm64(nan_value), result)};          }      }      if (!handled_special_case && is_signed) { diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp index 376aae0ea..3adbd2b16 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate_program.cpp @@ -9,6 +9,7 @@  #include "common/settings.h"  #include "shader_recompiler/exception.h"  #include "shader_recompiler/frontend/ir/basic_block.h" +#include "shader_recompiler/frontend/ir/ir_emitter.h"  #include "shader_recompiler/frontend/ir/post_order.h"  #include "shader_recompiler/frontend/maxwell/structured_control_flow.h"  #include "shader_recompiler/frontend/maxwell/translate/translate.h" @@ -233,6 +234,8 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo          Optimization::VerificationPass(program);      }      Optimization::CollectShaderInfoPass(env, program); +    Optimization::LayerPass(program, host_info); +      CollectInterpolationInfo(env, program);      AddNVNStorageBuffers(program);      return program; @@ -331,4 +334,82 @@ void ConvertLegacyToGeneric(IR::Program& program, const Shader::RuntimeInfo& run      }  } +IR::Program GenerateGeometryPassthrough(ObjectPool<IR::Inst>& inst_pool, +                                        ObjectPool<IR::Block>& block_pool, +                                        const HostTranslateInfo& host_info, +                                        IR::Program& source_program, +                                        Shader::OutputTopology output_topology) { +    IR::Program program; +    program.stage = Stage::Geometry; +    program.output_topology = output_topology; +    switch (output_topology) { +    case OutputTopology::PointList: +        program.output_vertices = 1; +        break; +    case OutputTopology::LineStrip: +        program.output_vertices = 2; +        break; +    default: +        program.output_vertices = 3; +        break; +    } + +    program.is_geometry_passthrough = false; +    program.info.loads.mask = source_program.info.stores.mask; +    program.info.stores.mask = source_program.info.stores.mask; +    program.info.stores.Set(IR::Attribute::Layer, true); +    program.info.stores.Set(source_program.info.emulated_layer, false); + +    IR::Block* current_block = block_pool.Create(inst_pool); +    auto& node{program.syntax_list.emplace_back()}; +    node.type = IR::AbstractSyntaxNode::Type::Block; +    node.data.block = current_block; + +    IR::IREmitter ir{*current_block}; +    for (u32 i = 0; i < program.output_vertices; i++) { +        // Assign generics from input +        for (u32 j = 0; j < 32; j++) { +            if (!program.info.stores.Generic(j)) { +                continue; +            } + +            const IR::Attribute attr = IR::Attribute::Generic0X + (j * 4); +            ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0)); +            ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0)); +            ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0)); +            ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0)); +        } + +        // Assign position from input +        const IR::Attribute attr = IR::Attribute::PositionX; +        ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0)); +        ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0)); +        ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0)); +        ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0)); + +        // Assign layer +        ir.SetAttribute(IR::Attribute::Layer, ir.GetAttribute(source_program.info.emulated_layer), +                        ir.Imm32(0)); + +        // Emit vertex +        ir.EmitVertex(ir.Imm32(0)); +    } +    ir.EndPrimitive(ir.Imm32(0)); + +    IR::Block* return_block{block_pool.Create(inst_pool)}; +    IR::IREmitter{*return_block}.Epilogue(); +    current_block->AddBranch(return_block); + +    auto& merge{program.syntax_list.emplace_back()}; +    merge.type = IR::AbstractSyntaxNode::Type::Block; +    merge.data.block = return_block; +    program.syntax_list.emplace_back().type = IR::AbstractSyntaxNode::Type::Return; + +    program.blocks = GenerateBlocks(program.syntax_list); +    program.post_order_blocks = PostOrder(program.syntax_list.front()); +    Optimization::SsaRewritePass(program); + +    return program; +} +  } // namespace Shader::Maxwell diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.h b/src/shader_recompiler/frontend/maxwell/translate_program.h index 02ede8c9c..497afe7cb 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.h +++ b/src/shader_recompiler/frontend/maxwell/translate_program.h @@ -25,4 +25,13 @@ namespace Shader::Maxwell {  void ConvertLegacyToGeneric(IR::Program& program, const RuntimeInfo& runtime_info); +// Maxwell v1 and older Nvidia cards don't support setting gl_Layer from non-geometry stages. +// This creates a workaround by setting the layer as a generic output and creating a +// passthrough geometry shader that reads the generic and sets the layer. +[[nodiscard]] IR::Program GenerateGeometryPassthrough(ObjectPool<IR::Inst>& inst_pool, +                                                      ObjectPool<IR::Block>& block_pool, +                                                      const HostTranslateInfo& host_info, +                                                      IR::Program& source_program, +                                                      Shader::OutputTopology output_topology); +  } // namespace Shader::Maxwell diff --git a/src/shader_recompiler/host_translate_info.h b/src/shader_recompiler/host_translate_info.h index cc1500690..d5d279554 100644 --- a/src/shader_recompiler/host_translate_info.h +++ b/src/shader_recompiler/host_translate_info.h @@ -13,7 +13,8 @@ struct HostTranslateInfo {      bool support_float16{};      ///< True when the device supports 16-bit floats      bool support_int64{};        ///< True when the device supports 64-bit integers      bool needs_demote_reorder{}; ///< True when the device needs DemoteToHelperInvocation reordered -    bool support_snorm_render_buffer{}; ///< True when the device supports SNORM render buffers +    bool support_snorm_render_buffer{};  ///< True when the device supports SNORM render buffers +    bool support_viewport_index_layer{}; ///< True when the device supports gl_Layer in VS  };  } // namespace Shader diff --git a/src/shader_recompiler/ir_opt/layer_pass.cpp b/src/shader_recompiler/ir_opt/layer_pass.cpp new file mode 100644 index 000000000..4574f7cf2 --- /dev/null +++ b/src/shader_recompiler/ir_opt/layer_pass.cpp @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <algorithm> +#include <bit> +#include <optional> + +#include <boost/container/small_vector.hpp> + +#include "shader_recompiler/environment.h" +#include "shader_recompiler/frontend/ir/basic_block.h" +#include "shader_recompiler/frontend/ir/breadth_first_search.h" +#include "shader_recompiler/frontend/ir/ir_emitter.h" +#include "shader_recompiler/host_translate_info.h" +#include "shader_recompiler/ir_opt/passes.h" +#include "shader_recompiler/shader_info.h" + +namespace Shader::Optimization { + +static IR::Attribute EmulatedLayerAttribute(VaryingState& stores) { +    for (u32 i = 0; i < 32; i++) { +        if (!stores.Generic(i)) { +            return IR::Attribute::Generic0X + (i * 4); +        } +    } +    return IR::Attribute::Layer; +} + +static bool PermittedProgramStage(Stage stage) { +    switch (stage) { +    case Stage::VertexA: +    case Stage::VertexB: +    case Stage::TessellationControl: +    case Stage::TessellationEval: +        return true; +    default: +        return false; +    } +} + +void LayerPass(IR::Program& program, const HostTranslateInfo& host_info) { +    if (host_info.support_viewport_index_layer || !PermittedProgramStage(program.stage)) { +        return; +    } + +    const auto end{program.post_order_blocks.end()}; +    const auto layer_attribute = EmulatedLayerAttribute(program.info.stores); +    bool requires_layer_emulation = false; + +    for (auto block = program.post_order_blocks.begin(); block != end; ++block) { +        for (IR::Inst& inst : (*block)->Instructions()) { +            if (inst.GetOpcode() == IR::Opcode::SetAttribute && +                inst.Arg(0).Attribute() == IR::Attribute::Layer) { +                requires_layer_emulation = true; +                inst.SetArg(0, IR::Value{layer_attribute}); +            } +        } +    } + +    if (requires_layer_emulation) { +        program.info.requires_layer_emulation = true; +        program.info.emulated_layer = layer_attribute; +        program.info.stores.Set(IR::Attribute::Layer, false); +        program.info.stores.Set(layer_attribute, true); +    } +} + +} // namespace Shader::Optimization diff --git a/src/shader_recompiler/ir_opt/passes.h b/src/shader_recompiler/ir_opt/passes.h index 586a0668f..11bfe801a 100644 --- a/src/shader_recompiler/ir_opt/passes.h +++ b/src/shader_recompiler/ir_opt/passes.h @@ -23,6 +23,7 @@ void RescalingPass(IR::Program& program);  void SsaRewritePass(IR::Program& program);  void PositionPass(Environment& env, IR::Program& program);  void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info); +void LayerPass(IR::Program& program, const HostTranslateInfo& host_info);  void VerificationPass(const IR::Program& program);  // Dual Vertex diff --git a/src/shader_recompiler/precompiled_headers.h b/src/shader_recompiler/precompiled_headers.h new file mode 100644 index 000000000..5dd6b7eca --- /dev/null +++ b/src/shader_recompiler/precompiled_headers.h @@ -0,0 +1,7 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" +#include "frontend/maxwell/translate/impl/impl.h" diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index ee6252bb5..d9c6e92db 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h @@ -204,6 +204,9 @@ struct Info {      u32 nvn_buffer_base{};      std::bitset<16> nvn_buffer_used{}; +    bool requires_layer_emulation{}; +    IR::Attribute emulated_layer{}; +      boost::container::static_vector<ConstantBufferDescriptor, MAX_CBUFS>          constant_buffer_descriptors;      boost::container::static_vector<StorageBufferDescriptor, MAX_SSBOS> storage_buffers_descriptors; diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 43ad2c7ff..348d1edf4 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -11,6 +11,7 @@ add_executable(tests      common/unique_function.cpp      core/core_timing.cpp      core/internal_network/network.cpp +    precompiled_headers.h      tests.cpp      video_core/buffer_base.cpp      input_common/calibration_configuration_job.cpp @@ -22,3 +23,7 @@ target_link_libraries(tests PRIVATE common core input_common)  target_link_libraries(tests PRIVATE ${PLATFORM_LIBRARIES} Catch2::Catch2 Threads::Threads)  add_test(NAME tests COMMAND tests) + +if (YUZU_USE_PRECOMPILED_HEADERS) +    target_precompile_headers(tests PRIVATE precompiled_headers.h) +endif() diff --git a/src/tests/precompiled_headers.h b/src/tests/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/tests/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index b03a30992..5096d935e 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -84,6 +84,7 @@ add_library(video_core STATIC      gpu_thread.h      memory_manager.cpp      memory_manager.h +    precompiled_headers.h      pte_kind.h      query_cache.h      rasterizer_accelerated.cpp @@ -91,6 +92,10 @@ add_library(video_core STATIC      rasterizer_interface.h      renderer_base.cpp      renderer_base.h +    renderer_null/null_rasterizer.cpp +    renderer_null/null_rasterizer.h +    renderer_null/renderer_null.cpp +    renderer_null/renderer_null.h      renderer_opengl/gl_buffer_cache.cpp      renderer_opengl/gl_buffer_cache.h      renderer_opengl/gl_compute_pipeline.cpp @@ -259,8 +264,7 @@ target_link_options(video_core PRIVATE ${FFmpeg_LDFLAGS})  add_dependencies(video_core host_shaders)  target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) -target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include) -target_link_libraries(video_core PRIVATE sirit) +target_link_libraries(video_core PRIVATE sirit Vulkan::Headers)  if (ENABLE_NSIGHT_AFTERMATH)      if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK}) @@ -279,9 +283,15 @@ if (MSVC)          /we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data      )  else() -    target_compile_options(video_core PRIVATE -        -Werror=conversion +    if (APPLE) +        # error: declaration shadows a typedef in 'interval_base_set<SubType, DomainT, Compare, Interval, Alloc>' +        # error: implicit conversion loses integer precision: 'int' to 'boost::icl::bound_type' (aka 'unsigned char') +        target_compile_options(video_core PRIVATE -Wno-shadow -Wno-unused-local-typedef) +    else() +        target_compile_options(video_core PRIVATE -Werror=conversion) +    endif() +    target_compile_options(video_core PRIVATE          -Wno-sign-conversion      ) @@ -294,9 +304,13 @@ if (ARCHITECTURE_x86_64)          macro/macro_jit_x64.cpp          macro/macro_jit_x64.h      ) -    target_link_libraries(video_core PUBLIC xbyak) +    target_link_libraries(video_core PUBLIC xbyak::xbyak)  endif()  if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) -    target_link_libraries(video_core PRIVATE dynarmic) +    target_link_libraries(video_core PRIVATE dynarmic::dynarmic) +endif() + +if (YUZU_USE_PRECOMPILED_HEADERS) +    target_precompile_headers(video_core PRIVATE precompiled_headers.h)  endif() diff --git a/src/video_core/buffer_cache/buffer_base.h b/src/video_core/buffer_cache/buffer_base.h index f9a6472cf..92d77eef2 100644 --- a/src/video_core/buffer_cache/buffer_base.h +++ b/src/video_core/buffer_cache/buffer_base.h @@ -535,7 +535,7 @@ private:          const u64* const state_words = Array<type>();          const u64 num_query_words = size / BYTES_PER_WORD + 1;          const u64 word_begin = offset / BYTES_PER_WORD; -        const u64 word_end = std::min(word_begin + num_query_words, NumWords()); +        const u64 word_end = std::min<u64>(word_begin + num_query_words, NumWords());          const u64 page_limit = Common::DivCeil(offset + size, BYTES_PER_PAGE);          u64 page_index = (offset / BYTES_PER_PAGE) % PAGES_PER_WORD;          for (u64 word_index = word_begin; word_index < word_end; ++word_index, page_index = 0) { diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 5d3a8293b..6881b34c4 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -19,6 +19,7 @@  #include "common/literals.h"  #include "common/lru_cache.h"  #include "common/microprofile.h" +#include "common/polyfill_ranges.h"  #include "common/settings.h"  #include "core/memory.h"  #include "video_core/buffer_cache/buffer_base.h" diff --git a/src/video_core/control/channel_state_cache.h b/src/video_core/control/channel_state_cache.h index 584a0c26c..cdaf4f8d5 100644 --- a/src/video_core/control/channel_state_cache.h +++ b/src/video_core/control/channel_state_cache.h @@ -35,8 +35,6 @@ public:      explicit ChannelInfo(Tegra::Control::ChannelState& state);      ChannelInfo(const ChannelInfo& state) = delete;      ChannelInfo& operator=(const ChannelInfo&) = delete; -    ChannelInfo(ChannelInfo&& other) = default; -    ChannelInfo& operator=(ChannelInfo&& other) = default;      Tegra::Engines::Maxwell3D& maxwell3d;      Tegra::Engines::KeplerCompute& kepler_compute; diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 55462752c..fb9b9b94e 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -126,7 +126,6 @@ void Maxwell3D::InitializeRegisterDefaults() {      draw_command[MAXWELL3D_REG_INDEX(draw_inline_index)] = true;      draw_command[MAXWELL3D_REG_INDEX(inline_index_2x16.even)] = true;      draw_command[MAXWELL3D_REG_INDEX(inline_index_4x8.index0)] = true; -    draw_command[MAXWELL3D_REG_INDEX(draw.instance_id)] = true;  }  void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) { @@ -218,16 +217,19 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume          regs.index_buffer.count = regs.index_buffer32_first.count;          regs.index_buffer.first = regs.index_buffer32_first.first;          dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; +        draw_indexed = true;          return ProcessDraw();      case MAXWELL3D_REG_INDEX(index_buffer16_first):          regs.index_buffer.count = regs.index_buffer16_first.count;          regs.index_buffer.first = regs.index_buffer16_first.first;          dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; +        draw_indexed = true;          return ProcessDraw();      case MAXWELL3D_REG_INDEX(index_buffer8_first):          regs.index_buffer.count = regs.index_buffer8_first.count;          regs.index_buffer.first = regs.index_buffer8_first.first;          dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; +        draw_indexed = true;          return ProcessDraw();      case MAXWELL3D_REG_INDEX(topology_override):          use_topology_override = true; @@ -300,21 +302,33 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {              draw_mode = DrawMode::InlineIndex;          };          switch (method) { +        case MAXWELL3D_REG_INDEX(draw.begin): { +            draw_mode = +                (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) || +                        (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged) +                    ? DrawMode::Instance +                    : DrawMode::General; +            break; +        }          case MAXWELL3D_REG_INDEX(draw.end):              switch (draw_mode) {              case DrawMode::General: -                ProcessDraw(1); +                ProcessDraw();                  break;              case DrawMode::InlineIndex:                  regs.index_buffer.count = static_cast<u32>(inline_index_draw_indexes.size() / 4);                  regs.index_buffer.format = Regs::IndexFormat::UnsignedInt; -                ProcessDraw(1); +                draw_indexed = true; +                ProcessDraw();                  inline_index_draw_indexes.clear();                  break;              case DrawMode::Instance:                  break;              }              break; +        case MAXWELL3D_REG_INDEX(index_buffer.count): +            draw_indexed = true; +            break;          case MAXWELL3D_REG_INDEX(draw_inline_index):              update_inline_index(method_argument);              break; @@ -328,13 +342,6 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {              update_inline_index(regs.inline_index_4x8.index2);              update_inline_index(regs.inline_index_4x8.index3);              break; -        case MAXWELL3D_REG_INDEX(draw.instance_id): -            draw_mode = -                (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Subsequent) || -                        (regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::Unchanged) -                    ? DrawMode::Instance -                    : DrawMode::General; -            break;          }      } else {          ProcessDeferredDraw(); @@ -486,41 +493,51 @@ void Maxwell3D::ProcessQueryGet() {  void Maxwell3D::ProcessQueryCondition() {      const GPUVAddr condition_address{regs.render_enable.Address()}; -    switch (regs.render_enable.mode) { -    case Regs::RenderEnable::Mode::True: { +    switch (regs.render_enable_override) { +    case Regs::RenderEnable::Override::AlwaysRender:          execute_on = true;          break; -    } -    case Regs::RenderEnable::Mode::False: { +    case Regs::RenderEnable::Override::NeverRender:          execute_on = false;          break; -    } -    case Regs::RenderEnable::Mode::Conditional: { -        Regs::ReportSemaphore::Compare cmp; -        memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp)); -        execute_on = cmp.initial_sequence != 0U && cmp.initial_mode != 0U; -        break; -    } -    case Regs::RenderEnable::Mode::IfEqual: { -        Regs::ReportSemaphore::Compare cmp; -        memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp)); -        execute_on = -            cmp.initial_sequence == cmp.current_sequence && cmp.initial_mode == cmp.current_mode; -        break; -    } -    case Regs::RenderEnable::Mode::IfNotEqual: { -        Regs::ReportSemaphore::Compare cmp; -        memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp)); -        execute_on = -            cmp.initial_sequence != cmp.current_sequence || cmp.initial_mode != cmp.current_mode; -        break; -    } -    default: { -        UNIMPLEMENTED_MSG("Uninplemented Condition Mode!"); -        execute_on = true; +    case Regs::RenderEnable::Override::UseRenderEnable: +        switch (regs.render_enable.mode) { +        case Regs::RenderEnable::Mode::True: { +            execute_on = true; +            break; +        } +        case Regs::RenderEnable::Mode::False: { +            execute_on = false; +            break; +        } +        case Regs::RenderEnable::Mode::Conditional: { +            Regs::ReportSemaphore::Compare cmp; +            memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp)); +            execute_on = cmp.initial_sequence != 0U && cmp.initial_mode != 0U; +            break; +        } +        case Regs::RenderEnable::Mode::IfEqual: { +            Regs::ReportSemaphore::Compare cmp; +            memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp)); +            execute_on = cmp.initial_sequence == cmp.current_sequence && +                         cmp.initial_mode == cmp.current_mode; +            break; +        } +        case Regs::RenderEnable::Mode::IfNotEqual: { +            Regs::ReportSemaphore::Compare cmp; +            memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp)); +            execute_on = cmp.initial_sequence != cmp.current_sequence || +                         cmp.initial_mode != cmp.current_mode; +            break; +        } +        default: { +            UNIMPLEMENTED_MSG("Uninplemented Condition Mode!"); +            execute_on = true; +            break; +        } +        }          break;      } -    }  }  void Maxwell3D::ProcessCounterReset() { @@ -624,27 +641,16 @@ void Maxwell3D::ProcessClearBuffers(u32 layer_count) {  void Maxwell3D::ProcessDraw(u32 instance_count) {      LOG_TRACE(HW_GPU, "called, topology={}, count={}", regs.draw.topology.Value(), -              regs.vertex_buffer.count); - -    ASSERT_MSG(!(regs.index_buffer.count && regs.vertex_buffer.count), "Both indexed and direct?"); - -    // Both instance configuration registers can not be set at the same time. -    ASSERT_MSG(regs.draw.instance_id == Maxwell3D::Regs::Draw::InstanceId::First || -                   regs.draw.instance_id != Maxwell3D::Regs::Draw::InstanceId::Unchanged, -               "Illegal combination of instancing parameters"); +              draw_indexed ? regs.index_buffer.count : regs.vertex_buffer.count);      ProcessTopologyOverride(); -    const bool is_indexed = regs.index_buffer.count && !regs.vertex_buffer.count;      if (ShouldExecute()) { -        rasterizer->Draw(is_indexed, instance_count); +        rasterizer->Draw(draw_indexed, instance_count);      } -    if (is_indexed) { -        regs.index_buffer.count = 0; -    } else { -        regs.vertex_buffer.count = 0; -    } +    draw_indexed = false; +    deferred_draw_method.clear();  }  void Maxwell3D::ProcessDeferredDraw() { @@ -667,8 +673,6 @@ void Maxwell3D::ProcessDeferredDraw() {      ASSERT_MSG(!(vertex_buffer_count && index_buffer_count), "Instance both indexed and direct?");      ProcessDraw(instance_count); - -    deferred_draw_method.clear();  }  } // namespace Tegra::Engines diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index deba292a5..a541cd95f 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -3159,6 +3159,7 @@ private:      std::vector<u32> deferred_draw_method;      enum class DrawMode : u32 { General = 0, Instance, InlineIndex };      DrawMode draw_mode{DrawMode::General}; +    bool draw_indexed{};  };  #define ASSERT_REG_POSITION(field_name, position)                                                  \ diff --git a/src/video_core/engines/sw_blitter/converter.cpp b/src/video_core/engines/sw_blitter/converter.cpp index cd46dfd4f..2419b5632 100644 --- a/src/video_core/engines/sw_blitter/converter.cpp +++ b/src/video_core/engines/sw_blitter/converter.cpp @@ -2,12 +2,12 @@  // SPDX-License-Identifier: GPL-3.0-or-later  #include <array> -#include <bit>  #include <cmath>  #include <span>  #include <unordered_map>  #include "common/assert.h" +#include "common/bit_cast.h"  #include "video_core/engines/sw_blitter/converter.h"  #include "video_core/surface.h"  #include "video_core/textures/decoders.h" @@ -693,21 +693,21 @@ private:              return shifted_value >> shift_amount;          };          const auto force_to_fp16 = [](f32 base_value) { -            u32 tmp = std::bit_cast<u32>(base_value); +            u32 tmp = Common::BitCast<u32>(base_value);              constexpr size_t fp32_mantissa_bits = 23;              constexpr size_t fp16_mantissa_bits = 10;              constexpr size_t mantissa_mask =                  ~((1ULL << (fp32_mantissa_bits - fp16_mantissa_bits)) - 1ULL);              tmp = tmp & static_cast<u32>(mantissa_mask);              // TODO: force the exponent within the range of half float. Not needed in UNORM / SNORM -            return std::bit_cast<f32>(tmp); +            return Common::BitCast<f32>(tmp);          };          const auto from_fp_n = [&sign_extend](u32 base_value, size_t bits, size_t mantissa) {              constexpr size_t fp32_mantissa_bits = 23;              size_t shift_towards = fp32_mantissa_bits - mantissa;              const u32 new_value =                  static_cast<u32>(sign_extend(base_value, bits) << shift_towards) & (~(1U << 31)); -            return std::bit_cast<f32>(new_value); +            return Common::BitCast<f32>(new_value);          };          const auto calculate_snorm = [&]() {              return static_cast<f32>( @@ -737,13 +737,13 @@ private:              out_component = force_to_fp16(out_component);          } else if constexpr (component_types[which_component] == ComponentType::FLOAT) {              if constexpr (component_sizes[which_component] == 32) { -                out_component = std::bit_cast<f32>(value); +                out_component = Common::BitCast<f32>(value);              } else if constexpr (component_sizes[which_component] == 16) {                  static constexpr u32 sign_mask = 0x8000;                  static constexpr u32 mantissa_mask = 0x8000; -                out_component = std::bit_cast<f32>(((value & sign_mask) << 16) | -                                                   (((value & 0x7c00) + 0x1C000) << 13) | -                                                   ((value & mantissa_mask) << 13)); +                out_component = Common::BitCast<f32>(((value & sign_mask) << 16) | +                                                     (((value & 0x7c00) + 0x1C000) << 13) | +                                                     ((value & mantissa_mask) << 13));              } else {                  out_component = from_fp_n(value, component_sizes[which_component],                                            component_sizes[which_component] - 5); @@ -771,7 +771,7 @@ private:          };          const auto to_fp_n = [](f32 base_value, size_t bits, size_t mantissa) {              constexpr size_t fp32_mantissa_bits = 23; -            u32 tmp_value = std::bit_cast<u32>(std::max(base_value, 0.0f)); +            u32 tmp_value = Common::BitCast<u32>(std::max(base_value, 0.0f));              size_t shift_towards = fp32_mantissa_bits - mantissa;              return tmp_value >> shift_towards;          }; @@ -799,13 +799,13 @@ private:              insert_to_word(tmp_word);          } else if constexpr (component_types[which_component] == ComponentType::FLOAT) {              if constexpr (component_sizes[which_component] == 32) { -                u32 tmp_word = std::bit_cast<u32>(in_component); +                u32 tmp_word = Common::BitCast<u32>(in_component);                  insert_to_word(tmp_word);              } else if constexpr (component_sizes[which_component] == 16) {                  static constexpr u32 sign_mask = 0x8000;                  static constexpr u32 mantissa_mask = 0x03ff;                  static constexpr u32 exponent_mask = 0x7c00; -                const u32 tmp_word = std::bit_cast<u32>(in_component); +                const u32 tmp_word = Common::BitCast<u32>(in_component);                  const u32 half = ((tmp_word >> 16) & sign_mask) |                                   ((((tmp_word & 0x7f800000) - 0x38000000) >> 13) & exponent_mask) |                                   ((tmp_word >> 13) & mantissa_mask); diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index 1bd477011..164a5252a 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp @@ -125,7 +125,7 @@ u64 ThreadManager::PushCommand(CommandData&& command_data, bool block) {      state.queue.Push(CommandDataContainer(std::move(command_data), fence, block));      if (block) { -        state.cv.wait(lk, thread.get_stop_token(), [this, fence] { +        Common::CondvarWait(state.cv, lk, thread.get_stop_token(), [this, fence] {              return fence <= state.signaled_fence.load(std::memory_order_relaxed);          });      } diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h index 64628d3e3..c71a419c7 100644 --- a/src/video_core/gpu_thread.h +++ b/src/video_core/gpu_thread.h @@ -10,6 +10,7 @@  #include <thread>  #include <variant> +#include "common/polyfill_thread.h"  #include "common/threadsafe_queue.h"  #include "video_core/framebuffer_config.h" diff --git a/src/video_core/precompiled_headers.h b/src/video_core/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/video_core/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index cfd872a40..b6907463c 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -6,8 +6,8 @@  #include <functional>  #include <optional>  #include <span> -#include <stop_token>  #include "common/common_types.h" +#include "common/polyfill_thread.h"  #include "video_core/engines/fermi_2d.h"  #include "video_core/gpu.h" diff --git a/src/video_core/renderer_null/null_rasterizer.cpp b/src/video_core/renderer_null/null_rasterizer.cpp new file mode 100644 index 000000000..9734d84bc --- /dev/null +++ b/src/video_core/renderer_null/null_rasterizer.cpp @@ -0,0 +1,90 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "video_core/host1x/host1x.h" +#include "video_core/memory_manager.h" +#include "video_core/renderer_null/null_rasterizer.h" + +namespace Null { + +AccelerateDMA::AccelerateDMA() = default; + +bool AccelerateDMA::BufferCopy(GPUVAddr start_address, GPUVAddr end_address, u64 amount) { +    return true; +} +bool AccelerateDMA::BufferClear(GPUVAddr src_address, u64 amount, u32 value) { +    return true; +} + +RasterizerNull::RasterizerNull(Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu) +    : RasterizerAccelerated(cpu_memory_), m_gpu{gpu} {} +RasterizerNull::~RasterizerNull() = default; + +void RasterizerNull::Draw(bool is_indexed, u32 instance_count) {} +void RasterizerNull::Clear(u32 layer_count) {} +void RasterizerNull::DispatchCompute() {} +void RasterizerNull::ResetCounter(VideoCore::QueryType type) {} +void RasterizerNull::Query(GPUVAddr gpu_addr, VideoCore::QueryType type, +                           std::optional<u64> timestamp) { +    if (!gpu_memory) { +        return; +    } + +    gpu_memory->Write(gpu_addr, u64{0}); +    if (timestamp) { +        gpu_memory->Write(gpu_addr + 8, *timestamp); +    } +} +void RasterizerNull::BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, +                                               u32 size) {} +void RasterizerNull::DisableGraphicsUniformBuffer(size_t stage, u32 index) {} +void RasterizerNull::FlushAll() {} +void RasterizerNull::FlushRegion(VAddr addr, u64 size) {} +bool RasterizerNull::MustFlushRegion(VAddr addr, u64 size) { +    return false; +} +void RasterizerNull::InvalidateRegion(VAddr addr, u64 size) {} +void RasterizerNull::OnCPUWrite(VAddr addr, u64 size) {} +void RasterizerNull::InvalidateGPUCache() {} +void RasterizerNull::UnmapMemory(VAddr addr, u64 size) {} +void RasterizerNull::ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) {} +void RasterizerNull::SignalFence(std::function<void()>&& func) { +    func(); +} +void RasterizerNull::SyncOperation(std::function<void()>&& func) { +    func(); +} +void RasterizerNull::SignalSyncPoint(u32 value) { +    auto& syncpoint_manager = m_gpu.Host1x().GetSyncpointManager(); +    syncpoint_manager.IncrementGuest(value); +    syncpoint_manager.IncrementHost(value); +} +void RasterizerNull::SignalReference() {} +void RasterizerNull::ReleaseFences() {} +void RasterizerNull::FlushAndInvalidateRegion(VAddr addr, u64 size) {} +void RasterizerNull::WaitForIdle() {} +void RasterizerNull::FragmentBarrier() {} +void RasterizerNull::TiledCacheBarrier() {} +void RasterizerNull::FlushCommands() {} +void RasterizerNull::TickFrame() {} +Tegra::Engines::AccelerateDMAInterface& RasterizerNull::AccessAccelerateDMA() { +    return m_accelerate_dma; +} +bool RasterizerNull::AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src, +                                           const Tegra::Engines::Fermi2D::Surface& dst, +                                           const Tegra::Engines::Fermi2D::Config& copy_config) { +    return true; +} +void RasterizerNull::AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, +                                              std::span<const u8> memory) {} +bool RasterizerNull::AccelerateDisplay(const Tegra::FramebufferConfig& config, +                                       VAddr framebuffer_addr, u32 pixel_stride) { +    return true; +} +void RasterizerNull::LoadDiskResources(u64 title_id, std::stop_token stop_loading, +                                       const VideoCore::DiskResourceLoadCallback& callback) {} +void RasterizerNull::InitializeChannel(Tegra::Control::ChannelState& channel) {} +void RasterizerNull::BindChannel(Tegra::Control::ChannelState& channel) {} +void RasterizerNull::ReleaseChannel(s32 channel_id) {} + +} // namespace Null diff --git a/src/video_core/renderer_null/null_rasterizer.h b/src/video_core/renderer_null/null_rasterizer.h new file mode 100644 index 000000000..ecf77ba42 --- /dev/null +++ b/src/video_core/renderer_null/null_rasterizer.h @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "video_core/control/channel_state_cache.h" +#include "video_core/engines/maxwell_dma.h" +#include "video_core/rasterizer_accelerated.h" +#include "video_core/rasterizer_interface.h" + +namespace Core { +class System; +} + +namespace Null { + +class RasterizerNull; + +class AccelerateDMA : public Tegra::Engines::AccelerateDMAInterface { +public: +    explicit AccelerateDMA(); +    bool BufferCopy(GPUVAddr start_address, GPUVAddr end_address, u64 amount) override; +    bool BufferClear(GPUVAddr src_address, u64 amount, u32 value) override; +}; + +class RasterizerNull final : public VideoCore::RasterizerAccelerated, +                             protected VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> { +public: +    explicit RasterizerNull(Core::Memory::Memory& cpu_memory, Tegra::GPU& gpu); +    ~RasterizerNull() override; + +    void Draw(bool is_indexed, u32 instance_count) override; +    void Clear(u32 layer_count) override; +    void DispatchCompute() override; +    void ResetCounter(VideoCore::QueryType type) override; +    void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional<u64> timestamp) override; +    void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size) override; +    void DisableGraphicsUniformBuffer(size_t stage, u32 index) override; +    void FlushAll() override; +    void FlushRegion(VAddr addr, u64 size) override; +    bool MustFlushRegion(VAddr addr, u64 size) override; +    void InvalidateRegion(VAddr addr, u64 size) override; +    void OnCPUWrite(VAddr addr, u64 size) override; +    void InvalidateGPUCache() override; +    void UnmapMemory(VAddr addr, u64 size) override; +    void ModifyGPUMemory(size_t as_id, GPUVAddr addr, u64 size) override; +    void SignalFence(std::function<void()>&& func) override; +    void SyncOperation(std::function<void()>&& func) override; +    void SignalSyncPoint(u32 value) override; +    void SignalReference() override; +    void ReleaseFences() override; +    void FlushAndInvalidateRegion(VAddr addr, u64 size) override; +    void WaitForIdle() override; +    void FragmentBarrier() override; +    void TiledCacheBarrier() override; +    void FlushCommands() override; +    void TickFrame() override; +    bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src, +                               const Tegra::Engines::Fermi2D::Surface& dst, +                               const Tegra::Engines::Fermi2D::Config& copy_config) override; +    Tegra::Engines::AccelerateDMAInterface& AccessAccelerateDMA() override; +    void AccelerateInlineToMemory(GPUVAddr address, size_t copy_size, +                                  std::span<const u8> memory) override; +    bool AccelerateDisplay(const Tegra::FramebufferConfig& config, VAddr framebuffer_addr, +                           u32 pixel_stride) override; +    void LoadDiskResources(u64 title_id, std::stop_token stop_loading, +                           const VideoCore::DiskResourceLoadCallback& callback) override; +    void InitializeChannel(Tegra::Control::ChannelState& channel) override; +    void BindChannel(Tegra::Control::ChannelState& channel) override; +    void ReleaseChannel(s32 channel_id) override; + +private: +    Tegra::GPU& m_gpu; +    AccelerateDMA m_accelerate_dma; +}; + +} // namespace Null diff --git a/src/video_core/renderer_null/renderer_null.cpp b/src/video_core/renderer_null/renderer_null.cpp new file mode 100644 index 000000000..e2a189b63 --- /dev/null +++ b/src/video_core/renderer_null/renderer_null.cpp @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "video_core/renderer_null/renderer_null.h" + +namespace Null { + +RendererNull::RendererNull(Core::Frontend::EmuWindow& emu_window, Core::Memory::Memory& cpu_memory, +                           Tegra::GPU& gpu, +                           std::unique_ptr<Core::Frontend::GraphicsContext> context_) +    : RendererBase(emu_window, std::move(context_)), m_gpu(gpu), m_rasterizer(cpu_memory, gpu) {} + +RendererNull::~RendererNull() = default; + +void RendererNull::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { +    if (!framebuffer) { +        return; +    } + +    m_gpu.RendererFrameEndNotify(); +    render_window.OnFrameDisplayed(); +} + +} // namespace Null diff --git a/src/video_core/renderer_null/renderer_null.h b/src/video_core/renderer_null/renderer_null.h new file mode 100644 index 000000000..967ff5645 --- /dev/null +++ b/src/video_core/renderer_null/renderer_null.h @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <memory> +#include <string> + +#include "video_core/renderer_base.h" +#include "video_core/renderer_null/null_rasterizer.h" + +namespace Null { + +class RendererNull final : public VideoCore::RendererBase { +public: +    explicit RendererNull(Core::Frontend::EmuWindow& emu_window, Core::Memory::Memory& cpu_memory, +                          Tegra::GPU& gpu, +                          std::unique_ptr<Core::Frontend::GraphicsContext> context); +    ~RendererNull() override; + +    void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; + +    VideoCore::RasterizerInterface* ReadRasterizer() override { +        return &m_rasterizer; +    } + +    [[nodiscard]] std::string GetDeviceVendor() const override { +        return "NULL"; +    } + +private: +    Tegra::GPU& m_gpu; +    RasterizerNull m_rasterizer; +}; + +} // namespace Null diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index 1663e277d..e2e3dac34 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp @@ -14,6 +14,7 @@  #include "common/literals.h"  #include "common/logging/log.h" +#include "common/polyfill_ranges.h"  #include "common/settings.h"  #include "shader_recompiler/stage.h"  #include "video_core/renderer_opengl/gl_device.h" diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 3fe04a115..a38060100 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -39,6 +39,7 @@ using Shader::Backend::GLASM::EmitGLASM;  using Shader::Backend::GLSL::EmitGLSL;  using Shader::Backend::SPIRV::EmitSPIRV;  using Shader::Maxwell::ConvertLegacyToGeneric; +using Shader::Maxwell::GenerateGeometryPassthrough;  using Shader::Maxwell::MergeDualVertexPrograms;  using Shader::Maxwell::TranslateProgram;  using VideoCommon::ComputeEnvironment; @@ -56,6 +57,17 @@ auto MakeSpan(Container& container) {      return std::span(container.data(), container.size());  } +Shader::OutputTopology MaxwellToOutputTopology(Maxwell::PrimitiveTopology topology) { +    switch (topology) { +    case Maxwell::PrimitiveTopology::Points: +        return Shader::OutputTopology::PointList; +    case Maxwell::PrimitiveTopology::LineStrip: +        return Shader::OutputTopology::LineStrip; +    default: +        return Shader::OutputTopology::TriangleStrip; +    } +} +  Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key,                                      const Shader::IR::Program& program,                                      const Shader::IR::Program* previous_program, @@ -220,6 +232,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo            .support_int64 = device.HasShaderInt64(),            .needs_demote_reorder = device.IsAmd(),            .support_snorm_render_buffer = false, +          .support_viewport_index_layer = device.HasVertexViewportLayer(),        } {      if (use_asynchronous_shaders) {          workers = CreateWorkers(); @@ -314,9 +327,7 @@ GraphicsPipeline* ShaderCache::CurrentGraphicsPipeline() {      const auto& regs{maxwell3d->regs};      graphics_key.raw = 0;      graphics_key.early_z.Assign(regs.mandated_early_z != 0 ? 1 : 0); -    graphics_key.gs_input_topology.Assign(graphics_key.unique_hashes[4] != 0 -                                              ? regs.draw.topology.Value() -                                              : Maxwell::PrimitiveTopology{}); +    graphics_key.gs_input_topology.Assign(regs.draw.topology.Value());      graphics_key.tessellation_primitive.Assign(regs.tessellation.params.domain_type.Value());      graphics_key.tessellation_spacing.Assign(regs.tessellation.params.spacing.Value());      graphics_key.tessellation_clockwise.Assign( @@ -415,7 +426,19 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(      std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs;      const bool uses_vertex_a{key.unique_hashes[0] != 0};      const bool uses_vertex_b{key.unique_hashes[1] != 0}; + +    // Layer passthrough generation for devices without GL_ARB_shader_viewport_layer_array +    Shader::IR::Program* layer_source_program{}; +      for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { +        const bool is_emulated_stage = layer_source_program != nullptr && +                                       index == static_cast<u32>(Maxwell::ShaderType::Geometry); +        if (key.unique_hashes[index] == 0 && is_emulated_stage) { +            auto topology = MaxwellToOutputTopology(key.gs_input_topology); +            programs[index] = GenerateGeometryPassthrough(pools.inst, pools.block, host_info, +                                                          *layer_source_program, topology); +            continue; +        }          if (key.unique_hashes[index] == 0) {              continue;          } @@ -443,6 +466,10 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(                  Shader::NumDescriptors(program_vb.info.storage_buffers_descriptors);              programs[index] = MergeDualVertexPrograms(program_va, program_vb, env);          } + +        if (programs[index].info.requires_layer_emulation) { +            layer_source_program = &programs[index]; +        }      }      const u32 glasm_storage_buffer_limit{device.GetMaxGLASMStorageBufferBlocks()};      const bool glasm_use_storage_buffers{total_storage_buffers <= glasm_storage_buffer_limit}; @@ -456,7 +483,9 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(      const bool use_glasm{device.UseAssemblyShaders()};      const size_t first_index = uses_vertex_a && uses_vertex_b ? 1 : 0;      for (size_t index = first_index; index < Maxwell::MaxShaderProgram; ++index) { -        if (key.unique_hashes[index] == 0) { +        const bool is_emulated_stage = layer_source_program != nullptr && +                                       index == static_cast<u32>(Maxwell::ShaderType::Geometry); +        if (key.unique_hashes[index] == 0 && !is_emulated_stage) {              continue;          }          UNIMPLEMENTED_IF(index == 0); diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index 89f181fe3..53ffea904 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h @@ -4,7 +4,6 @@  #pragma once  #include <filesystem> -#include <stop_token>  #include <unordered_map>  #include "common/common_types.h" diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index 98cc26679..5864e772b 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp @@ -7,6 +7,7 @@  #include "common/bit_cast.h"  #include "common/cityhash.h"  #include "common/common_types.h" +#include "common/polyfill_ranges.h"  #include "video_core/renderer_vulkan/fixed_pipeline_state.h"  #include "video_core/renderer_vulkan/vk_state_tracker.h" @@ -92,6 +93,8 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d,      provoking_vertex_last.Assign(regs.provoking_vertex == Maxwell::ProvokingVertex::Last ? 1 : 0);      conservative_raster_enable.Assign(regs.conservative_raster_enable != 0 ? 1 : 0);      smooth_lines.Assign(regs.line_anti_alias_enable != 0 ? 1 : 0); +    alpha_to_coverage_enabled.Assign(regs.anti_alias_alpha_control.alpha_to_coverage != 0 ? 1 : 0); +    alpha_to_one_enabled.Assign(regs.anti_alias_alpha_control.alpha_to_one != 0 ? 1 : 0);      for (size_t i = 0; i < regs.rt.size(); ++i) {          color_formats[i] = static_cast<u8>(regs.rt[i].format); diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h index 1afdef329..ab79fb8f3 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h @@ -195,6 +195,8 @@ struct FixedPipelineState {          BitField<12, 1, u32> provoking_vertex_last;          BitField<13, 1, u32> conservative_raster_enable;          BitField<14, 1, u32> smooth_lines; +        BitField<15, 1, u32> alpha_to_coverage_enabled; +        BitField<16, 1, u32> alpha_to_one_enabled;      };      std::array<u8, Maxwell::NumRenderTargets> color_formats; diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index 430a84272..3e03c5cd6 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp @@ -58,7 +58,7 @@ VkSamplerAddressMode WrapMode(const Device& device, Tegra::Texture::WrapMode wra      case Tegra::Texture::WrapMode::Border:          return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;      case Tegra::Texture::WrapMode::Clamp: -        if (device.GetDriverID() == VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR) { +        if (device.GetDriverID() == VK_DRIVER_ID_NVIDIA_PROPRIETARY) {              // Nvidia's Vulkan driver defaults to GL_CLAMP on invalid enumerations, we can hack this              // by sending an invalid enumeration.              return static_cast<VkSamplerAddressMode>(0xcafe); diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h index b7843e995..28b893e25 100644 --- a/src/video_core/renderer_vulkan/pipeline_helper.h +++ b/src/video_core/renderer_vulkan/pipeline_helper.h @@ -44,17 +44,17 @@ public:          });      } -    vk::DescriptorUpdateTemplateKHR CreateTemplate(VkDescriptorSetLayout descriptor_set_layout, -                                                   VkPipelineLayout pipeline_layout, -                                                   bool use_push_descriptor) const { +    vk::DescriptorUpdateTemplate CreateTemplate(VkDescriptorSetLayout descriptor_set_layout, +                                                VkPipelineLayout pipeline_layout, +                                                bool use_push_descriptor) const {          if (entries.empty()) {              return nullptr;          }          const VkDescriptorUpdateTemplateType type =              use_push_descriptor ? VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR -                                : VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR; -        return device->GetLogical().CreateDescriptorUpdateTemplateKHR({ -            .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR, +                                : VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET; +        return device->GetLogical().CreateDescriptorUpdateTemplate({ +            .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO,              .pNext = nullptr,              .flags = 0,              .descriptorUpdateEntryCount = static_cast<u32>(entries.size()), @@ -129,7 +129,7 @@ private:      const Device* device{};      bool is_compute{};      boost::container::small_vector<VkDescriptorSetLayoutBinding, 32> bindings; -    boost::container::small_vector<VkDescriptorUpdateTemplateEntryKHR, 32> entries; +    boost::container::small_vector<VkDescriptorUpdateTemplateEntry, 32> entries;      u32 binding{};      u32 num_descriptors{};      size_t offset{}; diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index c2a95200b..18be54729 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -45,14 +45,14 @@ std::string GetDriverVersion(const Device& device) {      // https://github.com/SaschaWillems/vulkan.gpuinfo.org/blob/5dddea46ea1120b0df14eef8f15ff8e318e35462/functions.php#L308-L314      const u32 version = device.GetDriverVersion(); -    if (device.GetDriverID() == VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR) { +    if (device.GetDriverID() == VK_DRIVER_ID_NVIDIA_PROPRIETARY) {          const u32 major = (version >> 22) & 0x3ff;          const u32 minor = (version >> 14) & 0x0ff;          const u32 secondary = (version >> 6) & 0x0ff;          const u32 tertiary = version & 0x003f;          return fmt::format("{}.{}.{}.{}", major, minor, secondary, tertiary);      } -    if (device.GetDriverID() == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR) { +    if (device.GetDriverID() == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) {          const u32 major = version >> 14;          const u32 minor = version & 0x3fff;          return fmt::format("{}.{}", major, minor); diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 89426121f..6e5abade4 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -10,6 +10,7 @@  #include "common/assert.h"  #include "common/common_types.h"  #include "common/math_util.h" +#include "common/polyfill_ranges.h"  #include "common/settings.h"  #include "core/core.h"  #include "core/frontend/emu_window.h" diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index 241d7573e..2c00979d7 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp @@ -93,7 +93,7 @@ constexpr DescriptorBankInfo ASTC_BANK_INFO{      .score = 2,  }; -constexpr VkDescriptorUpdateTemplateEntryKHR INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE{ +constexpr VkDescriptorUpdateTemplateEntry INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE{      .dstBinding = 0,      .dstArrayElement = 0,      .descriptorCount = 2, @@ -102,7 +102,7 @@ constexpr VkDescriptorUpdateTemplateEntryKHR INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMP      .stride = sizeof(DescriptorUpdateEntry),  }; -constexpr std::array<VkDescriptorUpdateTemplateEntryKHR, ASTC_NUM_BINDINGS> +constexpr std::array<VkDescriptorUpdateTemplateEntry, ASTC_NUM_BINDINGS>      ASTC_PASS_DESCRIPTOR_UPDATE_TEMPLATE_ENTRY{{          {              .dstBinding = ASTC_BINDING_INPUT_BUFFER, @@ -134,7 +134,7 @@ struct AstcPushConstants {  ComputePass::ComputePass(const Device& device_, DescriptorPool& descriptor_pool,                           vk::Span<VkDescriptorSetLayoutBinding> bindings, -                         vk::Span<VkDescriptorUpdateTemplateEntryKHR> templates, +                         vk::Span<VkDescriptorUpdateTemplateEntry> templates,                           const DescriptorBankInfo& bank_info,                           vk::Span<VkPushConstantRange> push_constants, std::span<const u32> code)      : device{device_} { @@ -155,13 +155,13 @@ ComputePass::ComputePass(const Device& device_, DescriptorPool& descriptor_pool,          .pPushConstantRanges = push_constants.data(),      });      if (!templates.empty()) { -        descriptor_template = device.GetLogical().CreateDescriptorUpdateTemplateKHR({ -            .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR, +        descriptor_template = device.GetLogical().CreateDescriptorUpdateTemplate({ +            .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO,              .pNext = nullptr,              .flags = 0,              .descriptorUpdateEntryCount = templates.size(),              .pDescriptorUpdateEntries = templates.data(), -            .templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR, +            .templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,              .descriptorSetLayout = *descriptor_set_layout,              .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,              .pipelineLayout = *layout, diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h index dcc691a8e..5d32e3caf 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.h +++ b/src/video_core/renderer_vulkan/vk_compute_pass.h @@ -29,14 +29,14 @@ class ComputePass {  public:      explicit ComputePass(const Device& device, DescriptorPool& descriptor_pool,                           vk::Span<VkDescriptorSetLayoutBinding> bindings, -                         vk::Span<VkDescriptorUpdateTemplateEntryKHR> templates, +                         vk::Span<VkDescriptorUpdateTemplateEntry> templates,                           const DescriptorBankInfo& bank_info,                           vk::Span<VkPushConstantRange> push_constants, std::span<const u32> code);      ~ComputePass();  protected:      const Device& device; -    vk::DescriptorUpdateTemplateKHR descriptor_template; +    vk::DescriptorUpdateTemplate descriptor_template;      vk::PipelineLayout layout;      vk::Pipeline pipeline;      vk::DescriptorSetLayout descriptor_set_layout; diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 7906e11a8..04a3a861e 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -53,7 +53,7 @@ ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descript              .requiredSubgroupSize = GuestWarpSize,          };          VkPipelineCreateFlags flags{}; -        if (device.IsKhrPipelineEexecutablePropertiesEnabled()) { +        if (device.IsKhrPipelineExecutablePropertiesEnabled()) {              flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;          }          pipeline = device.GetLogical().CreateComputePipeline({ diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h index 9879735fe..d70837fc5 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h @@ -55,7 +55,7 @@ private:      vk::DescriptorSetLayout descriptor_set_layout;      DescriptorAllocator descriptor_allocator;      vk::PipelineLayout pipeline_layout; -    vk::DescriptorUpdateTemplateKHR descriptor_update_template; +    vk::DescriptorUpdateTemplate descriptor_update_template;      vk::Pipeline pipeline;      std::condition_variable build_condvar; diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp index c7196b64e..b5ae6443c 100644 --- a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp @@ -7,6 +7,7 @@  #include <vector>  #include "common/common_types.h" +#include "common/polyfill_ranges.h"  #include "video_core/renderer_vulkan/vk_descriptor_pool.h"  #include "video_core/renderer_vulkan/vk_resource_pool.h"  #include "video_core/renderer_vulkan/vk_scheduler.h" diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index ef75c126c..006128638 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -714,8 +714,8 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {          .sampleShadingEnable = VK_FALSE,          .minSampleShading = 0.0f,          .pSampleMask = nullptr, -        .alphaToCoverageEnable = VK_FALSE, -        .alphaToOneEnable = VK_FALSE, +        .alphaToCoverageEnable = key.state.alpha_to_coverage_enabled != 0 ? VK_TRUE : VK_FALSE, +        .alphaToOneEnable = key.state.alpha_to_one_enabled != 0 ? VK_TRUE : VK_FALSE,      };      const VkPipelineDepthStencilStateCreateInfo depth_stencil_ci{          .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, @@ -830,7 +830,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {          */      }      VkPipelineCreateFlags flags{}; -    if (device.IsKhrPipelineEexecutablePropertiesEnabled()) { +    if (device.IsKhrPipelineExecutablePropertiesEnabled()) {          flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;      }      pipeline = device.GetLogical().CreateGraphicsPipeline({ diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 6bf577d25..1ed2967be 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -151,7 +151,7 @@ private:      vk::DescriptorSetLayout descriptor_set_layout;      DescriptorAllocator descriptor_allocator;      vk::PipelineLayout pipeline_layout; -    vk::DescriptorUpdateTemplateKHR descriptor_update_template; +    vk::DescriptorUpdateTemplate descriptor_update_template;      vk::Pipeline pipeline;      std::condition_variable build_condvar; diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp index 4e81d3d28..8aa07ef9d 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp @@ -11,10 +11,10 @@  namespace Vulkan {  MasterSemaphore::MasterSemaphore(const Device& device) { -    static constexpr VkSemaphoreTypeCreateInfoKHR semaphore_type_ci{ -        .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR, +    static constexpr VkSemaphoreTypeCreateInfo semaphore_type_ci{ +        .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,          .pNext = nullptr, -        .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE_KHR, +        .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,          .initialValue = 0,      };      static constexpr VkSemaphoreCreateInfo semaphore_ci{ @@ -28,7 +28,7 @@ MasterSemaphore::MasterSemaphore(const Device& device) {          return;      }      // Validation layers have a bug where they fail to track resource usage when using timeline -    // semaphores and synchronizing with GetSemaphoreCounterValueKHR. To workaround this issue, have +    // semaphores and synchronizing with GetSemaphoreCounterValue. To workaround this issue, have      // a separate thread waiting for each timeline semaphore value.      debug_thread = std::jthread([this](std::stop_token stop_token) {          u64 counter = 0; diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h index 362ed579a..689f02ea5 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.h +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h @@ -7,6 +7,7 @@  #include <thread>  #include "common/common_types.h" +#include "common/polyfill_thread.h"  #include "video_core/vulkan_common/vulkan_wrapper.h"  namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index d4b0a542a..38a6b7488 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -46,6 +46,7 @@ MICROPROFILE_DECLARE(Vulkan_PipelineCache);  namespace {  using Shader::Backend::SPIRV::EmitSPIRV;  using Shader::Maxwell::ConvertLegacyToGeneric; +using Shader::Maxwell::GenerateGeometryPassthrough;  using Shader::Maxwell::MergeDualVertexPrograms;  using Shader::Maxwell::TranslateProgram;  using VideoCommon::ComputeEnvironment; @@ -53,13 +54,24 @@ using VideoCommon::FileEnvironment;  using VideoCommon::GenericEnvironment;  using VideoCommon::GraphicsEnvironment; -constexpr u32 CACHE_VERSION = 7; +constexpr u32 CACHE_VERSION = 8;  template <typename Container>  auto MakeSpan(Container& container) {      return std::span(container.data(), container.size());  } +Shader::OutputTopology MaxwellToOutputTopology(Maxwell::PrimitiveTopology topology) { +    switch (topology) { +    case Maxwell::PrimitiveTopology::Points: +        return Shader::OutputTopology::PointList; +    case Maxwell::PrimitiveTopology::LineStrip: +        return Shader::OutputTopology::LineStrip; +    default: +        return Shader::OutputTopology::TriangleStrip; +    } +} +  Shader::CompareFunction MaxwellToCompareFunction(Maxwell::ComparisonOp comparison) {      switch (comparison) {      case Maxwell::ComparisonOp::Never_D3D: @@ -275,9 +287,9 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device        workers(std::max(std::thread::hardware_concurrency(), 2U) - 1, "VkPipelineBuilder"),        serialization_thread(1, "VkPipelineSerialization") {      const auto& float_control{device.FloatControlProperties()}; -    const VkDriverIdKHR driver_id{device.GetDriverID()}; +    const VkDriverId driver_id{device.GetDriverID()};      profile = Shader::Profile{ -        .supported_spirv = device.IsKhrSpirv1_4Supported() ? 0x00010400U : 0x00010000U, +        .supported_spirv = device.SupportedSpirvVersion(),          .unified_descriptor_binding = true,          .support_descriptor_aliasing = true,          .support_int8 = device.IsInt8Supported(), @@ -285,10 +297,10 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device          .support_int64 = device.IsShaderInt64Supported(),          .support_vertex_instance_id = false,          .support_float_controls = true, -        .support_separate_denorm_behavior = float_control.denormBehaviorIndependence == -                                            VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR, +        .support_separate_denorm_behavior = +            float_control.denormBehaviorIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL,          .support_separate_rounding_mode = -            float_control.roundingModeIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR, +            float_control.roundingModeIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL,          .support_fp16_denorm_preserve = float_control.shaderDenormPreserveFloat16 != VK_FALSE,          .support_fp32_denorm_preserve = float_control.shaderDenormPreserveFloat32 != VK_FALSE,          .support_fp16_denorm_flush = float_control.shaderDenormFlushToZeroFloat16 != VK_FALSE, @@ -315,18 +327,19 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device          .lower_left_origin_mode = false,          .need_declared_frag_colors = false, -        .has_broken_spirv_clamp = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR, +        .has_broken_spirv_clamp = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS,          .has_broken_unsigned_image_offsets = false,          .has_broken_signed_operations = false, -        .has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR, +        .has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY,          .ignore_nan_fp_comparisons = false,      };      host_info = Shader::HostTranslateInfo{          .support_float16 = device.IsFloat16Supported(),          .support_int64 = device.IsShaderInt64Supported(), -        .needs_demote_reorder = driver_id == VK_DRIVER_ID_AMD_PROPRIETARY_KHR || -                                driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR, +        .needs_demote_reorder = +            driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE,          .support_snorm_render_buffer = true, +        .support_viewport_index_layer = device.IsExtShaderViewportIndexLayerSupported(),      };  } @@ -395,7 +408,7 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading          std::unique_ptr<PipelineStatistics> statistics;      } state; -    if (device.IsKhrPipelineEexecutablePropertiesEnabled()) { +    if (device.IsKhrPipelineExecutablePropertiesEnabled()) {          state.statistics = std::make_unique<PipelineStatistics>(device);      }      const auto load_compute{[&](std::ifstream& file, FileEnvironment env) { @@ -509,7 +522,19 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(      std::array<Shader::IR::Program, Maxwell::MaxShaderProgram> programs;      const bool uses_vertex_a{key.unique_hashes[0] != 0};      const bool uses_vertex_b{key.unique_hashes[1] != 0}; + +    // Layer passthrough generation for devices without VK_EXT_shader_viewport_index_layer +    Shader::IR::Program* layer_source_program{}; +      for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { +        const bool is_emulated_stage = layer_source_program != nullptr && +                                       index == static_cast<u32>(Maxwell::ShaderType::Geometry); +        if (key.unique_hashes[index] == 0 && is_emulated_stage) { +            auto topology = MaxwellToOutputTopology(key.state.topology); +            programs[index] = GenerateGeometryPassthrough(pools.inst, pools.block, host_info, +                                                          *layer_source_program, topology); +            continue; +        }          if (key.unique_hashes[index] == 0) {              continue;          } @@ -530,6 +555,10 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(              auto program_vb{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)};              programs[index] = MergeDualVertexPrograms(program_va, program_vb, env);          } + +        if (programs[index].info.requires_layer_emulation) { +            layer_source_program = &programs[index]; +        }      }      std::array<const Shader::Info*, Maxwell::MaxShaderStage> infos{};      std::array<vk::ShaderModule, Maxwell::MaxShaderStage> modules; @@ -538,7 +567,9 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(      Shader::Backend::Bindings binding;      for (size_t index = uses_vertex_a && uses_vertex_b ? 1 : 0; index < Maxwell::MaxShaderProgram;           ++index) { -        if (key.unique_hashes[index] == 0) { +        const bool is_emulated_stage = layer_source_program != nullptr && +                                       index == static_cast<u32>(Maxwell::ShaderType::Geometry); +        if (key.unique_hashes[index] == 0 && !is_emulated_stage) {              continue;          }          UNIMPLEMENTED_IF(index == 0); diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index 4b15c0f85..929c8ece6 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp @@ -98,7 +98,7 @@ HostCounter::HostCounter(QueryCache& cache_, std::shared_ptr<HostCounter> depend        query{cache_.AllocateQuery(type_)}, tick{cache_.GetScheduler().CurrentTick()} {      const vk::Device* logical = &cache.GetDevice().GetLogical();      cache.GetScheduler().Record([logical, query = query](vk::CommandBuffer cmdbuf) { -        logical->ResetQueryPoolEXT(query.first, query.second, 1); +        logical->ResetQueryPool(query.first, query.second, 1);          cmdbuf.BeginQuery(query.first, query.second, VK_QUERY_CONTROL_PRECISE_BIT);      });  } diff --git a/src/video_core/renderer_vulkan/vk_render_pass_cache.h b/src/video_core/renderer_vulkan/vk_render_pass_cache.h index dc21b7e69..91ad4bf57 100644 --- a/src/video_core/renderer_vulkan/vk_render_pass_cache.h +++ b/src/video_core/renderer_vulkan/vk_render_pass_cache.h @@ -12,7 +12,7 @@  namespace Vulkan {  struct RenderPassKey { -    auto operator<=>(const RenderPassKey&) const noexcept = default; +    bool operator==(const RenderPassKey&) const noexcept = default;      std::array<VideoCore::Surface::PixelFormat, 8> color_formats;      VideoCore::Surface::PixelFormat depth_format; diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 4a7b633b7..c2e53a5d5 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -145,7 +145,7 @@ void Scheduler::WorkerThread(std::stop_token stop_token) {              if (work_queue.empty()) {                  wait_cv.notify_all();              } -            work_cv.wait(lock, stop_token, [this] { return !work_queue.empty(); }); +            Common::CondvarWait(work_cv, lock, stop_token, [&] { return !work_queue.empty(); });              if (stop_token.stop_requested()) {                  continue;              } @@ -194,8 +194,8 @@ void Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_s              VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,          }; -        const VkTimelineSemaphoreSubmitInfoKHR timeline_si{ -            .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR, +        const VkTimelineSemaphoreSubmitInfo timeline_si{ +            .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,              .pNext = nullptr,              .waitSemaphoreValueCount = num_wait_semaphores,              .pWaitSemaphoreValues = wait_values.data(), diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index 929216749..3858c506c 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -12,6 +12,7 @@  #include "common/alignment.h"  #include "common/common_types.h" +#include "common/polyfill_thread.h"  #include "video_core/renderer_vulkan/vk_master_semaphore.h"  #include "video_core/vulkan_common/vulkan_wrapper.h" diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 706d9ba74..d7be417f5 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -7,6 +7,7 @@  #include <vector>  #include "common/logging/log.h" +#include "common/polyfill_ranges.h"  #include "common/settings.h"  #include "core/core.h"  #include "video_core/renderer_vulkan/vk_scheduler.h" diff --git a/src/video_core/shader_cache.h b/src/video_core/shader_cache.h index a4391202d..f3cc4c70b 100644 --- a/src/video_core/shader_cache.h +++ b/src/video_core/shader_cache.h @@ -12,6 +12,7 @@  #include <vector>  #include "common/common_types.h" +#include "common/polyfill_ranges.h"  #include "video_core/control/channel_state_cache.h"  #include "video_core/rasterizer_interface.h"  #include "video_core/shader_environment.h" diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp index f24f320b6..958810747 100644 --- a/src/video_core/shader_environment.cpp +++ b/src/video_core/shader_environment.cpp @@ -15,6 +15,7 @@  #include "common/fs/fs.h"  #include "common/fs/path_util.h"  #include "common/logging/log.h" +#include "common/polyfill_ranges.h"  #include "shader_recompiler/environment.h"  #include "video_core/engines/kepler_compute.h"  #include "video_core/memory_manager.h" diff --git a/src/video_core/shader_environment.h b/src/video_core/shader_environment.h index bb55b029f..1342fab1e 100644 --- a/src/video_core/shader_environment.h +++ b/src/video_core/shader_environment.h @@ -10,12 +10,12 @@  #include <memory>  #include <optional>  #include <span> -#include <stop_token>  #include <type_traits>  #include <unordered_map>  #include <vector>  #include "common/common_types.h" +#include "common/polyfill_thread.h"  #include "common/unique_function.h"  #include "shader_recompiler/environment.h"  #include "video_core/engines/maxwell_3d.h" diff --git a/src/video_core/texture_cache/formatter.cpp b/src/video_core/texture_cache/formatter.cpp index ee4f2d406..418890126 100644 --- a/src/video_core/texture_cache/formatter.cpp +++ b/src/video_core/texture_cache/formatter.cpp @@ -4,6 +4,7 @@  #include <algorithm>  #include <string> +#include "common/polyfill_ranges.h"  #include "video_core/texture_cache/formatter.h"  #include "video_core/texture_cache/image_base.h"  #include "video_core/texture_cache/image_info.h" diff --git a/src/video_core/texture_cache/render_targets.h b/src/video_core/texture_cache/render_targets.h index 1efbd6507..0829d773a 100644 --- a/src/video_core/texture_cache/render_targets.h +++ b/src/video_core/texture_cache/render_targets.h @@ -13,7 +13,7 @@ namespace VideoCommon {  /// Framebuffer properties used to lookup a framebuffer  struct RenderTargets { -    constexpr auto operator<=>(const RenderTargets&) const noexcept = default; +    constexpr bool operator==(const RenderTargets&) const noexcept = default;      constexpr bool Contains(std::span<const ImageViewId> elements) const noexcept {          const auto contains = [elements](ImageViewId item) { diff --git a/src/video_core/texture_cache/slot_vector.h b/src/video_core/texture_cache/slot_vector.h index 46e8a86e6..1e2aad76a 100644 --- a/src/video_core/texture_cache/slot_vector.h +++ b/src/video_core/texture_cache/slot_vector.h @@ -12,6 +12,7 @@  #include "common/assert.h"  #include "common/common_types.h" +#include "common/polyfill_ranges.h"  namespace VideoCommon { diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index 9db7195bf..587339a31 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -16,6 +16,7 @@  #include "common/hash.h"  #include "common/literals.h"  #include "common/lru_cache.h" +#include "common/polyfill_ranges.h"  #include "video_core/compatible_formats.h"  #include "video_core/control/channel_state_cache.h"  #include "video_core/delayed_destruction_ring.h" @@ -60,8 +61,6 @@ public:      TextureCacheChannelInfo(Tegra::Control::ChannelState& state) noexcept;      TextureCacheChannelInfo(const TextureCacheChannelInfo& state) = delete;      TextureCacheChannelInfo& operator=(const TextureCacheChannelInfo&) = delete; -    TextureCacheChannelInfo(TextureCacheChannelInfo&& other) noexcept = default; -    TextureCacheChannelInfo& operator=(TextureCacheChannelInfo&& other) noexcept = default;      DescriptorTable<TICEntry> graphics_image_table{gpu_memory};      DescriptorTable<TSCEntry> graphics_sampler_table{gpu_memory}; diff --git a/src/video_core/textures/astc.cpp b/src/video_core/textures/astc.cpp index 69a32819a..e8d7c7863 100644 --- a/src/video_core/textures/astc.cpp +++ b/src/video_core/textures/astc.cpp @@ -15,6 +15,7 @@  #include "common/alignment.h"  #include "common/common_types.h" +#include "common/polyfill_ranges.h"  #include "common/thread_worker.h"  #include "video_core/textures/astc.h" diff --git a/src/video_core/transform_feedback.cpp b/src/video_core/transform_feedback.cpp index 45071185a..155599316 100644 --- a/src/video_core/transform_feedback.cpp +++ b/src/video_core/transform_feedback.cpp @@ -7,6 +7,7 @@  #include "common/alignment.h"  #include "common/assert.h" +#include "common/polyfill_ranges.h"  #include "shader_recompiler/shader_info.h"  #include "video_core/transform_feedback.h" diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index 04ac4af11..fedb4a7bb 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp @@ -7,6 +7,7 @@  #include "common/settings.h"  #include "core/core.h"  #include "video_core/renderer_base.h" +#include "video_core/renderer_null/renderer_null.h"  #include "video_core/renderer_opengl/renderer_opengl.h"  #include "video_core/renderer_vulkan/renderer_vulkan.h"  #include "video_core/video_core.h" @@ -26,6 +27,9 @@ std::unique_ptr<VideoCore::RendererBase> CreateRenderer(      case Settings::RendererBackend::Vulkan:          return std::make_unique<Vulkan::RendererVulkan>(telemetry_session, emu_window, cpu_memory,                                                          gpu, std::move(context)); +    case Settings::RendererBackend::Null: +        return std::make_unique<Null::RendererNull>(emu_window, cpu_memory, gpu, +                                                    std::move(context));      default:          return nullptr;      } diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index ddecfca13..467878431 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -12,6 +12,7 @@  #include "common/assert.h"  #include "common/literals.h" +#include "common/polyfill_ranges.h"  #include "common/settings.h"  #include "video_core/vulkan_common/nsight_aftermath_tracker.h"  #include "video_core/vulkan_common/vulkan_device.h" @@ -74,23 +75,8 @@ enum class NvidiaArchitecture {  };  constexpr std::array REQUIRED_EXTENSIONS{ -    VK_KHR_MAINTENANCE1_EXTENSION_NAME, -    VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME, -    VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, -    VK_KHR_16BIT_STORAGE_EXTENSION_NAME, -    VK_KHR_8BIT_STORAGE_EXTENSION_NAME, -    VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, -    VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME, -    VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME, -    VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME, -    VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME, -    VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME,      VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, -    VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME, -    VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME,      VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, -    VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME, -    VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME,  #ifdef _WIN32      VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,  #endif @@ -99,6 +85,19 @@ constexpr std::array REQUIRED_EXTENSIONS{  #endif  }; +constexpr std::array REQUIRED_EXTENSIONS_BEFORE_1_2{ +    VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME, +    VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME, +    VK_KHR_8BIT_STORAGE_EXTENSION_NAME, +    VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME, +    VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME, +    VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, +}; + +constexpr std::array REQUIRED_EXTENSIONS_BEFORE_1_3{ +    VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME, +}; +  template <typename T>  void SetNext(void**& next, T& data) {      *next = &data; @@ -308,10 +307,10 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,          VkPhysicalDeviceFragmentShadingRatePropertiesKHR shading_rate_props{};          shading_rate_props.sType =              VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR; -        VkPhysicalDeviceProperties2KHR physical_properties{}; -        physical_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; +        VkPhysicalDeviceProperties2 physical_properties{}; +        physical_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;          physical_properties.pNext = &shading_rate_props; -        physical.GetProperties2KHR(physical_properties); +        physical.GetProperties2(physical_properties);          if (shading_rate_props.primitiveFragmentShadingRateWithMultipleViewports) {              // Only Ampere and newer support this feature              return NvidiaArchitecture::AmpereOrNewer; @@ -327,7 +326,8 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,  Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface,                 const vk::InstanceDispatch& dld_)      : instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()}, -      supported_extensions{GetSupportedExtensions(physical)}, +      instance_version{properties.apiVersion}, supported_extensions{GetSupportedExtensions( +                                                   physical)},        format_properties(GetFormatProperties(physical)) {      CheckSuitability(surface != nullptr);      SetupFamilies(surface); @@ -401,15 +401,15 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR      const void* first_next = &features2;      void** next = &features2.pNext; -    VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline_semaphore{ -        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR, +    VkPhysicalDeviceTimelineSemaphoreFeatures timeline_semaphore{ +        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES,          .pNext = nullptr,          .timelineSemaphore = true,      };      SetNext(next, timeline_semaphore); -    VkPhysicalDevice16BitStorageFeaturesKHR bit16_storage{ -        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR, +    VkPhysicalDevice16BitStorageFeatures bit16_storage{ +        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES,          .pNext = nullptr,          .storageBuffer16BitAccess = true,          .uniformAndStorageBuffer16BitAccess = true, @@ -418,8 +418,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR      };      SetNext(next, bit16_storage); -    VkPhysicalDevice8BitStorageFeaturesKHR bit8_storage{ -        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR, +    VkPhysicalDevice8BitStorageFeatures bit8_storage{ +        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES,          .pNext = nullptr,          .storageBuffer8BitAccess = false,          .uniformAndStorageBuffer8BitAccess = true, @@ -436,32 +436,39 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR      };      SetNext(next, robustness2); -    VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset{ -        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT, +    VkPhysicalDeviceHostQueryResetFeatures host_query_reset{ +        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES,          .pNext = nullptr,          .hostQueryReset = true,      };      SetNext(next, host_query_reset); -    VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointers{ -        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR, +    VkPhysicalDeviceVariablePointerFeatures variable_pointers{ +        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES,          .pNext = nullptr,          .variablePointersStorageBuffer = VK_TRUE,          .variablePointers = VK_TRUE,      };      SetNext(next, variable_pointers); -    VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote{ -        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT, +    VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures demote{ +        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES,          .pNext = nullptr,          .shaderDemoteToHelperInvocation = true,      };      SetNext(next, demote); -    VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8; +    VkPhysicalDeviceShaderDrawParametersFeatures draw_parameters{ +        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES, +        .pNext = nullptr, +        .shaderDrawParameters = true, +    }; +    SetNext(next, draw_parameters); + +    VkPhysicalDeviceShaderFloat16Int8Features float16_int8;      if (is_int8_supported || is_float16_supported) {          float16_int8 = { -            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR, +            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES,              .pNext = nullptr,              .shaderFloat16 = is_float16_supported,              .shaderInt8 = is_int8_supported, @@ -487,10 +494,10 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR          LOG_INFO(Render_Vulkan, "Device doesn't support passthrough geometry shaders");      } -    VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR std430_layout; +    VkPhysicalDeviceUniformBufferStandardLayoutFeatures std430_layout;      if (khr_uniform_buffer_standard_layout) {          std430_layout = { -            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR, +            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES,              .pNext = nullptr,              .uniformBufferStandardLayout = true,          }; @@ -608,10 +615,10 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR          LOG_INFO(Render_Vulkan, "Device doesn't support vertex input dynamic state");      } -    VkPhysicalDeviceShaderAtomicInt64FeaturesKHR atomic_int64; +    VkPhysicalDeviceShaderAtomicInt64Features atomic_int64;      if (ext_shader_atomic_int64) {          atomic_int64 = { -            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR, +            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES,              .pNext = nullptr,              .shaderBufferInt64Atomics = VK_TRUE,              .shaderSharedInt64Atomics = VK_TRUE, @@ -896,28 +903,51 @@ std::string Device::GetDriverName() const {      }  } +static std::vector<const char*> ExtensionsRequiredForInstanceVersion(u32 available_version) { +    std::vector<const char*> extensions{REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()}; + +    if (available_version < VK_API_VERSION_1_2) { +        extensions.insert(extensions.end(), REQUIRED_EXTENSIONS_BEFORE_1_2.begin(), +                          REQUIRED_EXTENSIONS_BEFORE_1_2.end()); +    } + +    if (available_version < VK_API_VERSION_1_3) { +        extensions.insert(extensions.end(), REQUIRED_EXTENSIONS_BEFORE_1_3.begin(), +                          REQUIRED_EXTENSIONS_BEFORE_1_3.end()); +    } + +    return extensions; +} +  void Device::CheckSuitability(bool requires_swapchain) const { -    std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions; -    bool has_swapchain = false; -    for (const VkExtensionProperties& property : physical.EnumerateDeviceExtensionProperties()) { -        const std::string_view name{property.extensionName}; -        for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { -            if (available_extensions[i]) { -                continue; -            } -            available_extensions[i] = name == REQUIRED_EXTENSIONS[i]; -        } -        has_swapchain = has_swapchain || name == VK_KHR_SWAPCHAIN_EXTENSION_NAME; +    std::vector<const char*> required_extensions = +        ExtensionsRequiredForInstanceVersion(instance_version); +    std::vector<const char*> available_extensions; + +    if (requires_swapchain) { +        required_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);      } -    for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { -        if (available_extensions[i]) { -            continue; + +    auto extension_properties = physical.EnumerateDeviceExtensionProperties(); + +    for (const VkExtensionProperties& property : extension_properties) { +        available_extensions.push_back(property.extensionName); +    } + +    bool has_all_required_extensions = true; +    for (const char* requirement_name : required_extensions) { +        const bool found = +            std::ranges::any_of(available_extensions, [&](const char* extension_name) { +                return std::strcmp(requirement_name, extension_name) == 0; +            }); + +        if (!found) { +            LOG_ERROR(Render_Vulkan, "Missing required extension: {}", requirement_name); +            has_all_required_extensions = false;          } -        LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]); -        throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);      } -    if (requires_swapchain && !has_swapchain) { -        LOG_ERROR(Render_Vulkan, "Missing required extension: VK_KHR_swapchain"); + +    if (!has_all_required_extensions) {          throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);      } @@ -940,27 +970,46 @@ void Device::CheckSuitability(bool requires_swapchain) const {              throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);          }      } -    VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote{}; -    demote.sType = -        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT; +    VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures demote{}; +    demote.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES;      demote.pNext = nullptr; -    VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointers{}; -    variable_pointers.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR; +    VkPhysicalDeviceVariablePointerFeatures variable_pointers{}; +    variable_pointers.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES;      variable_pointers.pNext = &demote;      VkPhysicalDeviceRobustness2FeaturesEXT robustness2{};      robustness2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT;      robustness2.pNext = &variable_pointers; -    VkPhysicalDeviceFeatures2KHR features2{}; +    VkPhysicalDeviceTimelineSemaphoreFeatures timeline_semaphore{}; +    timeline_semaphore.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES; +    timeline_semaphore.pNext = &robustness2; + +    VkPhysicalDevice16BitStorageFeatures bit16_storage{}; +    bit16_storage.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES; +    bit16_storage.pNext = &timeline_semaphore; + +    VkPhysicalDevice8BitStorageFeatures bit8_storage{}; +    bit8_storage.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES; +    bit8_storage.pNext = &bit16_storage; + +    VkPhysicalDeviceHostQueryResetFeatures host_query_reset{}; +    host_query_reset.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES; +    host_query_reset.pNext = &bit8_storage; + +    VkPhysicalDeviceShaderDrawParametersFeatures draw_parameters{}; +    draw_parameters.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES; +    draw_parameters.pNext = &host_query_reset; + +    VkPhysicalDeviceFeatures2 features2{};      features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; -    features2.pNext = &robustness2; +    features2.pNext = &draw_parameters; -    physical.GetFeatures2KHR(features2); +    physical.GetFeatures2(features2);      const VkPhysicalDeviceFeatures& features{features2.features}; -    const std::array feature_report{ +    std::array feature_report{          std::make_pair(features.robustBufferAccess, "robustBufferAccess"),          std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"),          std::make_pair(features.imageCubeArray, "imageCubeArray"), @@ -976,6 +1025,7 @@ void Device::CheckSuitability(bool requires_swapchain) const {          std::make_pair(features.tessellationShader, "tessellationShader"),          std::make_pair(features.sampleRateShading, "sampleRateShading"),          std::make_pair(features.dualSrcBlend, "dualSrcBlend"), +        std::make_pair(features.logicOp, "logicOp"),          std::make_pair(features.occlusionQueryPrecise, "occlusionQueryPrecise"),          std::make_pair(features.fragmentStoresAndAtomics, "fragmentStoresAndAtomics"),          std::make_pair(features.shaderImageGatherExtended, "shaderImageGatherExtended"), @@ -983,27 +1033,38 @@ void Device::CheckSuitability(bool requires_swapchain) const {                         "shaderStorageImageWriteWithoutFormat"),          std::make_pair(features.shaderClipDistance, "shaderClipDistance"),          std::make_pair(features.shaderCullDistance, "shaderCullDistance"), -        std::make_pair(demote.shaderDemoteToHelperInvocation, "shaderDemoteToHelperInvocation"),          std::make_pair(variable_pointers.variablePointers, "variablePointers"),          std::make_pair(variable_pointers.variablePointersStorageBuffer,                         "variablePointersStorageBuffer"),          std::make_pair(robustness2.robustBufferAccess2, "robustBufferAccess2"),          std::make_pair(robustness2.robustImageAccess2, "robustImageAccess2"),          std::make_pair(robustness2.nullDescriptor, "nullDescriptor"), +        std::make_pair(demote.shaderDemoteToHelperInvocation, "shaderDemoteToHelperInvocation"), +        std::make_pair(timeline_semaphore.timelineSemaphore, "timelineSemaphore"), +        std::make_pair(bit16_storage.storageBuffer16BitAccess, "storageBuffer16BitAccess"), +        std::make_pair(bit16_storage.uniformAndStorageBuffer16BitAccess, +                       "uniformAndStorageBuffer16BitAccess"), +        std::make_pair(bit8_storage.uniformAndStorageBuffer8BitAccess, +                       "uniformAndStorageBuffer8BitAccess"), +        std::make_pair(host_query_reset.hostQueryReset, "hostQueryReset"), +        std::make_pair(draw_parameters.shaderDrawParameters, "shaderDrawParameters"),      }; + +    bool has_all_required_features = true;      for (const auto& [is_supported, name] : feature_report) { -        if (is_supported) { -            continue; +        if (!is_supported) { +            LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name); +            has_all_required_features = false;          } -        LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name); +    } + +    if (!has_all_required_features) {          throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);      }  }  std::vector<const char*> Device::LoadExtensions(bool requires_surface) { -    std::vector<const char*> extensions; -    extensions.reserve(8 + REQUIRED_EXTENSIONS.size()); -    extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()); +    std::vector<const char*> extensions = ExtensionsRequiredForInstanceVersion(instance_version);      if (requires_surface) {          extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);      } @@ -1079,37 +1140,37 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {                   VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME, false);          }      } -    VkPhysicalDeviceFeatures2KHR features{}; -    features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; +    VkPhysicalDeviceFeatures2 features{}; +    features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; -    VkPhysicalDeviceProperties2KHR physical_properties{}; -    physical_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; +    VkPhysicalDeviceProperties2 physical_properties{}; +    physical_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;      if (has_khr_shader_float16_int8) { -        VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8_features; -        float16_int8_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR; +        VkPhysicalDeviceShaderFloat16Int8Features float16_int8_features; +        float16_int8_features.sType = +            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES;          float16_int8_features.pNext = nullptr;          features.pNext = &float16_int8_features; -        physical.GetFeatures2KHR(features); +        physical.GetFeatures2(features);          is_float16_supported = float16_int8_features.shaderFloat16;          is_int8_supported = float16_int8_features.shaderInt8;          extensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME);      }      if (has_ext_subgroup_size_control) { -        VkPhysicalDeviceSubgroupSizeControlFeaturesEXT subgroup_features; -        subgroup_features.sType = -            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT; +        VkPhysicalDeviceSubgroupSizeControlFeatures subgroup_features; +        subgroup_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES;          subgroup_features.pNext = nullptr;          features.pNext = &subgroup_features; -        physical.GetFeatures2KHR(features); +        physical.GetFeatures2(features); -        VkPhysicalDeviceSubgroupSizeControlPropertiesEXT subgroup_properties; +        VkPhysicalDeviceSubgroupSizeControlProperties subgroup_properties;          subgroup_properties.sType = -            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT; +            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES;          subgroup_properties.pNext = nullptr;          physical_properties.pNext = &subgroup_properties; -        physical.GetProperties2KHR(physical_properties); +        physical.GetProperties2(physical_properties);          is_warp_potentially_bigger = subgroup_properties.maxSubgroupSize > GuestWarpSize; @@ -1128,7 +1189,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {          provoking_vertex.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT;          provoking_vertex.pNext = nullptr;          features.pNext = &provoking_vertex; -        physical.GetFeatures2KHR(features); +        physical.GetFeatures2(features);          if (provoking_vertex.provokingVertexLast &&              provoking_vertex.transformFeedbackPreservesProvokingVertex) { @@ -1142,7 +1203,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {              VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT;          vertex_input.pNext = nullptr;          features.pNext = &vertex_input; -        physical.GetFeatures2KHR(features); +        physical.GetFeatures2(features);          if (vertex_input.vertexInputDynamicState) {              extensions.push_back(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME); @@ -1154,7 +1215,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {          atomic_int64.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES;          atomic_int64.pNext = nullptr;          features.pNext = &atomic_int64; -        physical.GetFeatures2KHR(features); +        physical.GetFeatures2(features);          if (atomic_int64.shaderBufferInt64Atomics && atomic_int64.shaderSharedInt64Atomics) {              extensions.push_back(VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME); @@ -1166,13 +1227,13 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {          tfb_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT;          tfb_features.pNext = nullptr;          features.pNext = &tfb_features; -        physical.GetFeatures2KHR(features); +        physical.GetFeatures2(features);          VkPhysicalDeviceTransformFeedbackPropertiesEXT tfb_properties;          tfb_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;          tfb_properties.pNext = nullptr;          physical_properties.pNext = &tfb_properties; -        physical.GetProperties2KHR(physical_properties); +        physical.GetProperties2(physical_properties);          if (tfb_features.transformFeedback && tfb_features.geometryStreams &&              tfb_properties.maxTransformFeedbackStreams >= 4 && @@ -1187,7 +1248,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {          border_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT;          border_features.pNext = nullptr;          features.pNext = &border_features; -        physical.GetFeatures2KHR(features); +        physical.GetFeatures2(features);          if (border_features.customBorderColors && border_features.customBorderColorWithoutFormat) {              extensions.push_back(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); @@ -1200,7 +1261,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {              VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT;          extended_dynamic_state.pNext = nullptr;          features.pNext = &extended_dynamic_state; -        physical.GetFeatures2KHR(features); +        physical.GetFeatures2(features);          if (extended_dynamic_state.extendedDynamicState) {              extensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); @@ -1212,7 +1273,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {          line_raster.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT;          line_raster.pNext = nullptr;          features.pNext = &line_raster; -        physical.GetFeatures2KHR(features); +        physical.GetFeatures2(features);          if (line_raster.rectangularLines && line_raster.smoothLines) {              extensions.push_back(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME);              ext_line_rasterization = true; @@ -1224,7 +1285,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {              VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR;          layout.pNext = nullptr;          features.pNext = &layout; -        physical.GetFeatures2KHR(features); +        physical.GetFeatures2(features);          if (layout.workgroupMemoryExplicitLayout &&              layout.workgroupMemoryExplicitLayout8BitAccess && @@ -1240,7 +1301,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {              VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR;          executable_properties.pNext = nullptr;          features.pNext = &executable_properties; -        physical.GetFeatures2KHR(features); +        physical.GetFeatures2(features);          if (executable_properties.pipelineExecutableInfo) {              extensions.push_back(VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME); @@ -1253,7 +1314,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {              VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT;          primitive_topology_list_restart.pNext = nullptr;          features.pNext = &primitive_topology_list_restart; -        physical.GetFeatures2KHR(features); +        physical.GetFeatures2(features);          is_topology_list_restart_supported =              primitive_topology_list_restart.primitiveTopologyListRestart; @@ -1271,7 +1332,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {          push_descriptor.pNext = nullptr;          physical_properties.pNext = &push_descriptor; -        physical.GetProperties2KHR(physical_properties); +        physical.GetProperties2(physical_properties);          max_push_descriptors = push_descriptor.maxPushDescriptors;      } @@ -1322,18 +1383,18 @@ void Device::SetupFeatures() {  }  void Device::SetupProperties() { -    float_controls.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR; +    float_controls.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES;      VkPhysicalDeviceProperties2KHR properties2{}; -    properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; +    properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;      properties2.pNext = &float_controls; -    physical.GetProperties2KHR(properties2); +    physical.GetProperties2(properties2);  }  void Device::CollectTelemetryParameters() { -    VkPhysicalDeviceDriverPropertiesKHR driver{ -        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR, +    VkPhysicalDeviceDriverProperties driver{ +        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES,          .pNext = nullptr,          .driverID = {},          .driverName = {}, @@ -1341,12 +1402,12 @@ void Device::CollectTelemetryParameters() {          .conformanceVersion = {},      }; -    VkPhysicalDeviceProperties2KHR device_properties{ -        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR, +    VkPhysicalDeviceProperties2 device_properties{ +        .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,          .pNext = &driver,          .properties = {},      }; -    physical.GetProperties2KHR(device_properties); +    physical.GetProperties2(device_properties);      driver_id = driver.driverID;      vendor_name = driver.driverName; @@ -1402,23 +1463,10 @@ void Device::CollectToolingInfo() {      if (!ext_tooling_info) {          return;      } -    const auto vkGetPhysicalDeviceToolPropertiesEXT = -        reinterpret_cast<PFN_vkGetPhysicalDeviceToolPropertiesEXT>( -            dld.vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceToolPropertiesEXT")); -    if (!vkGetPhysicalDeviceToolPropertiesEXT) { -        return; -    } -    u32 tool_count = 0; -    if (vkGetPhysicalDeviceToolPropertiesEXT(physical, &tool_count, nullptr) != VK_SUCCESS) { -        return; -    } -    std::vector<VkPhysicalDeviceToolPropertiesEXT> tools(tool_count); -    if (vkGetPhysicalDeviceToolPropertiesEXT(physical, &tool_count, tools.data()) != VK_SUCCESS) { -        return; -    } -    for (const VkPhysicalDeviceToolPropertiesEXT& tool : tools) { +    auto tools{physical.GetPhysicalDeviceToolProperties()}; +    for (const VkPhysicalDeviceToolProperties& tool : tools) {          const std::string_view name = tool.name; -        LOG_INFO(Render_Vulkan, "{}", name); +        LOG_INFO(Render_Vulkan, "Attached debugging tool: {}", name);          has_renderdoc = has_renderdoc || name == "RenderDoc";          has_nsight_graphics = has_nsight_graphics || name == "NVIDIA Nsight Graphics";      } diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index d7cc6c593..db802437c 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -211,18 +211,13 @@ public:          return khr_uniform_buffer_standard_layout;      } -    /// Returns true if the device supports VK_KHR_spirv_1_4. -    bool IsKhrSpirv1_4Supported() const { -        return khr_spirv_1_4; -    } -      /// Returns true if the device supports VK_KHR_push_descriptor.      bool IsKhrPushDescriptorSupported() const {          return khr_push_descriptor;      }      /// Returns true if VK_KHR_pipeline_executable_properties is enabled. -    bool IsKhrPipelineEexecutablePropertiesEnabled() const { +    bool IsKhrPipelineExecutablePropertiesEnabled() const {          return khr_pipeline_executable_properties;      } @@ -316,6 +311,17 @@ public:          return ext_shader_atomic_int64;      } +    /// Returns the minimum supported version of SPIR-V. +    u32 SupportedSpirvVersion() const { +        if (instance_version >= VK_API_VERSION_1_3) { +            return 0x00010600U; +        } +        if (khr_spirv_1_4) { +            return 0x00010400U; +        } +        return 0x00010000U; +    } +      /// Returns true when a known debugging tool is attached.      bool HasDebuggingToolAttached() const {          return has_renderdoc || has_nsight_graphics; diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp index a082e3059..562039b56 100644 --- a/src/video_core/vulkan_common/vulkan_instance.cpp +++ b/src/video_core/vulkan_common/vulkan_instance.cpp @@ -9,18 +9,21 @@  #include "common/common_types.h"  #include "common/dynamic_library.h"  #include "common/logging/log.h" +#include "common/polyfill_ranges.h"  #include "core/frontend/emu_window.h"  #include "video_core/vulkan_common/vulkan_instance.h"  #include "video_core/vulkan_common/vulkan_wrapper.h"  // Include these late to avoid polluting previous headers -#ifdef _WIN32 +#if defined(_WIN32)  #include <windows.h>  // ensure include order  #include <vulkan/vulkan_win32.h> -#endif - -#if !defined(_WIN32) && !defined(__APPLE__) +#elif defined(__APPLE__) +#include <vulkan/vulkan_macos.h> +#elif defined(__ANDROID__) +#include <vulkan/vulkan_android.h> +#else  #include <X11/Xlib.h>  #include <vulkan/vulkan_wayland.h>  #include <vulkan/vulkan_xlib.h> @@ -39,8 +42,15 @@ namespace {      case Core::Frontend::WindowSystemType::Windows:          extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);          break; -#endif -#if !defined(_WIN32) && !defined(__APPLE__) +#elif defined(__APPLE__) +    case Core::Frontend::WindowSystemType::Cocoa: +        extensions.push_back(VK_MVK_MACOS_SURFACE_EXTENSION_NAME); +        break; +#elif defined(__ANDROID__) +    case Core::Frontend::WindowSystemType::Android: +        extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); +        break; +#else      case Core::Frontend::WindowSystemType::X11:          extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);          break; @@ -59,6 +69,10 @@ namespace {          extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);      }      extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + +#ifdef __APPLE__ +    extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); +#endif      return extensions;  } @@ -140,7 +154,7 @@ vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceD      }      vk::Instance instance =          std::async([&] { -            return vk::Instance::Create(required_version, layers, extensions, dld); +            return vk::Instance::Create(available_version, layers, extensions, dld);          }).get();      if (!vk::Load(*instance, dld)) {          LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers"); diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index 6442898bd..1732866e0 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -12,6 +12,7 @@  #include "common/assert.h"  #include "common/common_types.h"  #include "common/logging/log.h" +#include "common/polyfill_ranges.h"  #include "video_core/vulkan_common/vulkan_device.h"  #include "video_core/vulkan_common/vulkan_memory_allocator.h"  #include "video_core/vulkan_common/vulkan_wrapper.h" diff --git a/src/video_core/vulkan_common/vulkan_surface.cpp b/src/video_core/vulkan_common/vulkan_surface.cpp index 69f9c494b..fa9bafa20 100644 --- a/src/video_core/vulkan_common/vulkan_surface.cpp +++ b/src/video_core/vulkan_common/vulkan_surface.cpp @@ -11,9 +11,11 @@  #include <windows.h>  // ensure include order  #include <vulkan/vulkan_win32.h> -#endif - -#if !defined(_WIN32) && !defined(__APPLE__) +#elif defined(__APPLE__) +#include <vulkan/vulkan_macos.h> +#elif defined(__ANDROID__) +#include <vulkan/vulkan_android.h> +#else  #include <X11/Xlib.h>  #include <vulkan/vulkan_wayland.h>  #include <vulkan/vulkan_xlib.h> @@ -40,8 +42,33 @@ vk::SurfaceKHR CreateSurface(const vk::Instance& instance,              throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);          }      } -#endif -#if !defined(_WIN32) && !defined(__APPLE__) +#elif defined(__APPLE__) +    if (window_info.type == Core::Frontend::WindowSystemType::Cocoa) { +        const VkMacOSSurfaceCreateInfoMVK mvk_ci{VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, +                                                 nullptr, 0, window_info.render_surface}; +        const auto vkCreateMacOSSurfaceMVK = reinterpret_cast<PFN_vkCreateMacOSSurfaceMVK>( +            dld.vkGetInstanceProcAddr(*instance, "vkCreateMacOSSurfaceMVK")); +        if (!vkCreateMacOSSurfaceMVK || +            vkCreateMacOSSurfaceMVK(*instance, &mvk_ci, nullptr, &unsafe_surface) != VK_SUCCESS) { +            LOG_ERROR(Render_Vulkan, "Failed to initialize Metal surface"); +            throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); +        } +    } +#elif defined(__ANDROID__) +    if (window_info.type == Core::Frontend::WindowSystemType::Android) { +        const VkAndroidSurfaceCreateInfoKHR android_ci{ +            VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, nullptr, 0, +            reinterpret_cast<ANativeWindow*>(window_info.render_surface)}; +        const auto vkCreateAndroidSurfaceKHR = reinterpret_cast<PFN_vkCreateAndroidSurfaceKHR>( +            dld.vkGetInstanceProcAddr(*instance, "vkCreateAndroidSurfaceKHR")); +        if (!vkCreateAndroidSurfaceKHR || +            vkCreateAndroidSurfaceKHR(*instance, &android_ci, nullptr, &unsafe_surface) != +                VK_SUCCESS) { +            LOG_ERROR(Render_Vulkan, "Failed to initialize Android surface"); +            throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); +        } +    } +#else      if (window_info.type == Core::Frontend::WindowSystemType::X11) {          const VkXlibSurfaceCreateInfoKHR xlib_ci{              VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0, @@ -70,6 +97,7 @@ vk::SurfaceKHR CreateSurface(const vk::Instance& instance,          }      }  #endif +      if (!unsafe_surface) {          LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform");          throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 2ad98dcfe..bda10ee2f 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -130,7 +130,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {      X(vkCreateComputePipelines);      X(vkCreateDescriptorPool);      X(vkCreateDescriptorSetLayout); -    X(vkCreateDescriptorUpdateTemplateKHR); +    X(vkCreateDescriptorUpdateTemplate);      X(vkCreateEvent);      X(vkCreateFence);      X(vkCreateFramebuffer); @@ -149,7 +149,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {      X(vkDestroyCommandPool);      X(vkDestroyDescriptorPool);      X(vkDestroyDescriptorSetLayout); -    X(vkDestroyDescriptorUpdateTemplateKHR); +    X(vkDestroyDescriptorUpdateTemplate);      X(vkDestroyEvent);      X(vkDestroyFence);      X(vkDestroyFramebuffer); @@ -180,18 +180,29 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {      X(vkGetQueryPoolResults);      X(vkGetPipelineExecutablePropertiesKHR);      X(vkGetPipelineExecutableStatisticsKHR); -    X(vkGetSemaphoreCounterValueKHR); +    X(vkGetSemaphoreCounterValue);      X(vkMapMemory);      X(vkQueueSubmit);      X(vkResetFences); -    X(vkResetQueryPoolEXT); +    X(vkResetQueryPool);      X(vkSetDebugUtilsObjectNameEXT);      X(vkSetDebugUtilsObjectTagEXT);      X(vkUnmapMemory); -    X(vkUpdateDescriptorSetWithTemplateKHR); +    X(vkUpdateDescriptorSetWithTemplate);      X(vkUpdateDescriptorSets);      X(vkWaitForFences); -    X(vkWaitSemaphoresKHR); +    X(vkWaitSemaphores); + +    // Support for timeline semaphores is mandatory in Vulkan 1.2 +    if (!dld.vkGetSemaphoreCounterValue) { +        Proc(dld.vkGetSemaphoreCounterValue, dld, "vkGetSemaphoreCounterValueKHR", device); +        Proc(dld.vkWaitSemaphores, dld, "vkWaitSemaphoresKHR", device); +    } + +    // Support for host query reset is mandatory in Vulkan 1.2 +    if (!dld.vkResetQueryPool) { +        Proc(dld.vkResetQueryPool, dld, "vkResetQueryPoolEXT", device); +    }  #undef X  } @@ -224,12 +235,13 @@ bool Load(VkInstance instance, InstanceDispatch& dld) noexcept {      X(vkCreateDebugUtilsMessengerEXT);      X(vkDestroyDebugUtilsMessengerEXT);      X(vkDestroySurfaceKHR); -    X(vkGetPhysicalDeviceFeatures2KHR); -    X(vkGetPhysicalDeviceProperties2KHR); +    X(vkGetPhysicalDeviceFeatures2); +    X(vkGetPhysicalDeviceProperties2);      X(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);      X(vkGetPhysicalDeviceSurfaceFormatsKHR);      X(vkGetPhysicalDeviceSurfacePresentModesKHR);      X(vkGetPhysicalDeviceSurfaceSupportKHR); +    X(vkGetPhysicalDeviceToolProperties);      X(vkGetSwapchainImagesKHR);      X(vkQueuePresentKHR); @@ -359,9 +371,9 @@ void Destroy(VkDevice device, VkDescriptorSetLayout handle, const DeviceDispatch      dld.vkDestroyDescriptorSetLayout(device, handle, nullptr);  } -void Destroy(VkDevice device, VkDescriptorUpdateTemplateKHR handle, +void Destroy(VkDevice device, VkDescriptorUpdateTemplate handle,               const DeviceDispatch& dld) noexcept { -    dld.vkDestroyDescriptorUpdateTemplateKHR(device, handle, nullptr); +    dld.vkDestroyDescriptorUpdateTemplate(device, handle, nullptr);  }  void Destroy(VkDevice device, VkDeviceMemory handle, const DeviceDispatch& dld) noexcept { @@ -442,6 +454,12 @@ VkResult Free(VkDevice device, VkCommandPool handle, Span<VkCommandBuffer> buffe  Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char*> extensions,                            InstanceDispatch& dispatch) { +#ifdef __APPLE__ +    constexpr VkFlags ci_flags{VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR}; +#else +    constexpr VkFlags ci_flags{}; +#endif +      const VkApplicationInfo application_info{          .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,          .pNext = nullptr, @@ -454,7 +472,7 @@ Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char      const VkInstanceCreateInfo ci{          .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,          .pNext = nullptr, -        .flags = 0, +        .flags = ci_flags,          .pApplicationInfo = &application_info,          .enabledLayerCount = layers.size(),          .ppEnabledLayerNames = layers.data(), @@ -737,11 +755,11 @@ CommandPool Device::CreateCommandPool(const VkCommandPoolCreateInfo& ci) const {      return CommandPool(object, handle, *dld);  } -DescriptorUpdateTemplateKHR Device::CreateDescriptorUpdateTemplateKHR( -    const VkDescriptorUpdateTemplateCreateInfoKHR& ci) const { -    VkDescriptorUpdateTemplateKHR object; -    Check(dld->vkCreateDescriptorUpdateTemplateKHR(handle, &ci, nullptr, &object)); -    return DescriptorUpdateTemplateKHR(object, handle, *dld); +DescriptorUpdateTemplate Device::CreateDescriptorUpdateTemplate( +    const VkDescriptorUpdateTemplateCreateInfo& ci) const { +    VkDescriptorUpdateTemplate object; +    Check(dld->vkCreateDescriptorUpdateTemplate(handle, &ci, nullptr, &object)); +    return DescriptorUpdateTemplate(object, handle, *dld);  }  QueryPool Device::CreateQueryPool(const VkQueryPoolCreateInfo& ci) const { @@ -857,20 +875,20 @@ VkPhysicalDeviceProperties PhysicalDevice::GetProperties() const noexcept {      return properties;  } -void PhysicalDevice::GetProperties2KHR(VkPhysicalDeviceProperties2KHR& properties) const noexcept { -    dld->vkGetPhysicalDeviceProperties2KHR(physical_device, &properties); +void PhysicalDevice::GetProperties2(VkPhysicalDeviceProperties2& properties) const noexcept { +    dld->vkGetPhysicalDeviceProperties2(physical_device, &properties);  }  VkPhysicalDeviceFeatures PhysicalDevice::GetFeatures() const noexcept { -    VkPhysicalDeviceFeatures2KHR features2; -    features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; +    VkPhysicalDeviceFeatures2 features2; +    features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;      features2.pNext = nullptr; -    dld->vkGetPhysicalDeviceFeatures2KHR(physical_device, &features2); +    dld->vkGetPhysicalDeviceFeatures2(physical_device, &features2);      return features2.features;  } -void PhysicalDevice::GetFeatures2KHR(VkPhysicalDeviceFeatures2KHR& features) const noexcept { -    dld->vkGetPhysicalDeviceFeatures2KHR(physical_device, &features); +void PhysicalDevice::GetFeatures2(VkPhysicalDeviceFeatures2& features) const noexcept { +    dld->vkGetPhysicalDeviceFeatures2(physical_device, &features);  }  VkFormatProperties PhysicalDevice::GetFormatProperties(VkFormat format) const noexcept { @@ -895,6 +913,18 @@ std::vector<VkQueueFamilyProperties> PhysicalDevice::GetQueueFamilyProperties()      return properties;  } +std::vector<VkPhysicalDeviceToolProperties> PhysicalDevice::GetPhysicalDeviceToolProperties() +    const { +    u32 num = 0; +    if (!dld->vkGetPhysicalDeviceToolProperties) { +        return {}; +    } +    dld->vkGetPhysicalDeviceToolProperties(physical_device, &num, nullptr); +    std::vector<VkPhysicalDeviceToolProperties> properties(num); +    dld->vkGetPhysicalDeviceToolProperties(physical_device, &num, properties.data()); +    return properties; +} +  bool PhysicalDevice::GetSurfaceSupportKHR(u32 queue_family_index, VkSurfaceKHR surface) const {      VkBool32 supported;      Check(dld->vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue_family_index, surface, diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 1b3f493bd..8395ff2cb 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -168,12 +168,13 @@ struct InstanceDispatch {      PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties{};      PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices{};      PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr{}; -    PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR{}; +    PFN_vkGetPhysicalDeviceFeatures2 vkGetPhysicalDeviceFeatures2{};      PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties{};      PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties{};      PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2{};      PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties{}; -    PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR{}; +    PFN_vkGetPhysicalDeviceProperties2 vkGetPhysicalDeviceProperties2{}; +    PFN_vkGetPhysicalDeviceToolProperties vkGetPhysicalDeviceToolProperties{};      PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties{};      PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR{};      PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR{}; @@ -247,7 +248,7 @@ struct DeviceDispatch : InstanceDispatch {      PFN_vkCreateComputePipelines vkCreateComputePipelines{};      PFN_vkCreateDescriptorPool vkCreateDescriptorPool{};      PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout{}; -    PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR{}; +    PFN_vkCreateDescriptorUpdateTemplate vkCreateDescriptorUpdateTemplate{};      PFN_vkCreateEvent vkCreateEvent{};      PFN_vkCreateFence vkCreateFence{};      PFN_vkCreateFramebuffer vkCreateFramebuffer{}; @@ -266,7 +267,7 @@ struct DeviceDispatch : InstanceDispatch {      PFN_vkDestroyCommandPool vkDestroyCommandPool{};      PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool{};      PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout{}; -    PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR{}; +    PFN_vkDestroyDescriptorUpdateTemplate vkDestroyDescriptorUpdateTemplate{};      PFN_vkDestroyEvent vkDestroyEvent{};      PFN_vkDestroyFence vkDestroyFence{};      PFN_vkDestroyFramebuffer vkDestroyFramebuffer{}; @@ -297,18 +298,18 @@ struct DeviceDispatch : InstanceDispatch {      PFN_vkGetPipelineExecutablePropertiesKHR vkGetPipelineExecutablePropertiesKHR{};      PFN_vkGetPipelineExecutableStatisticsKHR vkGetPipelineExecutableStatisticsKHR{};      PFN_vkGetQueryPoolResults vkGetQueryPoolResults{}; -    PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR{}; +    PFN_vkGetSemaphoreCounterValue vkGetSemaphoreCounterValue{};      PFN_vkMapMemory vkMapMemory{};      PFN_vkQueueSubmit vkQueueSubmit{};      PFN_vkResetFences vkResetFences{}; -    PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT{}; +    PFN_vkResetQueryPool vkResetQueryPool{};      PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT{};      PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT{};      PFN_vkUnmapMemory vkUnmapMemory{}; -    PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR{}; +    PFN_vkUpdateDescriptorSetWithTemplate vkUpdateDescriptorSetWithTemplate{};      PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets{};      PFN_vkWaitForFences vkWaitForFences{}; -    PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR{}; +    PFN_vkWaitSemaphores vkWaitSemaphores{};  };  /// Loads instance agnostic function pointers. @@ -327,7 +328,7 @@ void Destroy(VkDevice, VkBufferView, const DeviceDispatch&) noexcept;  void Destroy(VkDevice, VkCommandPool, const DeviceDispatch&) noexcept;  void Destroy(VkDevice, VkDescriptorPool, const DeviceDispatch&) noexcept;  void Destroy(VkDevice, VkDescriptorSetLayout, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkDescriptorUpdateTemplateKHR, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkDescriptorUpdateTemplate, const DeviceDispatch&) noexcept;  void Destroy(VkDevice, VkDeviceMemory, const DeviceDispatch&) noexcept;  void Destroy(VkDevice, VkEvent, const DeviceDispatch&) noexcept;  void Destroy(VkDevice, VkFence, const DeviceDispatch&) noexcept; @@ -559,7 +560,7 @@ private:  using DebugUtilsMessenger = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>;  using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>; -using DescriptorUpdateTemplateKHR = Handle<VkDescriptorUpdateTemplateKHR, VkDevice, DeviceDispatch>; +using DescriptorUpdateTemplate = Handle<VkDescriptorUpdateTemplate, VkDevice, DeviceDispatch>;  using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>;  using PipelineLayout = Handle<VkPipelineLayout, VkDevice, DeviceDispatch>;  using QueryPool = Handle<VkQueryPool, VkDevice, DeviceDispatch>; @@ -766,7 +767,7 @@ public:      [[nodiscard]] u64 GetCounter() const {          u64 value; -        Check(dld->vkGetSemaphoreCounterValueKHR(owner, handle, &value)); +        Check(dld->vkGetSemaphoreCounterValue(owner, handle, &value));          return value;      } @@ -778,15 +779,15 @@ public:       * @return        True on successful wait, false on timeout       */      bool Wait(u64 value, u64 timeout = std::numeric_limits<u64>::max()) const { -        const VkSemaphoreWaitInfoKHR wait_info{ -            .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO_KHR, +        const VkSemaphoreWaitInfo wait_info{ +            .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO,              .pNext = nullptr,              .flags = 0,              .semaphoreCount = 1,              .pSemaphores = &handle,              .pValues = &value,          }; -        const VkResult result = dld->vkWaitSemaphoresKHR(owner, &wait_info, timeout); +        const VkResult result = dld->vkWaitSemaphores(owner, &wait_info, timeout);          switch (result) {          case VK_SUCCESS:              return true; @@ -840,8 +841,8 @@ public:      CommandPool CreateCommandPool(const VkCommandPoolCreateInfo& ci) const; -    DescriptorUpdateTemplateKHR CreateDescriptorUpdateTemplateKHR( -        const VkDescriptorUpdateTemplateCreateInfoKHR& ci) const; +    DescriptorUpdateTemplate CreateDescriptorUpdateTemplate( +        const VkDescriptorUpdateTemplateCreateInfo& ci) const;      QueryPool CreateQueryPool(const VkQueryPoolCreateInfo& ci) const; @@ -869,9 +870,9 @@ public:      void UpdateDescriptorSets(Span<VkWriteDescriptorSet> writes,                                Span<VkCopyDescriptorSet> copies) const noexcept; -    void UpdateDescriptorSet(VkDescriptorSet set, VkDescriptorUpdateTemplateKHR update_template, +    void UpdateDescriptorSet(VkDescriptorSet set, VkDescriptorUpdateTemplate update_template,                               const void* data) const noexcept { -        dld->vkUpdateDescriptorSetWithTemplateKHR(handle, set, update_template, data); +        dld->vkUpdateDescriptorSetWithTemplate(handle, set, update_template, data);      }      VkResult AcquireNextImageKHR(VkSwapchainKHR swapchain, u64 timeout, VkSemaphore semaphore, @@ -884,8 +885,8 @@ public:          return dld->vkDeviceWaitIdle(handle);      } -    void ResetQueryPoolEXT(VkQueryPool query_pool, u32 first, u32 count) const noexcept { -        dld->vkResetQueryPoolEXT(handle, query_pool, first, count); +    void ResetQueryPool(VkQueryPool query_pool, u32 first, u32 count) const noexcept { +        dld->vkResetQueryPool(handle, query_pool, first, count);      }      VkResult GetQueryResults(VkQueryPool query_pool, u32 first, u32 count, std::size_t data_size, @@ -910,11 +911,11 @@ public:      VkPhysicalDeviceProperties GetProperties() const noexcept; -    void GetProperties2KHR(VkPhysicalDeviceProperties2KHR&) const noexcept; +    void GetProperties2(VkPhysicalDeviceProperties2&) const noexcept;      VkPhysicalDeviceFeatures GetFeatures() const noexcept; -    void GetFeatures2KHR(VkPhysicalDeviceFeatures2KHR&) const noexcept; +    void GetFeatures2(VkPhysicalDeviceFeatures2&) const noexcept;      VkFormatProperties GetFormatProperties(VkFormat) const noexcept; @@ -922,6 +923,8 @@ public:      std::vector<VkQueueFamilyProperties> GetQueueFamilyProperties() const; +    std::vector<VkPhysicalDeviceToolProperties> GetPhysicalDeviceToolProperties() const; +      bool GetSurfaceSupportKHR(u32 queue_family_index, VkSurfaceKHR) const;      VkSurfaceCapabilitiesKHR GetSurfaceCapabilitiesKHR(VkSurfaceKHR) const; @@ -980,7 +983,7 @@ public:                                       dynamic_offsets.size(), dynamic_offsets.data());      } -    void PushDescriptorSetWithTemplateKHR(VkDescriptorUpdateTemplateKHR update_template, +    void PushDescriptorSetWithTemplateKHR(VkDescriptorUpdateTemplate update_template,                                            VkPipelineLayout layout, u32 set,                                            const void* data) const noexcept {          dld->vkCmdPushDescriptorSetWithTemplateKHR(handle, update_template, layout, set, data); diff --git a/src/web_service/CMakeLists.txt b/src/web_service/CMakeLists.txt index 3f75d97d1..02582aa04 100644 --- a/src/web_service/CMakeLists.txt +++ b/src/web_service/CMakeLists.txt @@ -4,6 +4,7 @@  add_library(web_service STATIC      announce_room_json.cpp      announce_room_json.h +    precompiled_headers.h      telemetry_json.cpp      telemetry_json.h      verify_login.cpp @@ -16,4 +17,8 @@ add_library(web_service STATIC  )  create_target_directory_groups(web_service) -target_link_libraries(web_service PRIVATE common network nlohmann_json::nlohmann_json httplib cpp-jwt) +target_link_libraries(web_service PRIVATE common network nlohmann_json::nlohmann_json httplib::httplib cpp-jwt::cpp-jwt) + +if (YUZU_USE_PRECOMPILED_HEADERS) +    target_precompile_headers(web_service PRIVATE precompiled_headers.h) +endif() diff --git a/src/web_service/precompiled_headers.h b/src/web_service/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/web_service/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 060de0259..d23eb2907 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -88,6 +88,9 @@ add_executable(yuzu      configuration/configure_input_advanced.cpp      configuration/configure_input_advanced.h      configuration/configure_input_advanced.ui +    configuration/configure_input_per_game.cpp +    configuration/configure_input_per_game.h +    configuration/configure_input_per_game.ui      configuration/configure_input_player.cpp      configuration/configure_input_player.h      configuration/configure_input_player.ui @@ -186,6 +189,7 @@ add_executable(yuzu      multiplayer/state.cpp      multiplayer/state.h      multiplayer/validation.h +    precompiled_headers.h      startup_checks.cpp      startup_checks.h      uisettings.cpp @@ -314,7 +318,7 @@ target_link_libraries(yuzu PRIVATE common core input_common network video_core)  target_link_libraries(yuzu PRIVATE Boost::boost glad Qt${QT_MAJOR_VERSION}::Widgets)  target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) -target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include) +target_link_libraries(yuzu PRIVATE Vulkan::Headers)  if (NOT WIN32)      target_include_directories(yuzu PRIVATE ${Qt${QT_MAJOR_VERSION}Gui_PRIVATE_INCLUDE_DIRS})  endif() @@ -350,7 +354,7 @@ if (USE_DISCORD_PRESENCE)          discord_impl.cpp          discord_impl.h      ) -    target_link_libraries(yuzu PRIVATE discord-rpc) +    target_link_libraries(yuzu PRIVATE DiscordRPC::discord-rpc)      target_compile_definitions(yuzu PRIVATE -DUSE_DISCORD_PRESENCE)  endif() @@ -387,11 +391,7 @@ if (YUZU_USE_BUNDLED_QT AND QT_VERSION VERSION_LESS 6)  endif()  if (ENABLE_SDL2) -    if (YUZU_USE_EXTERNAL_SDL2) -        target_link_libraries(yuzu PRIVATE SDL2-static) -    else() -        target_link_libraries(yuzu PRIVATE SDL2) -    endif() +    target_link_libraries(yuzu PRIVATE SDL2::SDL2)      target_compile_definitions(yuzu PRIVATE HAVE_SDL2)  endif() @@ -407,5 +407,9 @@ if (NOT APPLE)  endif()  if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) -    target_link_libraries(yuzu PRIVATE dynarmic) +    target_link_libraries(yuzu PRIVATE dynarmic::dynarmic) +endif() + +if (YUZU_USE_PRECOMPILED_HEADERS) +    target_precompile_headers(yuzu PRIVATE precompiled_headers.h)  endif() diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index 12efdc216..c30b54499 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -685,7 +685,7 @@ QtControllerSelector::QtControllerSelector(GMainWindow& parent) {  QtControllerSelector::~QtControllerSelector() = default;  void QtControllerSelector::ReconfigureControllers( -    std::function<void()> callback_, const Core::Frontend::ControllerParameters& parameters) const { +    ReconfigureCallback callback_, const Core::Frontend::ControllerParameters& parameters) const {      callback = std::move(callback_);      emit MainWindowReconfigureControllers(parameters);  } diff --git a/src/yuzu/applets/qt_controller.h b/src/yuzu/applets/qt_controller.h index cf948d2b5..16e99f507 100644 --- a/src/yuzu/applets/qt_controller.h +++ b/src/yuzu/applets/qt_controller.h @@ -157,7 +157,7 @@ public:      ~QtControllerSelector() override;      void ReconfigureControllers( -        std::function<void()> callback_, +        ReconfigureCallback callback_,          const Core::Frontend::ControllerParameters& parameters) const override;  signals: @@ -167,5 +167,5 @@ signals:  private:      void MainWindowReconfigureFinished(); -    mutable std::function<void()> callback; +    mutable ReconfigureCallback callback;  }; diff --git a/src/yuzu/applets/qt_error.cpp b/src/yuzu/applets/qt_error.cpp index 367d5352d..e0190a979 100644 --- a/src/yuzu/applets/qt_error.cpp +++ b/src/yuzu/applets/qt_error.cpp @@ -14,7 +14,7 @@ QtErrorDisplay::QtErrorDisplay(GMainWindow& parent) {  QtErrorDisplay::~QtErrorDisplay() = default; -void QtErrorDisplay::ShowError(Result error, std::function<void()> finished) const { +void QtErrorDisplay::ShowError(Result error, FinishedCallback finished) const {      callback = std::move(finished);      emit MainWindowDisplayError(          tr("Error Code: %1-%2 (0x%3)") @@ -25,7 +25,7 @@ void QtErrorDisplay::ShowError(Result error, std::function<void()> finished) con  }  void QtErrorDisplay::ShowErrorWithTimestamp(Result error, std::chrono::seconds time, -                                            std::function<void()> finished) const { +                                            FinishedCallback finished) const {      callback = std::move(finished);      const QDateTime date_time = QDateTime::fromSecsSinceEpoch(time.count()); @@ -42,7 +42,7 @@ void QtErrorDisplay::ShowErrorWithTimestamp(Result error, std::chrono::seconds t  void QtErrorDisplay::ShowCustomErrorText(Result error, std::string dialog_text,                                           std::string fullscreen_text, -                                         std::function<void()> finished) const { +                                         FinishedCallback finished) const {      callback = std::move(finished);      emit MainWindowDisplayError(          tr("Error Code: %1-%2 (0x%3)") diff --git a/src/yuzu/applets/qt_error.h b/src/yuzu/applets/qt_error.h index eb4107c7e..e4e174721 100644 --- a/src/yuzu/applets/qt_error.h +++ b/src/yuzu/applets/qt_error.h @@ -16,11 +16,11 @@ public:      explicit QtErrorDisplay(GMainWindow& parent);      ~QtErrorDisplay() override; -    void ShowError(Result error, std::function<void()> finished) const override; +    void ShowError(Result error, FinishedCallback finished) const override;      void ShowErrorWithTimestamp(Result error, std::chrono::seconds time, -                                std::function<void()> finished) const override; +                                FinishedCallback finished) const override;      void ShowCustomErrorText(Result error, std::string dialog_text, std::string fullscreen_text, -                             std::function<void()> finished) const override; +                             FinishedCallback finished) const override;  signals:      void MainWindowDisplayError(QString error_code, QString error_text) const; @@ -28,5 +28,5 @@ signals:  private:      void MainWindowFinishedError(); -    mutable std::function<void()> callback; +    mutable FinishedCallback callback;  }; diff --git a/src/yuzu/applets/qt_profile_select.cpp b/src/yuzu/applets/qt_profile_select.cpp index c8bcfb223..4145c5299 100644 --- a/src/yuzu/applets/qt_profile_select.cpp +++ b/src/yuzu/applets/qt_profile_select.cpp @@ -163,8 +163,7 @@ QtProfileSelector::QtProfileSelector(GMainWindow& parent) {  QtProfileSelector::~QtProfileSelector() = default; -void QtProfileSelector::SelectProfile( -    std::function<void(std::optional<Common::UUID>)> callback_) const { +void QtProfileSelector::SelectProfile(SelectProfileCallback callback_) const {      callback = std::move(callback_);      emit MainWindowSelectProfile();  } diff --git a/src/yuzu/applets/qt_profile_select.h b/src/yuzu/applets/qt_profile_select.h index 124f2cdbd..637a3bda2 100644 --- a/src/yuzu/applets/qt_profile_select.h +++ b/src/yuzu/applets/qt_profile_select.h @@ -65,7 +65,7 @@ public:      explicit QtProfileSelector(GMainWindow& parent);      ~QtProfileSelector() override; -    void SelectProfile(std::function<void(std::optional<Common::UUID>)> callback_) const override; +    void SelectProfile(SelectProfileCallback callback_) const override;  signals:      void MainWindowSelectProfile() const; @@ -73,5 +73,5 @@ signals:  private:      void MainWindowFinishedSelection(std::optional<Common::UUID> uuid); -    mutable std::function<void(std::optional<Common::UUID>)> callback; +    mutable SelectProfileCallback callback;  }; diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp index e60506197..734b0ea40 100644 --- a/src/yuzu/applets/qt_software_keyboard.cpp +++ b/src/yuzu/applets/qt_software_keyboard.cpp @@ -1566,10 +1566,7 @@ QtSoftwareKeyboard::~QtSoftwareKeyboard() = default;  void QtSoftwareKeyboard::InitializeKeyboard(      bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters, -    std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)> -        submit_normal_callback_, -    std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)> -        submit_inline_callback_) { +    SubmitNormalCallback submit_normal_callback_, SubmitInlineCallback submit_inline_callback_) {      if (is_inline) {          submit_inline_callback = std::move(submit_inline_callback_);      } else { diff --git a/src/yuzu/applets/qt_software_keyboard.h b/src/yuzu/applets/qt_software_keyboard.h index 35d4ee2ef..30ac8ecf6 100644 --- a/src/yuzu/applets/qt_software_keyboard.h +++ b/src/yuzu/applets/qt_software_keyboard.h @@ -233,12 +233,10 @@ public:      explicit QtSoftwareKeyboard(GMainWindow& parent);      ~QtSoftwareKeyboard() override; -    void InitializeKeyboard( -        bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters, -        std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)> -            submit_normal_callback_, -        std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)> -            submit_inline_callback_) override; +    void InitializeKeyboard(bool is_inline, +                            Core::Frontend::KeyboardInitializeParameters initialize_parameters, +                            SubmitNormalCallback submit_normal_callback_, +                            SubmitInlineCallback submit_inline_callback_) override;      void ShowNormalKeyboard() const override; @@ -279,8 +277,6 @@ private:      void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,                            std::u16string submitted_text, s32 cursor_position) const; -    mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)> -        submit_normal_callback; -    mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)> -        submit_inline_callback; +    mutable SubmitNormalCallback submit_normal_callback; +    mutable SubmitInlineCallback submit_inline_callback;  }; diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp index 89bd482e0..0a5912326 100644 --- a/src/yuzu/applets/qt_web_browser.cpp +++ b/src/yuzu/applets/qt_web_browser.cpp @@ -401,9 +401,9 @@ QtWebBrowser::QtWebBrowser(GMainWindow& main_window) {  QtWebBrowser::~QtWebBrowser() = default; -void QtWebBrowser::OpenLocalWebPage( -    const std::string& local_url, std::function<void()> extract_romfs_callback_, -    std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback_) const { +void QtWebBrowser::OpenLocalWebPage(const std::string& local_url, +                                    ExtractROMFSCallback extract_romfs_callback_, +                                    OpenWebPageCallback callback_) const {      extract_romfs_callback = std::move(extract_romfs_callback_);      callback = std::move(callback_); @@ -416,9 +416,8 @@ void QtWebBrowser::OpenLocalWebPage(      }  } -void QtWebBrowser::OpenExternalWebPage( -    const std::string& external_url, -    std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback_) const { +void QtWebBrowser::OpenExternalWebPage(const std::string& external_url, +                                       OpenWebPageCallback callback_) const {      callback = std::move(callback_);      const auto index = external_url.find('?'); diff --git a/src/yuzu/applets/qt_web_browser.h b/src/yuzu/applets/qt_web_browser.h index 043800853..e8fe511ed 100644 --- a/src/yuzu/applets/qt_web_browser.h +++ b/src/yuzu/applets/qt_web_browser.h @@ -197,13 +197,11 @@ public:      ~QtWebBrowser() override;      void OpenLocalWebPage(const std::string& local_url, -                          std::function<void()> extract_romfs_callback_, -                          std::function<void(Service::AM::Applets::WebExitReason, std::string)> -                              callback_) const override; +                          ExtractROMFSCallback extract_romfs_callback_, +                          OpenWebPageCallback callback_) const override;      void OpenExternalWebPage(const std::string& external_url, -                             std::function<void(Service::AM::Applets::WebExitReason, std::string)> -                                 callback_) const override; +                             OpenWebPageCallback callback_) const override;  signals:      void MainWindowOpenWebPage(const std::string& main_url, const std::string& additional_args, @@ -215,7 +213,6 @@ private:      void MainWindowWebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason,                                      std::string last_url); -    mutable std::function<void()> extract_romfs_callback; - -    mutable std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback; +    mutable ExtractROMFSCallback extract_romfs_callback; +    mutable OpenWebPageCallback callback;  }; diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index c934069dd..5b5b6fed8 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -118,7 +118,7 @@ void EmuThread::run() {              }          } else {              std::unique_lock lock{running_mutex}; -            running_cv.wait(lock, stop_token, [this] { return IsRunning(); }); +            Common::CondvarWait(running_cv, lock, stop_token, [&] { return IsRunning(); });          }      } @@ -237,8 +237,7 @@ private:      GRenderWindow* render_window;  }; -class OpenGLRenderWidget : public RenderWidget { -public: +struct OpenGLRenderWidget : public RenderWidget {      explicit OpenGLRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {          windowHandle()->setSurfaceType(QWindow::OpenGLSurface);      } @@ -251,13 +250,16 @@ private:      std::unique_ptr<Core::Frontend::GraphicsContext> context;  }; -class VulkanRenderWidget : public RenderWidget { -public: +struct VulkanRenderWidget : public RenderWidget {      explicit VulkanRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {          windowHandle()->setSurfaceType(QWindow::VulkanSurface);      }  }; +struct NullRenderWidget : public RenderWidget { +    explicit NullRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {} +}; +  static Core::Frontend::WindowSystemType GetWindowSystemType() {      // Determine WSI type based on Qt platform.      QString platform_name = QGuiApplication::platformName(); @@ -267,6 +269,10 @@ static Core::Frontend::WindowSystemType GetWindowSystemType() {          return Core::Frontend::WindowSystemType::X11;      else if (platform_name == QStringLiteral("wayland"))          return Core::Frontend::WindowSystemType::Wayland; +    else if (platform_name == QStringLiteral("cocoa")) +        return Core::Frontend::WindowSystemType::Cocoa; +    else if (platform_name == QStringLiteral("android")) +        return Core::Frontend::WindowSystemType::Android;      LOG_CRITICAL(Frontend, "Unknown Qt platform!");      return Core::Frontend::WindowSystemType::Windows; @@ -874,6 +880,9 @@ bool GRenderWindow::InitRenderTarget() {              return false;          }          break; +    case Settings::RendererBackend::Null: +        InitializeNull(); +        break;      }      // Update the Window System information with the new render target @@ -970,6 +979,11 @@ bool GRenderWindow::InitializeVulkan() {      return true;  } +void GRenderWindow::InitializeNull() { +    child_widget = new NullRenderWidget(this); +    main_context = std::make_unique<DummyContext>(); +} +  bool GRenderWindow::LoadOpenGL() {      auto context = CreateSharedContext();      auto scope = context->Acquire(); diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 4a01481cd..f4deae4ee 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -14,6 +14,7 @@  #include <QTouchEvent>  #include <QWidget> +#include "common/polyfill_thread.h"  #include "common/thread.h"  #include "core/frontend/emu_window.h" @@ -218,6 +219,7 @@ private:      bool InitializeOpenGL();      bool InitializeVulkan(); +    void InitializeNull();      bool LoadOpenGL();      QStringList GetUnsupportedGLExtensions() const; diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 750285478..722fc708e 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -124,6 +124,10 @@ void Config::Initialize(const std::string& config_name) {      }  } +bool Config::IsCustomConfig() { +    return type == ConfigType::PerGameConfig; +} +  /* {Read,Write}BasicSetting and WriteGlobalSetting templates must be defined here before their   * usages later in this file. This allows explicit definition of some types that don't work   * nicely with the general version. @@ -194,8 +198,20 @@ void Config::ReadPlayerValue(std::size_t player_index) {      }();      auto& player = Settings::values.players.GetValue()[player_index]; +    if (IsCustomConfig()) { +        const auto profile_name = +            qt_config->value(QStringLiteral("%1profile_name").arg(player_prefix), QString{}) +                .toString() +                .toStdString(); +        if (profile_name.empty()) { +            // Use the global input config +            player = Settings::values.players.GetValue(true)[player_index]; +            return; +        } +        player.profile_name = profile_name; +    } -    if (player_prefix.isEmpty()) { +    if (player_prefix.isEmpty() && Settings::IsConfiguringGlobal()) {          const auto controller = static_cast<Settings::ControllerType>(              qt_config                  ->value(QStringLiteral("%1type").arg(player_prefix), @@ -388,9 +404,26 @@ void Config::ReadAudioValues() {  void Config::ReadControlValues() {      qt_config->beginGroup(QStringLiteral("Controls")); +    Settings::values.players.SetGlobal(!IsCustomConfig());      for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {          ReadPlayerValue(p);      } +    ReadGlobalSetting(Settings::values.use_docked_mode); + +    // Disable docked mode if handheld is selected +    const auto controller_type = Settings::values.players.GetValue()[0].controller_type; +    if (controller_type == Settings::ControllerType::Handheld) { +        Settings::values.use_docked_mode.SetGlobal(!IsCustomConfig()); +        Settings::values.use_docked_mode.SetValue(false); +    } + +    ReadGlobalSetting(Settings::values.vibration_enabled); +    ReadGlobalSetting(Settings::values.enable_accurate_vibrations); +    ReadGlobalSetting(Settings::values.motion_enabled); +    if (IsCustomConfig()) { +        qt_config->endGroup(); +        return; +    }      ReadDebugValues();      ReadKeyboardValues();      ReadMouseValues(); @@ -412,18 +445,6 @@ void Config::ReadControlValues() {      ReadBasicSetting(Settings::values.tas_loop);      ReadBasicSetting(Settings::values.pause_tas_on_load); -    ReadGlobalSetting(Settings::values.use_docked_mode); - -    // Disable docked mode if handheld is selected -    const auto controller_type = Settings::values.players.GetValue()[0].controller_type; -    if (controller_type == Settings::ControllerType::Handheld) { -        Settings::values.use_docked_mode.SetValue(false); -    } - -    ReadGlobalSetting(Settings::values.vibration_enabled); -    ReadGlobalSetting(Settings::values.enable_accurate_vibrations); -    ReadGlobalSetting(Settings::values.motion_enabled); -      ReadBasicSetting(Settings::values.controller_navigation);      qt_config->endGroup(); @@ -906,7 +927,6 @@ void Config::ReadMultiplayerValues() {  void Config::ReadValues() {      if (global) { -        ReadControlValues();          ReadDataStorageValues();          ReadDebuggingValues();          ReadDisabledAddOnValues(); @@ -915,6 +935,7 @@ void Config::ReadValues() {          ReadWebServiceValues();          ReadMiscellaneousValues();      } +    ReadControlValues();      ReadCoreValues();      ReadCpuValues();      ReadRendererValues(); @@ -933,12 +954,20 @@ void Config::SavePlayerValue(std::size_t player_index) {      }();      const auto& player = Settings::values.players.GetValue()[player_index]; +    if (IsCustomConfig()) { +        if (player.profile_name.empty()) { +            // No custom profile selected +            return; +        } +        WriteSetting(QStringLiteral("%1profile_name").arg(player_prefix), +                     QString::fromStdString(player.profile_name), QString{}); +    }      WriteSetting(QStringLiteral("%1type").arg(player_prefix),                   static_cast<u8>(player.controller_type),                   static_cast<u8>(Settings::ControllerType::ProController)); -    if (!player_prefix.isEmpty()) { +    if (!player_prefix.isEmpty() || !Settings::IsConfiguringGlobal()) {          WriteSetting(QStringLiteral("%1connected").arg(player_prefix), player.connected,                       player_index == 0);          WriteSetting(QStringLiteral("%1vibration_enabled").arg(player_prefix), @@ -1056,7 +1085,6 @@ void Config::SaveIrCameraValues() {  void Config::SaveValues() {      if (global) { -        SaveControlValues();          SaveDataStorageValues();          SaveDebuggingValues();          SaveDisabledAddOnValues(); @@ -1065,6 +1093,7 @@ void Config::SaveValues() {          SaveWebServiceValues();          SaveMiscellaneousValues();      } +    SaveControlValues();      SaveCoreValues();      SaveCpuValues();      SaveRendererValues(); @@ -1089,9 +1118,14 @@ void Config::SaveAudioValues() {  void Config::SaveControlValues() {      qt_config->beginGroup(QStringLiteral("Controls")); +    Settings::values.players.SetGlobal(!IsCustomConfig());      for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {          SavePlayerValue(p);      } +    if (IsCustomConfig()) { +        qt_config->endGroup(); +        return; +    }      SaveDebugValues();      SaveMouseValues();      SaveTouchscreenValues(); @@ -1581,6 +1615,13 @@ void Config::SaveControlPlayerValue(std::size_t player_index) {      qt_config->endGroup();  } +void Config::ClearControlPlayerValues() { +    qt_config->beginGroup(QStringLiteral("Controls")); +    // If key is an empty string, all keys in the current group() are removed. +    qt_config->remove(QString{}); +    qt_config->endGroup(); +} +  const std::string& Config::GetConfigFilePath() const {      return qt_config_loc;  } diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index 06fa7d2d0..7d26e9ab6 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h @@ -34,6 +34,7 @@ public:      void ReadControlPlayerValue(std::size_t player_index);      void SaveControlPlayerValue(std::size_t player_index); +    void ClearControlPlayerValues();      const std::string& GetConfigFilePath() const; @@ -58,6 +59,7 @@ public:  private:      void Initialize(const std::string& config_name); +    bool IsCustomConfig();      void ReadValues();      void ReadPlayerValue(std::size_t player_index); diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index f1385e972..e9388daad 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -31,7 +31,7 @@ ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* paren      ui->backend->addItem(QStringLiteral("GLSL"));      ui->backend->addItem(tr("GLASM (Assembly Shaders, NVIDIA Only)")); -    ui->backend->addItem(QStringLiteral("SPIR-V (Experimental, Mesa Only)")); +    ui->backend->addItem(tr("SPIR-V (Experimental, Mesa Only)"));      SetupPerGameUI(); @@ -260,6 +260,7 @@ void ConfigureGraphics::ApplyConfiguration() {              Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend());              switch (GetCurrentGraphicsBackend()) {              case Settings::RendererBackend::OpenGL: +            case Settings::RendererBackend::Null:                  Settings::values.shader_backend.SetGlobal(false);                  Settings::values.vulkan_device.SetGlobal(true);                  Settings::values.shader_backend.SetValue(shader_backend); @@ -348,6 +349,10 @@ void ConfigureGraphics::UpdateAPILayout() {          ui->device_widget->setVisible(true);          ui->backend_widget->setVisible(false);          break; +    case Settings::RendererBackend::Null: +        ui->device_widget->setVisible(false); +        ui->backend_widget->setVisible(false); +        break;      }  } @@ -360,7 +365,7 @@ void ConfigureGraphics::RetrieveVulkanDevices() try {      vk::InstanceDispatch dld;      const Common::DynamicLibrary library = OpenLibrary(); -    const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_0); +    const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_1);      const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();      vulkan_devices.clear(); diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index 37271f956..f78396690 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui @@ -139,6 +139,11 @@                    <string notr="true">Vulkan</string>                   </property>                  </item> +                <item> +                 <property name="text"> +                  <string>None</string> +                 </property> +                </item>                 </widget>                </item>               </layout> diff --git a/src/yuzu/configuration/configure_input_per_game.cpp b/src/yuzu/configuration/configure_input_per_game.cpp new file mode 100644 index 000000000..78e65d468 --- /dev/null +++ b/src/yuzu/configuration/configure_input_per_game.cpp @@ -0,0 +1,115 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/settings.h" +#include "core/core.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" +#include "ui_configure_input_per_game.h" +#include "yuzu/configuration/config.h" +#include "yuzu/configuration/configure_input_per_game.h" +#include "yuzu/configuration/input_profiles.h" + +ConfigureInputPerGame::ConfigureInputPerGame(Core::System& system_, Config* config_, +                                             QWidget* parent) +    : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputPerGame>()), +      profiles(std::make_unique<InputProfiles>()), system{system_}, config{config_} { +    ui->setupUi(this); +    const std::array labels = { +        ui->label_player_1, ui->label_player_2, ui->label_player_3, ui->label_player_4, +        ui->label_player_5, ui->label_player_6, ui->label_player_7, ui->label_player_8, +    }; +    profile_comboboxes = { +        ui->profile_player_1, ui->profile_player_2, ui->profile_player_3, ui->profile_player_4, +        ui->profile_player_5, ui->profile_player_6, ui->profile_player_7, ui->profile_player_8, +    }; + +    Settings::values.players.SetGlobal(false); + +    const auto& profile_names = profiles->GetInputProfileNames(); +    const auto populate_profiles = [this, &profile_names](size_t player_index) { +        const auto previous_profile = +            Settings::values.players.GetValue()[player_index].profile_name; + +        auto* const player_combobox = profile_comboboxes[player_index]; +        player_combobox->addItem(tr("Use global input configuration")); + +        for (size_t index = 0; index < profile_names.size(); ++index) { +            const auto& profile_name = profile_names[index]; +            player_combobox->addItem(QString::fromStdString(profile_name)); +            if (profile_name == previous_profile) { +                // offset by 1 since the first element is the global config +                player_combobox->setCurrentIndex(static_cast<int>(index + 1)); +            } +        } +    }; +    for (size_t index = 0; index < profile_comboboxes.size(); ++index) { +        labels[index]->setText(tr("Player %1 profile").arg(index + 1)); +        populate_profiles(index); +    } + +    LoadConfiguration(); +} + +void ConfigureInputPerGame::ApplyConfiguration() { +    LoadConfiguration(); +    SaveConfiguration(); +} + +void ConfigureInputPerGame::LoadConfiguration() { +    static constexpr size_t HANDHELD_INDEX = 8; + +    auto& hid_core = system.HIDCore(); +    for (size_t player_index = 0; player_index < profile_comboboxes.size(); ++player_index) { +        Settings::values.players.SetGlobal(false); + +        auto* emulated_controller = hid_core.GetEmulatedControllerByIndex(player_index); +        auto* const player_combobox = profile_comboboxes[player_index]; + +        const auto selection_index = player_combobox->currentIndex(); +        if (selection_index == 0) { +            Settings::values.players.GetValue()[player_index].profile_name = ""; +            if (player_index == 0) { +                Settings::values.players.GetValue()[HANDHELD_INDEX] = {}; +            } +            Settings::values.players.SetGlobal(true); +            emulated_controller->ReloadFromSettings(); +            continue; +        } +        const auto profile_name = player_combobox->itemText(selection_index).toStdString(); +        if (profile_name.empty()) { +            continue; +        } +        auto& player = Settings::values.players.GetValue()[player_index]; +        player.profile_name = profile_name; +        // Read from the profile into the custom player settings +        profiles->LoadProfile(profile_name, player_index); +        // Make sure the controller is connected +        player.connected = true; + +        emulated_controller->ReloadFromSettings(); + +        if (player_index > 0) { +            continue; +        } +        // Handle Handheld cases +        auto& handheld_player = Settings::values.players.GetValue()[HANDHELD_INDEX]; +        auto* handheld_controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); +        if (player.controller_type == Settings::ControllerType::Handheld) { +            handheld_player = player; +        } else { +            handheld_player = {}; +        } +        handheld_controller->ReloadFromSettings(); +    } +} + +void ConfigureInputPerGame::SaveConfiguration() { +    Settings::values.players.SetGlobal(false); + +    // Clear all controls from the config in case the user reverted back to globals +    config->ClearControlPlayerValues(); +    for (size_t index = 0; index < Settings::values.players.GetValue().size(); ++index) { +        config->SaveControlPlayerValue(index); +    } +} diff --git a/src/yuzu/configuration/configure_input_per_game.h b/src/yuzu/configuration/configure_input_per_game.h new file mode 100644 index 000000000..660faf574 --- /dev/null +++ b/src/yuzu/configuration/configure_input_per_game.h @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <memory> + +#include <QWidget> + +#include "ui_configure_input_per_game.h" +#include "yuzu/configuration/input_profiles.h" + +class QComboBox; + +namespace Core { +class System; +} // namespace Core + +class Config; + +class ConfigureInputPerGame : public QWidget { +    Q_OBJECT + +public: +    explicit ConfigureInputPerGame(Core::System& system_, Config* config_, +                                   QWidget* parent = nullptr); + +    /// Load and Save configurations to settings file. +    void ApplyConfiguration(); + +private: +    /// Load configuration from settings file. +    void LoadConfiguration(); + +    /// Save configuration to settings file. +    void SaveConfiguration(); + +    std::unique_ptr<Ui::ConfigureInputPerGame> ui; +    std::unique_ptr<InputProfiles> profiles; + +    std::array<QComboBox*, 8> profile_comboboxes; + +    Core::System& system; +    Config* config; +}; diff --git a/src/yuzu/configuration/configure_input_per_game.ui b/src/yuzu/configuration/configure_input_per_game.ui new file mode 100644 index 000000000..fbd8eab1c --- /dev/null +++ b/src/yuzu/configuration/configure_input_per_game.ui @@ -0,0 +1,333 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ConfigureInputPerGame</class> + <widget class="QWidget" name="PerGameInput"> +  <property name="geometry"> +   <rect> +    <x>0</x> +    <y>0</y> +    <width>541</width> +    <height>759</height> +   </rect> +  </property> +  <property name="windowTitle"> +   <string>Form</string> +  </property> +  <property name="accessibleName"> +   <string>Graphics</string> +  </property> +  <layout class="QVBoxLayout" name="verticalLayout_1"> +   <item> +    <layout class="QVBoxLayout" name="verticalLayout_2"> +     <property name="spacing"> +      <number>0</number> +     </property> +     <item> +      <widget class="QGroupBox" name="groupBox"> +       <property name="title"> +        <string>Input Profiles</string> +       </property> +       <layout class="QVBoxLayout" name="verticalLayout_4"> +        <item> +         <widget class="QWidget" name="player_1" native="true"> +          <layout class="QHBoxLayout" name="input_profile_layout_1"> +           <property name="leftMargin"> +            <number>0</number> +           </property> +           <property name="topMargin"> +            <number>0</number> +           </property> +           <property name="rightMargin"> +            <number>0</number> +           </property> +           <property name="bottomMargin"> +            <number>0</number> +           </property> +           <item> +            <widget class="QLabel" name="label_player_1"> +             <property name="text"> +              <string>Player 1 Profile</string> +             </property> +            </widget> +           </item> +           <item> +            <widget class="QComboBox" name="profile_player_1"> +             <property name="sizePolicy"> +              <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> +               <horstretch>0</horstretch> +               <verstretch>0</verstretch> +              </sizepolicy> +             </property> +            </widget> +           </item> +          </layout> +         </widget> +        </item> +        <item> +         <widget class="QWidget" name="player_2" native="true"> +          <layout class="QHBoxLayout" name="input_profile_layout_2"> +           <property name="leftMargin"> +            <number>0</number> +           </property> +           <property name="topMargin"> +            <number>0</number> +           </property> +           <property name="rightMargin"> +            <number>0</number> +           </property> +           <property name="bottomMargin"> +            <number>0</number> +           </property> +           <item> +            <widget class="QLabel" name="label_player_2"> +             <property name="text"> +              <string>Player 2 Profile</string> +             </property> +            </widget> +           </item> +           <item> +            <widget class="QComboBox" name="profile_player_2"> +             <property name="sizePolicy"> +              <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> +               <horstretch>0</horstretch> +               <verstretch>0</verstretch> +              </sizepolicy> +             </property> +            </widget> +           </item> +          </layout> +         </widget> +        </item> +        <item> +         <widget class="QWidget" name="player_3" native="true"> +          <layout class="QHBoxLayout" name="input_profile_layout_3"> +           <property name="leftMargin"> +            <number>0</number> +           </property> +           <property name="topMargin"> +            <number>0</number> +           </property> +           <property name="rightMargin"> +            <number>0</number> +           </property> +           <property name="bottomMargin"> +            <number>0</number> +           </property> +           <item> +            <widget class="QLabel" name="label_player_3"> +             <property name="text"> +              <string>Player 3 Profile</string> +             </property> +            </widget> +           </item> +           <item> +            <widget class="QComboBox" name="profile_player_3"> +             <property name="sizePolicy"> +              <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> +               <horstretch>0</horstretch> +               <verstretch>0</verstretch> +              </sizepolicy> +             </property> +            </widget> +           </item> +          </layout> +         </widget> +        </item> +        <item> +         <widget class="QWidget" name="player_4" native="true"> +          <layout class="QHBoxLayout" name="input_profile_layout_4"> +           <property name="leftMargin"> +            <number>0</number> +           </property> +           <property name="topMargin"> +            <number>0</number> +           </property> +           <property name="rightMargin"> +            <number>0</number> +           </property> +           <property name="bottomMargin"> +            <number>0</number> +           </property> +           <item> +            <widget class="QLabel" name="label_player_4"> +             <property name="text"> +              <string>Player 4 Profile</string> +             </property> +            </widget> +           </item> +           <item> +            <widget class="QComboBox" name="profile_player_4"> +             <property name="sizePolicy"> +              <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> +               <horstretch>0</horstretch> +               <verstretch>0</verstretch> +              </sizepolicy> +             </property> +            </widget> +           </item> +          </layout> +         </widget> +        </item> +        <item> +         <widget class="QWidget" name="player_5" native="true"> +          <layout class="QHBoxLayout" name="input_profile_layout_5"> +           <property name="leftMargin"> +            <number>0</number> +           </property> +           <property name="topMargin"> +            <number>0</number> +           </property> +           <property name="rightMargin"> +            <number>0</number> +           </property> +           <property name="bottomMargin"> +            <number>0</number> +           </property> +           <item> +            <widget class="QLabel" name="label_player_5"> +             <property name="text"> +              <string>Player 5 Profile</string> +             </property> +            </widget> +           </item> +           <item> +            <widget class="QComboBox" name="profile_player_5"> +             <property name="sizePolicy"> +              <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> +               <horstretch>0</horstretch> +               <verstretch>0</verstretch> +              </sizepolicy> +             </property> +            </widget> +           </item> +          </layout> +         </widget> +        </item> +        <item> +         <widget class="QWidget" name="player_6" native="true"> +          <layout class="QHBoxLayout" name="input_profile_layout_6"> +           <property name="leftMargin"> +            <number>0</number> +           </property> +           <property name="topMargin"> +            <number>0</number> +           </property> +           <property name="rightMargin"> +            <number>0</number> +           </property> +           <property name="bottomMargin"> +            <number>0</number> +           </property> +           <item> +            <widget class="QLabel" name="label_player_6"> +             <property name="text"> +              <string>Player 6 Profile</string> +             </property> +            </widget> +           </item> +           <item> +            <widget class="QComboBox" name="profile_player_6"> +             <property name="sizePolicy"> +              <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> +               <horstretch>0</horstretch> +               <verstretch>0</verstretch> +              </sizepolicy> +             </property> +            </widget> +           </item> +          </layout> +         </widget> +        </item> +        <item> +         <widget class="QWidget" name="player_7" native="true"> +          <layout class="QHBoxLayout" name="input_profile_layout_7"> +           <property name="leftMargin"> +            <number>0</number> +           </property> +           <property name="topMargin"> +            <number>0</number> +           </property> +           <property name="rightMargin"> +            <number>0</number> +           </property> +           <property name="bottomMargin"> +            <number>0</number> +           </property> +           <item> +            <widget class="QLabel" name="label_player_7"> +             <property name="text"> +              <string>Player 7 Profile</string> +             </property> +            </widget> +           </item> +           <item> +            <widget class="QComboBox" name="profile_player_7"> +             <property name="sizePolicy"> +              <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> +               <horstretch>0</horstretch> +               <verstretch>0</verstretch> +              </sizepolicy> +             </property> +            </widget> +           </item> +          </layout> +         </widget> +        </item> +        <item> +         <widget class="QWidget" name="player_8" native="true"> +          <layout class="QHBoxLayout" name="input_profile_layout_8"> +           <property name="leftMargin"> +            <number>0</number> +           </property> +           <property name="topMargin"> +            <number>0</number> +           </property> +           <property name="rightMargin"> +            <number>0</number> +           </property> +           <property name="bottomMargin"> +            <number>0</number> +           </property> +           <item> +            <widget class="QLabel" name="label_player_8"> +             <property name="text"> +              <string>Player 8 Profile</string> +             </property> +            </widget> +           </item> +           <item> +            <widget class="QComboBox" name="profile_player_8"> +             <property name="sizePolicy"> +              <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> +               <horstretch>0</horstretch> +               <verstretch>0</verstretch> +              </sizepolicy> +             </property> +            </widget> +           </item> +          </layout> +         </widget> +        </item> +       </layout> +      </widget> +     </item> +    </layout> +   </item> +   <item> +    <spacer name="verticalSpacer"> +     <property name="orientation"> +      <enum>Qt::Vertical</enum> +     </property> +     <property name="sizeHint" stdset="0"> +      <size> +       <width>20</width> +       <height>40</height> +      </size> +     </property> +    </spacer> +   </item> +  </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 9e5a40fe7..b1575b0d3 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -855,8 +855,7 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() {          return;      } -    const auto devices = -        emulated_controller->GetMappedDevices(Core::HID::EmulatedDeviceIndex::AllDevices); +    const auto devices = emulated_controller->GetMappedDevices();      UpdateInputDevices();      if (devices.empty()) { @@ -1553,6 +1552,7 @@ void ConfigureInputPlayer::LoadProfile() {  }  void ConfigureInputPlayer::SaveProfile() { +    static constexpr size_t HANDHELD_INDEX = 8;      const QString profile_name = ui->comboProfiles->itemText(ui->comboProfiles->currentIndex());      if (profile_name.isEmpty()) { @@ -1561,7 +1561,12 @@ void ConfigureInputPlayer::SaveProfile() {      ApplyConfiguration(); -    if (!profiles->SaveProfile(profile_name.toStdString(), player_index)) { +    // When we're in handheld mode, only the handheld emulated controller bindings are updated +    const bool is_handheld = player_index == 0 && emulated_controller->GetNpadIdType() == +                                                      Core::HID::NpadIdType::Handheld; +    const auto profile_player_index = is_handheld ? HANDHELD_INDEX : player_index; + +    if (!profiles->SaveProfile(profile_name.toStdString(), profile_player_index)) {          QMessageBox::critical(this, tr("Save Input Profile"),                                tr("Failed to save the input profile \"%1\"").arg(profile_name));          UpdateInputProfiles(); diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index 79434fdd8..26f60d121 100644 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h @@ -38,7 +38,7 @@ enum class InputType;  namespace Ui {  class ConfigureInputPlayer; -} +} // namespace Ui  namespace Core::HID {  class HIDCore; diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index c3cb8f61d..93db47cfd 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -28,7 +28,7 @@  #include "yuzu/configuration/configure_general.h"  #include "yuzu/configuration/configure_graphics.h"  #include "yuzu/configuration/configure_graphics_advanced.h" -#include "yuzu/configuration/configure_input.h" +#include "yuzu/configuration/configure_input_per_game.h"  #include "yuzu/configuration/configure_per_game.h"  #include "yuzu/configuration/configure_per_game_addons.h"  #include "yuzu/configuration/configure_system.h" @@ -50,6 +50,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st      general_tab = std::make_unique<ConfigureGeneral>(system_, this);      graphics_tab = std::make_unique<ConfigureGraphics>(system_, this);      graphics_advanced_tab = std::make_unique<ConfigureGraphicsAdvanced>(system_, this); +    input_tab = std::make_unique<ConfigureInputPerGame>(system_, game_config.get(), this);      system_tab = std::make_unique<ConfigureSystem>(system_, this);      ui->setupUi(this); @@ -61,6 +62,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st      ui->tabWidget->addTab(graphics_tab.get(), tr("Graphics"));      ui->tabWidget->addTab(graphics_advanced_tab.get(), tr("Adv. Graphics"));      ui->tabWidget->addTab(audio_tab.get(), tr("Audio")); +    ui->tabWidget->addTab(input_tab.get(), tr("Input Profiles"));      setFocusPolicy(Qt::ClickFocus);      setWindowTitle(tr("Properties")); @@ -91,6 +93,7 @@ void ConfigurePerGame::ApplyConfiguration() {      graphics_tab->ApplyConfiguration();      graphics_advanced_tab->ApplyConfiguration();      audio_tab->ApplyConfiguration(); +    input_tab->ApplyConfiguration();      system.ApplySettings();      Settings::LogSettings(); diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h index 17a98a0f3..4ecc43541 100644 --- a/src/yuzu/configuration/configure_per_game.h +++ b/src/yuzu/configuration/configure_per_game.h @@ -16,12 +16,17 @@ namespace Core {  class System;  } +namespace InputCommon { +class InputSubsystem; +} +  class ConfigurePerGameAddons;  class ConfigureAudio;  class ConfigureCpu;  class ConfigureGeneral;  class ConfigureGraphics;  class ConfigureGraphicsAdvanced; +class ConfigureInputPerGame;  class ConfigureSystem;  class QGraphicsScene; @@ -72,5 +77,6 @@ private:      std::unique_ptr<ConfigureGeneral> general_tab;      std::unique_ptr<ConfigureGraphics> graphics_tab;      std::unique_ptr<ConfigureGraphicsAdvanced> graphics_advanced_tab; +    std::unique_ptr<ConfigureInputPerGame> input_tab;      std::unique_ptr<ConfigureSystem> system_tab;  }; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index c21153560..c0afb2e5f 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -126,6 +126,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual  #include "yuzu/compatibility_list.h"  #include "yuzu/configuration/config.h"  #include "yuzu/configuration/configure_dialog.h" +#include "yuzu/configuration/configure_input_per_game.h"  #include "yuzu/debugger/console.h"  #include "yuzu/debugger/controller.h"  #include "yuzu/debugger/profiler.h" @@ -1012,29 +1013,11 @@ void GMainWindow::InitializeWidgets() {      renderer_status_button->setObjectName(QStringLiteral("RendererStatusBarButton"));      renderer_status_button->setCheckable(true);      renderer_status_button->setFocusPolicy(Qt::NoFocus); -    connect(renderer_status_button, &QPushButton::toggled, [this](bool checked) { -        renderer_status_button->setText(checked ? tr("VULKAN") : tr("OPENGL")); -    }); -    renderer_status_button->toggle(); - +    connect(renderer_status_button, &QPushButton::clicked, this, &GMainWindow::OnToggleGraphicsAPI); +    UpdateAPIText(); +    renderer_status_button->setCheckable(true);      renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() ==                                         Settings::RendererBackend::Vulkan); -    connect(renderer_status_button, &QPushButton::clicked, [this] { -        if (emulation_running) { -            return; -        } -        if (renderer_status_button->isChecked()) { -            Settings::values.renderer_backend.SetValue(Settings::RendererBackend::Vulkan); -        } else { -            Settings::values.renderer_backend.SetValue(Settings::RendererBackend::OpenGL); -            if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) { -                Settings::values.scaling_filter.SetValue(Settings::ScalingFilter::NearestNeighbor); -                UpdateFilterText(); -            } -        } - -        system->ApplySettings(); -    });      statusBar()->insertPermanentWidget(0, renderer_status_button);      statusBar()->setVisible(true); @@ -1676,6 +1659,11 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t      LOG_INFO(Frontend, "yuzu starting...");      StoreRecentFile(filename); // Put the filename on top of the list +    // Save configurations +    UpdateUISettings(); +    game_list->SaveInterfaceLayout(); +    config->Save(); +      u64 title_id{0};      last_filename_booted = filename; @@ -1692,14 +1680,10 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t                                            ? Common::FS::PathToUTF8String(file_path.filename())                                            : fmt::format("{:016X}", title_id);          Config per_game_config(config_file_name, Config::ConfigType::PerGameConfig); +        system->HIDCore().ReloadInputDevices();          system->ApplySettings();      } -    // Save configurations -    UpdateUISettings(); -    game_list->SaveInterfaceLayout(); -    config->Save(); -      Settings::LogSettings();      if (UISettings::values.select_user_on_boot) { @@ -2820,6 +2804,7 @@ void GMainWindow::OnStopGame() {      ShutdownGame();      Settings::RestoreGlobalState(system->IsPoweredOn()); +    system->HIDCore().ReloadInputDevices();      UpdateStatusButtons();  } @@ -2850,6 +2835,7 @@ void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_tex  }  void GMainWindow::OnMenuReportCompatibility() { +#if defined(ARCHITECTURE_x86_64) && !defined(__APPLE__)      const auto& caps = Common::GetCPUCaps();      const bool has_fma = caps.fma || caps.fma4;      const auto processor_count = std::thread::hardware_concurrency(); @@ -2876,6 +2862,11 @@ void GMainWindow::OnMenuReportCompatibility() {                 "> "                 "Web."));      } +#else +    QMessageBox::critical(this, tr("Hardware requirements not met"), +                          tr("Your system does not meet the recommended hardware requirements. " +                             "Compatibility reporting has been disabled.")); +#endif  }  void GMainWindow::OpenURL(const QUrl& url) { @@ -3253,6 +3244,18 @@ void GMainWindow::OnToggleAdaptingFilter() {      UpdateFilterText();  } +void GMainWindow::OnToggleGraphicsAPI() { +    auto api = Settings::values.renderer_backend.GetValue(); +    if (api == Settings::RendererBackend::OpenGL) { +        api = Settings::RendererBackend::Vulkan; +    } else { +        api = Settings::RendererBackend::OpenGL; +    } +    Settings::values.renderer_backend.SetValue(api); +    renderer_status_button->setChecked(api == Settings::RendererBackend::Vulkan); +    UpdateAPIText(); +} +  void GMainWindow::OnConfigurePerGame() {      const u64 title_id = system->GetCurrentProcessProgramID();      OpenPerGameConfiguration(title_id, current_game_path.toStdString()); @@ -3281,6 +3284,7 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file      // Do not cause the global config to write local settings into the config file      const bool is_powered_on = system->IsPoweredOn();      Settings::RestoreGlobalState(is_powered_on); +    system->HIDCore().ReloadInputDevices();      UISettings::values.configuration_applied = false; @@ -3573,6 +3577,21 @@ void GMainWindow::UpdateDockedButton() {      dock_status_button->setText(is_docked ? tr("DOCKED") : tr("HANDHELD"));  } +void GMainWindow::UpdateAPIText() { +    const auto api = Settings::values.renderer_backend.GetValue(); +    switch (api) { +    case Settings::RendererBackend::OpenGL: +        renderer_status_button->setText(tr("OPENGL")); +        break; +    case Settings::RendererBackend::Vulkan: +        renderer_status_button->setText(tr("VULKAN")); +        break; +    case Settings::RendererBackend::Null: +        renderer_status_button->setText(tr("NULL")); +        break; +    } +} +  void GMainWindow::UpdateFilterText() {      const auto filter = Settings::values.scaling_filter.GetValue();      switch (filter) { @@ -3618,6 +3637,7 @@ void GMainWindow::UpdateAAText() {  void GMainWindow::UpdateStatusButtons() {      renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() ==                                         Settings::RendererBackend::Vulkan); +    UpdateAPIText();      UpdateGPUAccuracyButton();      UpdateDockedButton();      UpdateFilterText(); @@ -3748,6 +3768,7 @@ void GMainWindow::OnCoreError(Core::SystemResultStatus result, std::string detai              ShutdownGame();              Settings::RestoreGlobalState(system->IsPoweredOn()); +            system->HIDCore().ReloadInputDevices();              UpdateStatusButtons();          }      } else { @@ -3899,18 +3920,19 @@ void GMainWindow::closeEvent(QCloseEvent* event) {      // Unload controllers early      controller_dialog->UnloadController();      game_list->UnloadController(); -    system->HIDCore().UnloadInputDevices();      // Shutdown session if the emu thread is active...      if (emu_thread != nullptr) {          ShutdownGame();          Settings::RestoreGlobalState(system->IsPoweredOn()); +        system->HIDCore().ReloadInputDevices();          UpdateStatusButtons();      }      render_window->close();      multiplayer_state->Close(); +    system->HIDCore().UnloadInputDevices();      system->GetRoomNetwork().Shutdown();      QWidget::closeEvent(event); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 4f9c3b450..62d629973 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -307,6 +307,7 @@ private slots:      void OnTasStartStop();      void OnTasRecord();      void OnTasReset(); +    void OnToggleGraphicsAPI();      void OnToggleDockedMode();      void OnToggleGpuAccuracy();      void OnToggleAdaptingFilter(); @@ -347,6 +348,7 @@ private:      void UpdateWindowTitle(std::string_view title_name = {}, std::string_view title_version = {},                             std::string_view gpu_vendor = {});      void UpdateDockedButton(); +    void UpdateAPIText();      void UpdateFilterText();      void UpdateAAText();      void UpdateStatusBar(); diff --git a/src/yuzu/multiplayer/chat_room.h b/src/yuzu/multiplayer/chat_room.h index 01c70fad0..dd71ea4cd 100644 --- a/src/yuzu/multiplayer/chat_room.h +++ b/src/yuzu/multiplayer/chat_room.h @@ -4,6 +4,7 @@  #pragma once  #include <memory> +#include <unordered_map>  #include <unordered_set>  #include <QDialog>  #include <QSortFilterProxyModel> diff --git a/src/yuzu/precompiled_headers.h b/src/yuzu/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/yuzu/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/yuzu/startup_checks.cpp b/src/yuzu/startup_checks.cpp index ccdcf10fa..563818362 100644 --- a/src/yuzu/startup_checks.cpp +++ b/src/yuzu/startup_checks.cpp @@ -27,7 +27,7 @@ void CheckVulkan() {          Vulkan::vk::InstanceDispatch dld;          const Common::DynamicLibrary library = Vulkan::OpenLibrary();          const Vulkan::vk::Instance instance = -            Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_0); +            Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_1);      } catch (const Vulkan::vk::Exception& exception) {          fmt::print(stderr, "Failed to initialize Vulkan: {}\n", exception.what()); diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index 7d8ca3d8a..f6eeb9d8d 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -22,8 +22,11 @@ add_executable(yuzu-cmd      emu_window/emu_window_sdl2.h      emu_window/emu_window_sdl2_gl.cpp      emu_window/emu_window_sdl2_gl.h +    emu_window/emu_window_sdl2_null.cpp +    emu_window/emu_window_sdl2_null.h      emu_window/emu_window_sdl2_vk.cpp      emu_window/emu_window_sdl2_vk.h +    precompiled_headers.h      yuzu.cpp      yuzu.rc  ) @@ -31,21 +34,16 @@ add_executable(yuzu-cmd  create_target_directory_groups(yuzu-cmd)  target_link_libraries(yuzu-cmd PRIVATE common core input_common) -target_link_libraries(yuzu-cmd PRIVATE inih glad) +target_link_libraries(yuzu-cmd PRIVATE inih::INIReader glad)  if (MSVC)      target_link_libraries(yuzu-cmd PRIVATE getopt)  endif() -target_link_libraries(yuzu-cmd PRIVATE ${PLATFORM_LIBRARIES} SDL2 Threads::Threads) +target_link_libraries(yuzu-cmd PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)  create_resource("../../dist/yuzu.bmp" "yuzu_cmd/yuzu_icon.h" "yuzu_icon")  target_include_directories(yuzu-cmd PRIVATE ${RESOURCES_DIR}) -target_include_directories(yuzu-cmd PRIVATE ../../externals/Vulkan-Headers/include) - -if (YUZU_USE_EXTERNAL_SDL2) -    target_compile_definitions(yuzu-cmd PRIVATE -DYUZU_USE_EXTERNAL_SDL2) -    target_include_directories(yuzu-cmd PRIVATE ${PROJECT_BINARY_DIR}/externals/SDL/include) -endif() +target_link_libraries(yuzu-cmd PRIVATE SDL2::SDL2 Vulkan::Headers)  if(UNIX AND NOT APPLE)      install(TARGETS yuzu-cmd) @@ -55,3 +53,7 @@ if (MSVC)      include(CopyYuzuSDLDeps)      copy_yuzu_SDL_deps(yuzu-cmd)  endif() + +if (YUZU_USE_PRECOMPILED_HEADERS) +    target_precompile_headers(yuzu-cmd PRIVATE precompiled_headers.h) +endif() diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index 767b0d0e3..de9b220da 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -15,7 +15,7 @@  #pragma clang diagnostic pop  #endif -#include <inih/cpp/INIReader.h> +#include <INIReader.h>  #include "common/fs/file.h"  #include "common/fs/fs.h"  #include "common/fs/path_util.h" diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h index 90bb0b415..25c23e2a5 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h @@ -89,3 +89,5 @@ protected:      /// yuzu core instance      Core::System& system;  }; + +class DummyContext : public Core::Frontend::GraphicsContext {}; diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_null.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_null.cpp new file mode 100644 index 000000000..259192f3c --- /dev/null +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_null.cpp @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <cstdlib> +#include <memory> +#include <string> + +#include <fmt/format.h> + +#include "common/logging/log.h" +#include "common/scm_rev.h" +#include "video_core/renderer_null/renderer_null.h" +#include "yuzu_cmd/emu_window/emu_window_sdl2_null.h" + +#ifdef YUZU_USE_EXTERNAL_SDL2 +// Include this before SDL.h to prevent the external from including a dummy +#define USING_GENERATED_CONFIG_H +#include <SDL_config.h> +#endif + +#include <SDL.h> + +EmuWindow_SDL2_Null::EmuWindow_SDL2_Null(InputCommon::InputSubsystem* input_subsystem_, +                                         Core::System& system_, bool fullscreen) +    : EmuWindow_SDL2{input_subsystem_, system_} { +    const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name, +                                                 Common::g_scm_branch, Common::g_scm_desc); +    render_window = +        SDL_CreateWindow(window_title.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, +                         Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height, +                         SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); + +    SetWindowIcon(); + +    if (fullscreen) { +        Fullscreen(); +        ShowCursor(false); +    } + +    OnResize(); +    OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); +    SDL_PumpEvents(); +    LOG_INFO(Frontend, "yuzu Version: {} | {}-{} (Null)", Common::g_build_name, +             Common::g_scm_branch, Common::g_scm_desc); +} + +EmuWindow_SDL2_Null::~EmuWindow_SDL2_Null() = default; + +std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_Null::CreateSharedContext() const { +    return std::make_unique<DummyContext>(); +} diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_null.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_null.h new file mode 100644 index 000000000..35aee286d --- /dev/null +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_null.h @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <memory> + +#include "core/frontend/emu_window.h" +#include "yuzu_cmd/emu_window/emu_window_sdl2.h" + +namespace Core { +class System; +} + +namespace InputCommon { +class InputSubsystem; +} + +class EmuWindow_SDL2_Null final : public EmuWindow_SDL2 { +public: +    explicit EmuWindow_SDL2_Null(InputCommon::InputSubsystem* input_subsystem_, +                                 Core::System& system, bool fullscreen); +    ~EmuWindow_SDL2_Null() override; + +    std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; +}; diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp index 25948328c..9ed47d453 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp @@ -12,12 +12,6 @@  #include "video_core/renderer_vulkan/renderer_vulkan.h"  #include "yuzu_cmd/emu_window/emu_window_sdl2_vk.h" -#ifdef YUZU_USE_EXTERNAL_SDL2 -// Include this before SDL.h to prevent the external from including a dummy -#define USING_GENERATED_CONFIG_H -#include <SDL_config.h> -#endif -  #include <SDL.h>  #include <SDL_syswm.h> @@ -51,11 +45,6 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste          window_info.type = Core::Frontend::WindowSystemType::Windows;          window_info.render_surface = reinterpret_cast<void*>(wm.info.win.window);          break; -#else -    case SDL_SYSWM_TYPE::SDL_SYSWM_WINDOWS: -        LOG_CRITICAL(Frontend, "Window manager subsystem Windows not compiled"); -        std::exit(EXIT_FAILURE); -        break;  #endif  #ifdef SDL_VIDEO_DRIVER_X11      case SDL_SYSWM_TYPE::SDL_SYSWM_X11: @@ -63,11 +52,6 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste          window_info.display_connection = wm.info.x11.display;          window_info.render_surface = reinterpret_cast<void*>(wm.info.x11.window);          break; -#else -    case SDL_SYSWM_TYPE::SDL_SYSWM_X11: -        LOG_CRITICAL(Frontend, "Window manager subsystem X11 not compiled"); -        std::exit(EXIT_FAILURE); -        break;  #endif  #ifdef SDL_VIDEO_DRIVER_WAYLAND      case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND: @@ -75,14 +59,21 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste          window_info.display_connection = wm.info.wl.display;          window_info.render_surface = wm.info.wl.surface;          break; -#else -    case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND: -        LOG_CRITICAL(Frontend, "Window manager subsystem Wayland not compiled"); -        std::exit(EXIT_FAILURE); +#endif +#ifdef SDL_VIDEO_DRIVER_COCOA +    case SDL_SYSWM_TYPE::SDL_SYSWM_COCOA: +        window_info.type = Core::Frontend::WindowSystemType::Cocoa; +        window_info.render_surface = SDL_Metal_CreateView(render_window); +        break; +#endif +#ifdef SDL_VIDEO_DRIVER_ANDROID +    case SDL_SYSWM_TYPE::SDL_SYSWM_ANDROID: +        window_info.type = Core::Frontend::WindowSystemType::Android; +        window_info.render_surface = reinterpret_cast<void*>(wm.info.android.window);          break;  #endif      default: -        LOG_CRITICAL(Frontend, "Window manager subsystem not implemented"); +        LOG_CRITICAL(Frontend, "Window manager subsystem {} not implemented", wm.subsystem);          std::exit(EXIT_FAILURE);          break;      } diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h index e39ad754d..9467d164a 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h @@ -24,5 +24,3 @@ public:      std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;  }; - -class DummyContext : public Core::Frontend::GraphicsContext {}; diff --git a/src/yuzu_cmd/precompiled_headers.h b/src/yuzu_cmd/precompiled_headers.h new file mode 100644 index 000000000..aabae730b --- /dev/null +++ b/src/yuzu_cmd/precompiled_headers.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_precompiled_headers.h" diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index dfe5a30ea..a80649703 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -34,6 +34,7 @@  #include "yuzu_cmd/config.h"  #include "yuzu_cmd/emu_window/emu_window_sdl2.h"  #include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h" +#include "yuzu_cmd/emu_window/emu_window_sdl2_null.h"  #include "yuzu_cmd/emu_window/emu_window_sdl2_vk.h"  #ifdef _WIN32 @@ -317,6 +318,9 @@ int main(int argc, char** argv) {      case Settings::RendererBackend::Vulkan:          emu_window = std::make_unique<EmuWindow_SDL2_VK>(&input_subsystem, system, fullscreen);          break; +    case Settings::RendererBackend::Null: +        emu_window = std::make_unique<EmuWindow_SDL2_Null>(&input_subsystem, system, fullscreen); +        break;      }      system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>()); | 
