Compare commits
80 Commits
Author | SHA1 | Date | |
---|---|---|---|
c66df41896 | |||
2d27a19a45 | |||
be90677180 | |||
6089988914 | |||
91ea6931dd | |||
74de70bf21 | |||
1880a4bdf4 | |||
371beafc10 | |||
734077642e | |||
a2ca75bff4 | |||
09997b31af | |||
9200731b56 | |||
dade6e6797 | |||
c5f08a1408 | |||
67c20e04b4 | |||
609e32e317 | |||
2397c82b85 | |||
1ded25f68b | |||
39ca721cac | |||
2d4f762db1 | |||
810df95b81 | |||
ff9b0dfe2f | |||
d51c720392 | |||
2d8aded953 | |||
8feafd2ac5 | |||
94696de2b2 | |||
371387b44f | |||
d8d14491dd | |||
6b890987c4 | |||
5338e2e3a3 | |||
6b8931c899 | |||
5cad914b73 | |||
d865780291 | |||
60f0269569 | |||
ceadee0358 | |||
a9b96789d7 | |||
79379f21a4 | |||
0e98fb3780 | |||
d373d74804 | |||
a9436e01ca | |||
e7a6af73c1 | |||
9850c23a03 | |||
55e5c4edc9 | |||
f990a842da | |||
b5e4ec35e3 | |||
b1b61683f2 | |||
bbb4f1b040 | |||
5f942fb4c9 | |||
7c72060662 | |||
5b918cb535 | |||
61932f9a6c | |||
8a2cc15cd1 | |||
18cc68c687 | |||
69bde2b13b | |||
816a846cfb | |||
4dd4f2170d | |||
0eff9ad215 | |||
d4b88ac158 | |||
ed9000d0ec | |||
a657ef33e6 | |||
87db7a6888 | |||
ba6795b6cc | |||
a6fc19d7d9 | |||
06cecba63f | |||
0d0712f7d7 | |||
72340c5685 | |||
1f967b4770 | |||
5858bd3116 | |||
ab9b84f721 | |||
f6988d4a8e | |||
bc440ce6a3 | |||
b6099d5504 | |||
6b3767f1b7 | |||
4151fad10b | |||
2ec7f37d69 | |||
47e48617d5 | |||
98332af610 | |||
84f97fc77e | |||
c89434627a | |||
32bab7d1ba |
56
.gitmodules
vendored
56
.gitmodules
vendored
@ -1,57 +1,27 @@
|
||||
[submodule "boost"]
|
||||
path = externals/boost
|
||||
url = https://github.com/citra-emu/ext-boost.git
|
||||
[submodule "nihstro"]
|
||||
path = externals/nihstro
|
||||
url = https://github.com/neobrain/nihstro.git
|
||||
[submodule "soundtouch"]
|
||||
path = externals/soundtouch
|
||||
url = https://github.com/citra-emu/ext-soundtouch.git
|
||||
[submodule "catch"]
|
||||
path = externals/catch
|
||||
url = https://github.com/philsquared/Catch.git
|
||||
[submodule "dynarmic"]
|
||||
path = externals/dynarmic
|
||||
url = https://github.com/citra-emu/dynarmic.git
|
||||
[submodule "xbyak"]
|
||||
path = externals/xbyak
|
||||
url = https://github.com/herumi/xbyak.git
|
||||
[submodule "cryptopp"]
|
||||
path = externals/cryptopp/cryptopp
|
||||
url = https://github.com/weidai11/cryptopp.git
|
||||
[submodule "fmt"]
|
||||
path = externals/fmt
|
||||
url = https://github.com/fmtlib/fmt.git
|
||||
[submodule "enet"]
|
||||
path = externals/enet
|
||||
url = https://github.com/lsalzman/enet.git
|
||||
[submodule "inih"]
|
||||
path = externals/inih/inih
|
||||
url = https://github.com/benhoyt/inih.git
|
||||
[submodule "libressl"]
|
||||
path = externals/libressl
|
||||
url = https://github.com/citra-emu/ext-libressl-portable.git
|
||||
[submodule "libusb"]
|
||||
path = externals/libusb/libusb
|
||||
url = https://github.com/libusb/libusb.git
|
||||
url = https://github.com/merryhime/dynarmic.git
|
||||
[submodule "cubeb"]
|
||||
path = externals/cubeb
|
||||
url = https://github.com/kinetiknz/cubeb.git
|
||||
[submodule "discord-rpc"]
|
||||
path = externals/discord-rpc
|
||||
url = https://github.com/discord/discord-rpc.git
|
||||
[submodule "cpp-jwt"]
|
||||
path = externals/cpp-jwt
|
||||
url = https://github.com/arun11299/cpp-jwt.git
|
||||
[submodule "teakra"]
|
||||
path = externals/teakra
|
||||
url = https://github.com/wwylele/teakra.git
|
||||
[submodule "lodepng"]
|
||||
path = externals/lodepng/lodepng
|
||||
url = https://github.com/lvandeve/lodepng.git
|
||||
[submodule "zstd"]
|
||||
path = externals/zstd
|
||||
url = https://github.com/facebook/zstd.git
|
||||
[submodule "libyuv"]
|
||||
path = externals/libyuv
|
||||
url = https://github.com/lemenkov/libyuv.git
|
||||
[submodule "externals/vma"]
|
||||
path = externals/vma
|
||||
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
|
||||
[submodule "externals/Vulkan-Headers"]
|
||||
path = externals/Vulkan-Headers
|
||||
url = https://github.com/KhronosGroup/Vulkan-Headers
|
||||
[submodule "externals/vcpkg"]
|
||||
path = externals/vcpkg
|
||||
url = https://github.com/microsoft/vcpkg
|
||||
[submodule "externals/inih/inih"]
|
||||
path = externals/inih/inih
|
||||
url = https://github.com/benhoyt/inih
|
||||
|
203
CMakeLists.txt
203
CMakeLists.txt
@ -1,9 +1,12 @@
|
||||
# CMake 3.8 required for 17 to be a valid value for CXX_STANDARD
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
# CMake 3.12 required for 20 to be a valid value for CXX_STANDARD
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.15)
|
||||
# Don't override the warning flags in MSVC:
|
||||
cmake_policy(SET CMP0092 NEW)
|
||||
endif ()
|
||||
# Allow selecting MSVC runtime library using CMAKE_MSVC_RUNTIME_LIBRARY.
|
||||
cmake_policy(SET CMP0091 NEW)
|
||||
endif()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
|
||||
include(DownloadExternals)
|
||||
@ -14,7 +17,6 @@ project(citra LANGUAGES C CXX ASM)
|
||||
# Set bundled sdl2/qt as dependent options.
|
||||
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
|
||||
option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
|
||||
CMAKE_DEPENDENT_OPTION(CITRA_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF)
|
||||
|
||||
option(ENABLE_QT "Enable the Qt frontend" ON)
|
||||
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
|
||||
@ -31,16 +33,12 @@ if (ENABLE_FFMPEG_AUDIO_DECODER OR ENABLE_FFMPEG_VIDEO_DUMPER)
|
||||
set(ENABLE_FFMPEG ON)
|
||||
endif()
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(CITRA_USE_BUNDLED_FFMPEG "Download bundled FFmpeg binaries" ON "ENABLE_FFMPEG;MSVC" OFF)
|
||||
|
||||
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(ENABLE_MF "Use Media Foundation decoder (preferred over FFmpeg)" ON "WIN32" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(COMPILE_WITH_DWARF "Add DWARF debugging information" ON "MINGW" OFF)
|
||||
|
||||
option(USE_SYSTEM_BOOST "Use the system Boost libs (instead of the bundled ones)" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(ENABLE_FDK "Use FDK AAC decoder" OFF "NOT ENABLE_FFMPEG_AUDIO_DECODER;NOT ENABLE_MF" OFF)
|
||||
|
||||
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit)
|
||||
@ -49,6 +47,14 @@ if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit)
|
||||
DESTINATION ${PROJECT_SOURCE_DIR}/.git/hooks)
|
||||
endif()
|
||||
|
||||
# Use ccache for android if available
|
||||
# =======================================================================
|
||||
if (NOT $ENV{NDK_CCACHE} EQUAL "")
|
||||
set(CCACHE_EXE $ENV{NDK_CCACHE})
|
||||
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_EXE})
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_EXE})
|
||||
endif()
|
||||
|
||||
# Sanity check : Check that all submodules are present
|
||||
# =======================================================================
|
||||
|
||||
@ -126,47 +132,123 @@ message(STATUS "Target architecture: ${ARCHITECTURE}")
|
||||
# Configure C++ standard
|
||||
# ===========================
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# set up output paths for executable binaries
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin/$<CONFIG>)
|
||||
|
||||
|
||||
# System imported libraries
|
||||
# ======================
|
||||
|
||||
# Enable vcpkg features
|
||||
if (NOT DEFINED VCPKG_MANIFEST_FEATURES)
|
||||
if (ENABLE_SDL2)
|
||||
find_package(SDL2 CONFIG)
|
||||
|
||||
if (NOT SDL2_FOUND)
|
||||
message(STATUS "SDL2 not found. Using vcpkg")
|
||||
list(APPEND VCPKG_MANIFEST_FEATURES "citra-sdl2")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
list(APPEND VCPKG_MANIFEST_FEATURES "citra-web-service")
|
||||
endif()
|
||||
|
||||
if (USE_DISCORD_PRESENCE)
|
||||
list(APPEND VCPKG_MANIFEST_FEATURES "citra-discord")
|
||||
endif()
|
||||
|
||||
if (ENABLE_FFMPEG)
|
||||
find_package(FFmpeg COMPONENTS avcodec avformat avutil swscale swresample)
|
||||
|
||||
if (NOT FFMPEG_FOUND OR "${FFmpeg_avcodec_VERSION}" VERSION_LESS "57.48.101")
|
||||
message(STATUS "FFmpeg not found. Using vcpkg")
|
||||
list(APPEND VCPKG_MANIFEST_FEATURES "citra-ffmpeg")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (ENABLE_FDK)
|
||||
find_library(FDK_AAC fdk-aac DOC "The path to fdk_aac library")
|
||||
if(FDK_AAC STREQUAL "FDK_AAC-NOTFOUND")
|
||||
message(STATUS "FDK AAC not found. Using vcpkg")
|
||||
list(APPEND VCPKG_MANIFEST_FEATURES "citra-fdk-aac")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Cache the selected manifest features.
|
||||
set(VCPKG_MANIFEST_FEATURES ${VCPKG_MANIFEST_FEATURES} CACHE STRING "")
|
||||
endif()
|
||||
|
||||
# Prefer static linkage on windows and MinGW
|
||||
if (MINGW)
|
||||
set(VCPKG_TARGET_TRIPLET "x64-mingw-static")
|
||||
elseif (WIN32)
|
||||
# We could also build a dynamic CRT and not require this flag but vcpkg
|
||||
# developers actively discourage this. See:
|
||||
# https://github.com/microsoft/vcpkg/issues/15122#issuecomment-745497720
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
set(VCPKG_TARGET_TRIPLET "x64-windows-static")
|
||||
endif()
|
||||
|
||||
# Include vcpkg toolchain file
|
||||
include(${CMAKE_SOURCE_DIR}/externals/vcpkg/scripts/buildsystems/vcpkg.cmake)
|
||||
|
||||
# Prefer the -pthread flag on Linux.
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# Boost
|
||||
find_package(Boost REQUIRED COMPONENTS serialization)
|
||||
|
||||
# DiscordRPC
|
||||
if (USE_DISCORD_PRESENCE)
|
||||
find_package(discord-rpc CONFIG REQUIRED)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
# OpenSSL
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
||||
# JSON
|
||||
find_package(nlohmann_json CONFIG REQUIRED)
|
||||
|
||||
# httplib
|
||||
find_path(CPP_HTTPLIB_INCLUDE_DIRS "httplib.h")
|
||||
add_library(httplib INTERFACE)
|
||||
target_include_directories(httplib INTERFACE ${CPP_HTTPLIB_INCLUDE_DIRS})
|
||||
|
||||
# cpp-jwt
|
||||
find_package(cpp-jwt CONFIG REQUIRED)
|
||||
endif()
|
||||
|
||||
# (xperia64): Only use libyuv on Android b/c of build issues on Windows and mandatory JPEG
|
||||
if(ANDROID)
|
||||
# libyuv
|
||||
find_package(libyuv CONFIG REQUIRED)
|
||||
endif()
|
||||
|
||||
# Find the rest of our dependecies
|
||||
set(REQUIRED_PACKAGES
|
||||
Catch2
|
||||
cryptopp
|
||||
fmt
|
||||
glad
|
||||
glm
|
||||
zstd
|
||||
unofficial-enet
|
||||
lodepng
|
||||
glslang
|
||||
xbyak
|
||||
)
|
||||
|
||||
foreach(PACKAGE ${REQUIRED_PACKAGES})
|
||||
find_package(${PACKAGE} CONFIG REQUIRED)
|
||||
endforeach()
|
||||
|
||||
if (ENABLE_SDL2)
|
||||
if (CITRA_USE_BUNDLED_SDL2)
|
||||
# Detect toolchain and platform
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
|
||||
set(SDL2_VER "SDL2-2.0.16")
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable CITRA_USE_BUNDLED_SDL2 and provide your own.")
|
||||
endif()
|
||||
|
||||
if (DEFINED SDL2_VER)
|
||||
download_bundled_external("sdl2/" ${SDL2_VER} SDL2_PREFIX)
|
||||
endif()
|
||||
|
||||
set(SDL2_FOUND YES)
|
||||
set(SDL2_INCLUDE_DIR "${SDL2_PREFIX}/include" CACHE PATH "Path to SDL2 headers")
|
||||
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")
|
||||
else()
|
||||
find_package(SDL2 REQUIRED)
|
||||
endif()
|
||||
|
||||
if (SDL2_FOUND)
|
||||
# TODO(yuriks): Make FindSDL2.cmake export an IMPORTED library instead
|
||||
add_library(SDL2 INTERFACE)
|
||||
target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}")
|
||||
target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")
|
||||
endif()
|
||||
find_package(SDL2 CONFIG REQUIRED)
|
||||
else()
|
||||
set(SDL2_FOUND NO)
|
||||
endif()
|
||||
@ -174,7 +256,7 @@ endif()
|
||||
if (ENABLE_QT)
|
||||
if (CITRA_USE_BUNDLED_QT)
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
|
||||
set(QT_VER qt-5.10.0-msvc2017_64)
|
||||
set(QT_VER qt-5.12.12-msvc2017_64)
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable CITRA_USE_BUNDLED_QT and provide your own.")
|
||||
endif()
|
||||
@ -203,45 +285,24 @@ if(NOT APPLE)
|
||||
find_package(LibUSB)
|
||||
endif()
|
||||
if (NOT LIBUSB_FOUND)
|
||||
add_subdirectory(externals/libusb)
|
||||
set(LIBUSB_INCLUDE_DIR "")
|
||||
set(LIBUSB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/externals/libusb/libusb/libusb")
|
||||
set(LIBUSB_LIBRARIES usb)
|
||||
endif()
|
||||
|
||||
if (ENABLE_FFMPEG)
|
||||
if (CITRA_USE_BUNDLED_FFMPEG)
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
|
||||
set(FFmpeg_VER "ffmpeg-4.1-win64")
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled FFmpeg binaries for your toolchain. Disable CITRA_USE_BUNDLED_FFMPEG and provide your own.")
|
||||
endif()
|
||||
|
||||
if (DEFINED FFmpeg_VER)
|
||||
download_bundled_external("ffmpeg/" ${FFmpeg_VER} FFmpeg_PREFIX)
|
||||
set(FFMPEG_DIR "${FFmpeg_PREFIX}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (ENABLE_FFMPEG_VIDEO_DUMPER)
|
||||
find_package(FFmpeg REQUIRED COMPONENTS avcodec avformat avutil swscale swresample)
|
||||
if(ENABLE_FFMPEG_VIDEO_DUMPER)
|
||||
set(FFmpeg_COMPONENTS "avcodec avformat avutil swscale swresample")
|
||||
else()
|
||||
find_package(FFmpeg REQUIRED COMPONENTS avcodec)
|
||||
set(FFmpeg_COMPONENTS "avcodec")
|
||||
endif()
|
||||
if ("${FFmpeg_avcodec_VERSION}" VERSION_LESS "57.48.101")
|
||||
message(FATAL_ERROR "Found version for libavcodec is too low. The required version is at least 57.48.101 (included in FFmpeg 3.1 and later).")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (ENABLE_FFMPEG_VIDEO_DUMPER)
|
||||
add_definitions(-DENABLE_FFMPEG_VIDEO_DUMPER)
|
||||
find_package(FFmpeg REQUIRED COMPONENTS ${FFmpeg_COMPONENTS})
|
||||
endif()
|
||||
|
||||
if (ENABLE_FDK)
|
||||
find_library(FDK_AAC fdk-aac DOC "The path to fdk_aac library")
|
||||
if(FDK_AAC STREQUAL "FDK_AAC-NOTFOUND")
|
||||
message(FATAL_ERROR "fdk_aac library not found.")
|
||||
endif()
|
||||
find_package(fdk-aac CONFIG REQUIRED)
|
||||
endif()
|
||||
|
||||
# Platform-specific library requirements
|
||||
# ======================================
|
||||
|
||||
@ -351,21 +412,9 @@ git_describe(GIT_DESC --always --long --dirty)
|
||||
git_branch_name(GIT_BRANCH)
|
||||
get_timestamp(BUILD_DATE)
|
||||
|
||||
if (NOT USE_SYSTEM_BOOST)
|
||||
add_definitions( -DBOOST_ALL_NO_LIB )
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
add_subdirectory(externals)
|
||||
|
||||
# Boost
|
||||
if (USE_SYSTEM_BOOST)
|
||||
find_package(Boost 1.70.0 COMPONENTS serialization REQUIRED)
|
||||
else()
|
||||
add_library(Boost::boost ALIAS boost)
|
||||
add_library(Boost::serialization ALIAS boost_serialization)
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(dist/installer)
|
||||
|
||||
|
28
CMakeModules/VcpkgCmakeUtils.cmake
Normal file
28
CMakeModules/VcpkgCmakeUtils.cmake
Normal file
@ -0,0 +1,28 @@
|
||||
# Enable library versioning and manifests
|
||||
set(VCPKG_FEATURE_FLAGS "manifests,versions" CACHE INTERNAL "Necessary vcpkg flags for manifest based autoinstall and versioning")
|
||||
|
||||
# enable rebuilding of packages if requested by changed configuration
|
||||
if(NOT DEFINED VCPKG_RECURSE_REBUILD_FLAG)
|
||||
set(VCPKG_RECURSE_REBUILD_FLAG "--recurse" CACHE INTERNAL "Enable rebuilding of packages if requested by changed configuration by default")
|
||||
endif()
|
||||
|
||||
# Configure vcpkg
|
||||
set(VCPKG_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/externals/vcpkg")
|
||||
if (WIN32)
|
||||
#execute_process(COMMAND cmd /C "${VCPKG_DIRECTORY}/bootstrap-vcpkg.bat")
|
||||
set(VCPKG_EXECUTABLE "${VCPKG_DIRECTORY}/vcpkg.exe")
|
||||
else()
|
||||
execute_process(COMMAND bash "${VCPKG_DIRECTORY}/bootstrap-vcpkg.sh")
|
||||
set(VCPKG_EXECUTABLE "${VCPKG_DIRECTORY}/vcpkg")
|
||||
endif()
|
||||
|
||||
# Install a package using the command line interface
|
||||
function(vcpkg_add_package PKG_NAME)
|
||||
# Run the executable to install dependencies
|
||||
set(VCPKG_TARGET_TRIPLET_FLAG "--triplet=x64-windows-static")
|
||||
message(STATUS "VCPKG: Installing ${PKG_NAME}")
|
||||
execute_process(COMMAND ${VCPKG_EXECUTABLE} ${VCPKG_TARGET_TRIPLET_FLAG} ${VCPKG_RECURSE_REBUILD_FLAG} --disable-metrics install "${PKG_NAME}" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} RESULT_VARIABLE VCPKG_INSTALL_OK)
|
||||
if (NOT VCPKG_INSTALL_OK EQUAL "0")
|
||||
message(FATAL_ERROR "VCPKG: Failed installing ${PKG_NAME}!")
|
||||
endif()
|
||||
endfunction()
|
92
externals/CMakeLists.txt
vendored
92
externals/CMakeLists.txt
vendored
@ -9,34 +9,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules)
|
||||
include(DownloadExternals)
|
||||
include(ExternalProject)
|
||||
|
||||
# Boost
|
||||
set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/boost")
|
||||
set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost")
|
||||
set(Boost_NO_SYSTEM_PATHS ON)
|
||||
add_library(boost INTERFACE)
|
||||
target_include_directories(boost SYSTEM INTERFACE ${Boost_INCLUDE_DIR})
|
||||
|
||||
# Boost::serialization
|
||||
file(GLOB boost_serialization_SRC "${CMAKE_SOURCE_DIR}/externals/boost/libs/serialization/src/*.cpp")
|
||||
add_library(boost_serialization STATIC ${boost_serialization_SRC})
|
||||
target_link_libraries(boost_serialization PUBLIC boost)
|
||||
|
||||
# Add additional boost libs here; remember to ALIAS them in the root CMakeLists!
|
||||
|
||||
# Catch
|
||||
add_library(catch-single-include INTERFACE)
|
||||
target_include_directories(catch-single-include INTERFACE catch/single_include)
|
||||
|
||||
# Crypto++
|
||||
add_subdirectory(cryptopp)
|
||||
|
||||
# Xbyak
|
||||
if (ARCHITECTURE_x86_64)
|
||||
add_library(xbyak INTERFACE)
|
||||
target_include_directories(xbyak SYSTEM INTERFACE ./xbyak/xbyak)
|
||||
target_compile_definitions(xbyak INTERFACE XBYAK_NO_OP_NAMES)
|
||||
endif()
|
||||
|
||||
# Dynarmic
|
||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_ARM64)
|
||||
set(DYNARMIC_TESTS OFF)
|
||||
@ -45,18 +17,11 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_ARM64)
|
||||
add_subdirectory(dynarmic)
|
||||
endif()
|
||||
|
||||
# libfmt
|
||||
add_subdirectory(fmt)
|
||||
add_library(fmt::fmt ALIAS fmt)
|
||||
|
||||
# getopt
|
||||
if (MSVC)
|
||||
add_subdirectory(getopt)
|
||||
endif()
|
||||
|
||||
# Glad
|
||||
add_subdirectory(glad)
|
||||
|
||||
# inih
|
||||
add_subdirectory(inih)
|
||||
|
||||
@ -79,66 +44,13 @@ target_include_directories(SoundTouch INTERFACE ./soundtouch/include)
|
||||
# Teakra
|
||||
add_subdirectory(teakra EXCLUDE_FROM_ALL)
|
||||
|
||||
# Zstandard
|
||||
add_subdirectory(zstd/build/cmake EXCLUDE_FROM_ALL)
|
||||
target_include_directories(libzstd_static INTERFACE $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/externals/zstd/lib>)
|
||||
|
||||
# ENet
|
||||
add_subdirectory(enet)
|
||||
target_include_directories(enet INTERFACE ./enet/include)
|
||||
|
||||
# Cubeb
|
||||
if (ENABLE_CUBEB)
|
||||
set(BUILD_TESTS OFF CACHE BOOL "")
|
||||
add_subdirectory(cubeb EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
# DiscordRPC
|
||||
if (USE_DISCORD_PRESENCE)
|
||||
add_subdirectory(discord-rpc EXCLUDE_FROM_ALL)
|
||||
target_include_directories(discord-rpc INTERFACE ./discord-rpc/include)
|
||||
if (ENABLE_WEB_SERVICE AND ANDROID)
|
||||
add_subdirectory(android-ifaddrs)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
find_package(OpenSSL 1.1)
|
||||
if (OPENSSL_FOUND)
|
||||
set(OPENSSL_LIBRARIES OpenSSL::SSL OpenSSL::Crypto)
|
||||
else()
|
||||
# LibreSSL
|
||||
set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
|
||||
set(OPENSSLDIR "/etc/ssl/")
|
||||
add_subdirectory(libressl EXCLUDE_FROM_ALL)
|
||||
target_include_directories(ssl INTERFACE ./libressl/include)
|
||||
target_compile_definitions(ssl PRIVATE -DHAVE_INET_NTOP)
|
||||
get_directory_property(OPENSSL_LIBRARIES
|
||||
DIRECTORY libressl
|
||||
DEFINITION OPENSSL_LIBS)
|
||||
endif()
|
||||
# JSON
|
||||
add_library(json-headers INTERFACE)
|
||||
target_include_directories(json-headers INTERFACE ./json)
|
||||
|
||||
if(ANDROID)
|
||||
add_subdirectory(android-ifaddrs)
|
||||
endif()
|
||||
|
||||
# httplib
|
||||
add_library(httplib INTERFACE)
|
||||
target_include_directories(httplib INTERFACE ./httplib)
|
||||
target_compile_options(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT)
|
||||
target_link_libraries(httplib INTERFACE ${OPENSSL_LIBRARIES})
|
||||
|
||||
# cpp-jwt
|
||||
add_library(cpp-jwt INTERFACE)
|
||||
target_include_directories(cpp-jwt INTERFACE ./cpp-jwt/include)
|
||||
endif()
|
||||
|
||||
# lodepng
|
||||
add_subdirectory(lodepng)
|
||||
|
||||
# (xperia64): Only use libyuv on Android b/c of build issues on Windows and mandatory JPEG
|
||||
if(ANDROID)
|
||||
# libyuv
|
||||
add_subdirectory(libyuv)
|
||||
target_include_directories(yuv INTERFACE ./libyuv/include)
|
||||
endif()
|
||||
|
1
externals/Vulkan-Headers
vendored
Submodule
1
externals/Vulkan-Headers
vendored
Submodule
Submodule externals/Vulkan-Headers added at 2c823b7f27
1
externals/boost
vendored
1
externals/boost
vendored
Submodule externals/boost deleted from 36603a1e66
1
externals/catch
vendored
1
externals/catch
vendored
Submodule externals/catch deleted from c4e3767e26
1
externals/cpp-jwt
vendored
1
externals/cpp-jwt
vendored
Submodule externals/cpp-jwt deleted from 6e27aa4c86
449
externals/cryptopp/CMakeLists.txt
vendored
449
externals/cryptopp/CMakeLists.txt
vendored
@ -1,449 +0,0 @@
|
||||
# A trimmed down version of the CMakeLists.txt from noloader/cryptopp-cmake
|
||||
# The differences are:
|
||||
# - removed support for legacy CMake versions
|
||||
# - removed support for 32-bit
|
||||
# - added prefix "CRYPTOPP_OPT_" to all option names
|
||||
# - disabled testing
|
||||
# - disabled installation
|
||||
# - disabled documentation
|
||||
# - configured to build a static library only
|
||||
# - adds include directories to the library target
|
||||
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
if (POLICY CMP0048)
|
||||
cmake_policy(SET CMP0048 NEW)
|
||||
endif ()
|
||||
project(cryptopp VERSION 8.5.0)
|
||||
if (POLICY CMP0054)
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
endif ()
|
||||
|
||||
set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cryptopp)
|
||||
|
||||
include(TestBigEndian)
|
||||
include(GNUInstallDirs)
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
set(TEST_PROG_DIR ${SRC_DIR}/TestPrograms)
|
||||
set(TEST_CXX_FILE ${TEST_PROG_DIR}/test_cxx.cxx)
|
||||
|
||||
#============================================================================
|
||||
# Settable options
|
||||
#============================================================================
|
||||
|
||||
option(CRYPTOPP_OPT_DISABLE_ASM "Disable ASM" OFF)
|
||||
option(CRYPTOPP_OPT_DISABLE_SSSE3 "Disable SSSE3" OFF)
|
||||
option(CRYPTOPP_OPT_DISABLE_SSE4 "Disable SSE4" OFF)
|
||||
option(CRYPTOPP_OPT_DISABLE_AESNI "Disable AES-NI" OFF)
|
||||
option(CRYPTOPP_OPT_DISABLE_SHA "Disable SHA" OFF)
|
||||
option(CRYPTOPP_OPT_DISABLE_AVX "Disable AVX" OFF)
|
||||
option(CRYPTOPP_OPT_DISABLE_AVX2 "Disable AVX2" OFF)
|
||||
|
||||
#============================================================================
|
||||
# Compiler options
|
||||
#============================================================================
|
||||
|
||||
# Only set when cross-compiling, http://www.vtk.org/Wiki/CMake_Cross_Compiling
|
||||
if (NOT (CMAKE_SYSTEM_VERSION AND CMAKE_SYSTEM_PROCESSOR))
|
||||
set(CRYPTOPP_CROSS_COMPILE 1)
|
||||
else()
|
||||
set(CRYPTOPP_CROSS_COMPILE 0)
|
||||
endif()
|
||||
|
||||
set(CRYPTOPP_COMPILE_DEFINITIONS)
|
||||
set(CRYPTOPP_COMPILE_OPTIONS)
|
||||
|
||||
# Don't use RPATH's. The resulting binary could fail a security audit.
|
||||
set(CMAKE_MACOSX_RPATH 0)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
|
||||
list(APPEND CRYPTOPP_COMPILE_OPTIONS -wd68 -wd186 -wd279 -wd327 -wd161 -wd3180)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
# Disable C4390: empty controlled statement found: is this the intent?
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4390")
|
||||
endif()
|
||||
|
||||
# Endianness
|
||||
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
|
||||
if(IS_BIG_ENDIAN)
|
||||
add_definitions(-DIS_BIG_ENDIAN)
|
||||
endif()
|
||||
|
||||
if (CRYPTOPP_OPT_DISABLE_ASM)
|
||||
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_ASM)
|
||||
endif ()
|
||||
if (CRYPTOPP_OPT_DISABLE_SSSE3)
|
||||
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_SSSE3)
|
||||
endif ()
|
||||
if (CRYPTOPP_OPT_DISABLE_SSE4)
|
||||
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_SSSE4)
|
||||
endif ()
|
||||
if (CRYPTOPP_OPT_DISABLE_CLMUL)
|
||||
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_CLMUL)
|
||||
endif ()
|
||||
if (CRYPTOPP_OPT_DISABLE_AESNI)
|
||||
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_AESNI)
|
||||
endif ()
|
||||
if (CRYPTOPP_OPT_DISABLE_RDRAND)
|
||||
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_RDRAND)
|
||||
endif ()
|
||||
if (CRYPTOPP_OPT_DISABLE_RDSEED)
|
||||
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_RDSEED)
|
||||
endif ()
|
||||
if (CRYPTOPP_OPT_DISABLE_AVX)
|
||||
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_AVX)
|
||||
endif ()
|
||||
if (CRYPTOPP_OPT_DISABLE_AVX2)
|
||||
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_AVX2)
|
||||
endif ()
|
||||
if (CRYPTOPP_OPT_DISABLE_SHA)
|
||||
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS CRYPTOPP_DISABLE_SHA)
|
||||
endif ()
|
||||
|
||||
# We need the output 'uname -s' for Unix and Linux system detection
|
||||
if (NOT CRYPTOPP_CROSS_COMPILE)
|
||||
set (UNAME_CMD "uname")
|
||||
set (UNAME_ARG "-s")
|
||||
execute_process(COMMAND ${UNAME_CMD} ${UNAME_ARG}
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
RESULT_VARIABLE UNAME_RESULT
|
||||
OUTPUT_VARIABLE UNAME_SYSTEM)
|
||||
string(REGEX REPLACE "\n$" "" UNAME_SYSTEM "${UNAME_SYSTEM}")
|
||||
endif()
|
||||
|
||||
# We need the output 'uname -m' for Unix and Linux platform detection
|
||||
if (NOT CRYPTOPP_CROSS_COMPILE)
|
||||
set (UNAME_CMD "uname")
|
||||
set (UNAME_ARG "-m")
|
||||
execute_process(COMMAND ${UNAME_CMD} ${UNAME_ARG}
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
RESULT_VARIABLE UNAME_RESULT
|
||||
OUTPUT_VARIABLE UNAME_MACHINE)
|
||||
string(REGEX REPLACE "\n$" "" UNAME_MACHINE "${UNAME_MACHINE}")
|
||||
endif()
|
||||
|
||||
###############################################################################
|
||||
|
||||
# Try to find a Posix compatible grep and sed. Solaris, Digital Unix,
|
||||
# Tru64, HP-UX and a few others need tweaking
|
||||
|
||||
if (EXISTS /usr/xpg4/bin/grep)
|
||||
set(GREP_CMD /usr/xpg4/bin/grep)
|
||||
elseif (EXISTS /usr/gnu/bin/grep)
|
||||
set(GREP_CMD /usr/gnu/bin/grep)
|
||||
elseif (EXISTS /usr/linux/bin/grep)
|
||||
set(GREP_CMD /usr/linux/bin/grep)
|
||||
else ()
|
||||
set(GREP_CMD grep)
|
||||
endif ()
|
||||
|
||||
if (EXISTS /usr/xpg4/bin/sed)
|
||||
set(SED_CMD /usr/xpg4/bin/sed)
|
||||
elseif (EXISTS /usr/gnu/bin/sed)
|
||||
set(SED_CMD /usr/gnu/bin/sed)
|
||||
elseif (EXISTS /usr/linux/bin/sed)
|
||||
set(SED_CMD /usr/linux/bin/sed)
|
||||
else ()
|
||||
set(SED_CMD sed)
|
||||
endif ()
|
||||
|
||||
###############################################################################
|
||||
|
||||
function(CheckCompileOption opt var)
|
||||
CHECK_CXX_COMPILER_FLAG(${opt} ${var})
|
||||
endfunction(CheckCompileOption)
|
||||
|
||||
function(CheckCompileLinkOption opt var prog)
|
||||
|
||||
if (MSVC)
|
||||
|
||||
# TODO: improve this...
|
||||
CHECK_CXX_COMPILER_FLAG(${opt} ${var})
|
||||
|
||||
elseif (APPLE)
|
||||
|
||||
message(STATUS "Performing Test ${var}")
|
||||
try_compile(COMMAND_SUCCESS ${CMAKE_BINARY_DIR} ${prog} COMPILE_DEFINITIONS ${opt})
|
||||
if (COMMAND_SUCCESS)
|
||||
set(${var} 1 PARENT_SCOPE)
|
||||
message(STATUS "Performing Test ${var} - Success")
|
||||
else ()
|
||||
set(${var} 0 PARENT_SCOPE)
|
||||
message(STATUS "Performing Test ${var} - Failed")
|
||||
endif ()
|
||||
|
||||
else ()
|
||||
|
||||
message(STATUS "Performing Test ${var}")
|
||||
try_compile(COMMAND_SUCCESS ${CMAKE_BINARY_DIR} ${prog} COMPILE_DEFINITIONS ${opt})
|
||||
if (COMMAND_SUCCESS)
|
||||
set(${var} 1 PARENT_SCOPE)
|
||||
message(STATUS "Performing Test ${var} - Success")
|
||||
else ()
|
||||
set(${var} 0 PARENT_SCOPE)
|
||||
message(STATUS "Performing Test ${var} - Failed")
|
||||
endif ()
|
||||
|
||||
endif ()
|
||||
|
||||
endfunction(CheckCompileLinkOption)
|
||||
|
||||
function(AddCompileOption opt)
|
||||
|
||||
if ("${COMMAND_OUTPUT}" NOT STREQUAL "")
|
||||
list(APPEND CRYPTOPP_COMPILE_OPTIONS "${opt}")
|
||||
endif ()
|
||||
|
||||
endfunction(AddCompileOption)
|
||||
|
||||
###############################################################################
|
||||
|
||||
function(DumpMachine output pattern)
|
||||
|
||||
if (MSVC)
|
||||
|
||||
# CMake does not provide a generic shell/terminal mechanism
|
||||
# and Microsoft environments don't know what 'sh' is.
|
||||
set(${output} 0 PARENT_SCOPE)
|
||||
|
||||
else ()
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES ${pattern})
|
||||
set(${output} TRUE PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endfunction(DumpMachine)
|
||||
|
||||
# Thansk to Anonimal for MinGW; see http://github.com/weidai11/cryptopp/issues/466
|
||||
DumpMachine(CRYPTOPP_AMD64 "(x86_64|AMD64|amd64)")
|
||||
DumpMachine(CRYPTOPP_I386 "(i.86)")
|
||||
DumpMachine(CRYPTOPP_MINGW64 "(w64-mingw32)|(mingw64)")
|
||||
DumpMachine(CRYPTOPP_ARMV8 "(armv8|aarch64)")
|
||||
|
||||
###############################################################################
|
||||
|
||||
if(MSVC)
|
||||
if(CMAKE_SYSTEM_VERSION MATCHES "10\\.0.*")
|
||||
list(APPEND CRYPTOPP_COMPILE_DEFINITIONS "_WIN32_WINNT=0x0A00")
|
||||
endif()
|
||||
list(APPEND CRYPTOPP_COMPILE_OPTIONS /FI winapifamily.h)
|
||||
endif()
|
||||
|
||||
# Enable PIC for all targets except Windows and 32-bit x86.
|
||||
# Avoid on 32-bit x86 due to register pressures.
|
||||
if ((NOT CRYPTOPP_CROSS_COMPILE) AND (NOT (WINDOWS OR WINDOWS_STORE OR WINDOWS_PHONE)))
|
||||
# Use Regex; match i386, i486, i586 and i686
|
||||
if (NOT (${UNAME_MACHINE} MATCHES "i.86"))
|
||||
SET(CMAKE_POSITION_INDEPENDENT_CODE 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Link is driven through the compiler, but CXXFLAGS are not used. Also see
|
||||
# http://public.kitware.com/pipermail/cmake/2003-June/003967.html
|
||||
if (NOT (WINDOWS OR WINDOWS_STORE OR WINDOWS_PHONE))
|
||||
SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
endif()
|
||||
|
||||
#============================================================================
|
||||
# Sources & headers
|
||||
#============================================================================
|
||||
|
||||
# Library headers
|
||||
file(GLOB cryptopp_HEADERS ${SRC_DIR}/*.h)
|
||||
|
||||
# Remove headers used to build test suite
|
||||
list(REMOVE_ITEM cryptopp_HEADERS
|
||||
${SRC_DIR}/bench.h
|
||||
${SRC_DIR}/validate.h
|
||||
)
|
||||
|
||||
# Library sources.
|
||||
# These have been trimmed to include only things Citra uses. This speeds up
|
||||
# compiles and reduces the amount of compilation breakage.
|
||||
set(cryptopp_SOURCES
|
||||
# The Crypto++ readme says you should put these 3 object files first,
|
||||
# to avoid "problems associated with C++ static initialization order",
|
||||
# but doesn't actually tell what could go wrong. Better safe than sorry
|
||||
# I guess...
|
||||
${SRC_DIR}/cryptlib.cpp
|
||||
${SRC_DIR}/cpu.cpp
|
||||
${SRC_DIR}/integer.cpp
|
||||
|
||||
${SRC_DIR}/algparam.cpp
|
||||
${SRC_DIR}/allocate.cpp
|
||||
${SRC_DIR}/asn.cpp
|
||||
${SRC_DIR}/authenc.cpp
|
||||
${SRC_DIR}/base64.cpp
|
||||
${SRC_DIR}/basecode.cpp
|
||||
${SRC_DIR}/ccm.cpp
|
||||
${SRC_DIR}/crc_simd.cpp
|
||||
${SRC_DIR}/des.cpp
|
||||
${SRC_DIR}/dessp.cpp
|
||||
${SRC_DIR}/dll.cpp
|
||||
${SRC_DIR}/ec2n.cpp
|
||||
${SRC_DIR}/ecp.cpp
|
||||
${SRC_DIR}/filters.cpp
|
||||
${SRC_DIR}/fips140.cpp
|
||||
${SRC_DIR}/gcm_simd.cpp
|
||||
${SRC_DIR}/gf2n_simd.cpp
|
||||
${SRC_DIR}/gf2n.cpp
|
||||
${SRC_DIR}/gfpcrypt.cpp
|
||||
${SRC_DIR}/hex.cpp
|
||||
${SRC_DIR}/hmac.cpp
|
||||
${SRC_DIR}/hrtimer.cpp
|
||||
${SRC_DIR}/iterhash.cpp
|
||||
${SRC_DIR}/md5.cpp
|
||||
${SRC_DIR}/misc.cpp
|
||||
${SRC_DIR}/modes.cpp
|
||||
${SRC_DIR}/mqueue.cpp
|
||||
${SRC_DIR}/nbtheory.cpp
|
||||
${SRC_DIR}/neon_simd.cpp
|
||||
${SRC_DIR}/oaep.cpp
|
||||
${SRC_DIR}/osrng.cpp
|
||||
${SRC_DIR}/ppc_power7.cpp
|
||||
${SRC_DIR}/ppc_power8.cpp
|
||||
${SRC_DIR}/ppc_power9.cpp
|
||||
${SRC_DIR}/ppc_simd.cpp
|
||||
${SRC_DIR}/pubkey.cpp
|
||||
${SRC_DIR}/queue.cpp
|
||||
${SRC_DIR}/randpool.cpp
|
||||
${SRC_DIR}/rdtables.cpp
|
||||
${SRC_DIR}/rijndael_simd.cpp
|
||||
${SRC_DIR}/rijndael.cpp
|
||||
${SRC_DIR}/rng.cpp
|
||||
${SRC_DIR}/sha_simd.cpp
|
||||
${SRC_DIR}/sha.cpp
|
||||
${SRC_DIR}/sse_simd.cpp
|
||||
)
|
||||
|
||||
if(ANDROID)
|
||||
include_directories(${ANDROID_NDK}/sources/android/cpufeatures)
|
||||
list(APPEND cryptopp_SOURCES ${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c)
|
||||
endif()
|
||||
|
||||
set(cryptopp_SOURCES_ASM)
|
||||
|
||||
if (MSVC AND NOT DISABLE_ASM)
|
||||
if (${CMAKE_GENERATOR} MATCHES ".*ARM")
|
||||
message(STATUS "Disabling ASM because ARM is specified as target platform.")
|
||||
else ()
|
||||
enable_language(ASM_MASM)
|
||||
list(APPEND cryptopp_SOURCES_ASM
|
||||
${SRC_DIR}/rdrand.asm
|
||||
${SRC_DIR}/rdseed.asm
|
||||
)
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
list(APPEND cryptopp_SOURCES_ASM
|
||||
${SRC_DIR}/x64dll.asm
|
||||
${SRC_DIR}/x64masm.asm
|
||||
)
|
||||
set_source_files_properties(${cryptopp_SOURCES_ASM} PROPERTIES COMPILE_DEFINITIONS "_M_X64")
|
||||
else ()
|
||||
set_source_files_properties(${cryptopp_SOURCES_ASM} PROPERTIES COMPILE_DEFINITIONS "_M_X86" COMPILE_FLAGS "/safeseh")
|
||||
endif ()
|
||||
set_source_files_properties(${cryptopp_SOURCES_ASM} PROPERTIES LANGUAGE ASM_MASM)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
#============================================================================
|
||||
# Architecture flags
|
||||
#============================================================================
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Intel" OR CMAKE_CXX_COMPILER MATCHES "xlC")
|
||||
|
||||
if (CRYPTOPP_AMD64 OR CRYPTOPP_I386)
|
||||
CheckCompileLinkOption("-msse2" CRYPTOPP_IA32_SSE2
|
||||
"${TEST_PROG_DIR}/test_x86_sse2.cxx")
|
||||
CheckCompileLinkOption("-mssse3" CRYPTOPP_IA32_SSSE3
|
||||
"${TEST_PROG_DIR}/test_x86_ssse3.cxx")
|
||||
CheckCompileLinkOption("-msse4.1" CRYPTOPP_IA32_SSE41
|
||||
"${TEST_PROG_DIR}/test_x86_sse41.cxx")
|
||||
CheckCompileLinkOption("-msse4.2" CRYPTOPP_IA32_SSE42
|
||||
"${TEST_PROG_DIR}/test_x86_sse42.cxx")
|
||||
CheckCompileLinkOption("-mssse3 -mpclmul" CRYPTOPP_IA32_CLMUL
|
||||
"${TEST_PROG_DIR}/test_x86_clmul.cxx")
|
||||
CheckCompileLinkOption("-msse4.1 -maes" CRYPTOPP_IA32_AES
|
||||
"${TEST_PROG_DIR}/test_x86_aes.cxx")
|
||||
CheckCompileLinkOption("-mavx" CRYPTOPP_IA32_AVX
|
||||
"${TEST_PROG_DIR}/test_x86_avx.cxx")
|
||||
CheckCompileLinkOption("-mavx2" CRYPTOPP_IA32_AVX2
|
||||
"${TEST_PROG_DIR}/test_x86_avx2.cxx")
|
||||
CheckCompileLinkOption("-msse4.2 -msha" CRYPTOPP_IA32_SHA
|
||||
"${TEST_PROG_DIR}/test_x86_sha.cxx")
|
||||
if (EXISTS "${TEST_PROG_DIR}/test_asm_mixed.cxx")
|
||||
CheckCompileLinkOption("" CRYPTOPP_MIXED_ASM
|
||||
"${TEST_PROG_DIR}/test_asm_mixed.cxx")
|
||||
else ()
|
||||
CheckCompileLinkOption("" CRYPTOPP_MIXED_ASM
|
||||
"${TEST_PROG_DIR}/test_mixed_asm.cxx")
|
||||
endif ()
|
||||
|
||||
if (NOT CRYPTOPP_MIXED_ASM)
|
||||
list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_MIXED_ASM")
|
||||
endif ()
|
||||
|
||||
if (NOT CRYPTOPP_IA32_SSE2 AND NOT CRYPTOPP_DISABLE_ASM)
|
||||
list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_ASM")
|
||||
elseif (CRYPTOPP_IA32_SSE2 AND NOT CRYPTOPP_DISABLE_ASM)
|
||||
set_source_files_properties(${SRC_DIR}/sse_simd.cpp PROPERTIES COMPILE_FLAGS "-msse2")
|
||||
endif ()
|
||||
if (NOT CRYPTOPP_IA32_SSSE3 AND NOT CRYPTOPP_DISABLE_SSSE3)
|
||||
list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_SSSE3")
|
||||
elseif (CRYPTOPP_IA32_SSSE3 AND NOT CRYPTOPP_DISABLE_SSSE3)
|
||||
if (NOT CRYPTOPP_IA32_SSE41 AND NOT CRYPTOPP_DISABLE_SSE4)
|
||||
list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_SSE4")
|
||||
endif ()
|
||||
if (NOT CRYPTOPP_IA32_SSE42 AND NOT CRYPTOPP_DISABLE_SSE4)
|
||||
list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_SSE4")
|
||||
elseif (CRYPTOPP_IA32_SSE42 AND NOT CRYPTOPP_DISABLE_SSE4)
|
||||
set_source_files_properties(${SRC_DIR}/crc_simd.cpp PROPERTIES COMPILE_FLAGS "-msse4.2")
|
||||
if (NOT CRYPTOPP_IA32_CLMUL AND NOT CRYPTOPP_DISABLE_CLMUL)
|
||||
list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_CLMUL")
|
||||
elseif (CRYPTOPP_IA32_CLMUL AND NOT CRYPTOPP_DISABLE_CLMUL)
|
||||
set_source_files_properties(${SRC_DIR}/gcm_simd.cpp PROPERTIES COMPILE_FLAGS "-mssse3 -mpclmul")
|
||||
set_source_files_properties(${SRC_DIR}/gf2n_simd.cpp PROPERTIES COMPILE_FLAGS "-mpclmul")
|
||||
endif ()
|
||||
if (NOT CRYPTOPP_IA32_AES AND NOT CRYPTOPP_DISABLE_AES)
|
||||
list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_AESNI")
|
||||
elseif (CRYPTOPP_IA32_AES AND NOT CRYPTOPP_DISABLE_AES)
|
||||
set_source_files_properties(${SRC_DIR}/rijndael_simd.cpp PROPERTIES COMPILE_FLAGS "-msse4.1 -maes")
|
||||
endif ()
|
||||
if (NOT CRYPTOPP_IA32_AVX2 AND NOT CRYPTOPP_DISABLE_AVX2)
|
||||
list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_AVX2")
|
||||
endif ()
|
||||
if (NOT CRYPTOPP_IA32_SHA AND NOT CRYPTOPP_DISABLE_SHA)
|
||||
list(APPEND CRYPTOPP_COMPILE_OPTIONS "-DCRYPTOPP_DISABLE_SHANI")
|
||||
elseif (CRYPTOPP_IA32_SHA AND NOT CRYPTOPP_DISABLE_SHA)
|
||||
set_source_files_properties(${SRC_DIR}/sha_simd.cpp PROPERTIES COMPILE_FLAGS "-msse4.2 -msha")
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
#============================================================================
|
||||
# Compile targets
|
||||
#============================================================================
|
||||
|
||||
set(cryptopp_LIBRARY_SOURCES ${cryptopp_SOURCES_ASM})
|
||||
list(APPEND cryptopp_LIBRARY_SOURCES ${cryptopp_SOURCES})
|
||||
|
||||
add_library(cryptopp STATIC ${cryptopp_LIBRARY_SOURCES})
|
||||
target_compile_definitions(cryptopp PUBLIC ${CRYPTOPP_COMPILE_DEFINITIONS})
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
|
||||
target_include_directories(cryptopp INTERFACE .)
|
||||
|
||||
#============================================================================
|
||||
# Third-party libraries
|
||||
#============================================================================
|
||||
|
||||
find_package(Threads)
|
||||
target_link_libraries(cryptopp PRIVATE ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
if(ANDROID)
|
||||
include(AndroidNdkModules)
|
||||
android_ndk_import_module_cpufeatures()
|
||||
target_link_libraries(cryptopp PRIVATE cpufeatures)
|
||||
endif()
|
1
externals/cryptopp/cryptopp
vendored
1
externals/cryptopp/cryptopp
vendored
Submodule externals/cryptopp/cryptopp deleted from f2102243e6
1
externals/discord-rpc
vendored
1
externals/discord-rpc
vendored
Submodule externals/discord-rpc deleted from 963aa9f3e5
2
externals/dynarmic
vendored
2
externals/dynarmic
vendored
Submodule externals/dynarmic updated: af0d4a7c18...da5d06c32a
1
externals/enet
vendored
1
externals/enet
vendored
Submodule externals/enet deleted from 498b9e3571
1
externals/fmt
vendored
1
externals/fmt
vendored
Submodule externals/fmt deleted from cc09f1a679
12
externals/glad/CMakeLists.txt
vendored
12
externals/glad/CMakeLists.txt
vendored
@ -1,12 +0,0 @@
|
||||
add_library(glad STATIC
|
||||
src/glad.c
|
||||
include/KHR/khrplatform.h
|
||||
include/glad/glad.h
|
||||
)
|
||||
|
||||
create_target_directory_groups(glad)
|
||||
target_include_directories(glad PUBLIC "include/")
|
||||
|
||||
if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
|
||||
target_link_libraries(glad PRIVATE dl)
|
||||
endif()
|
5
externals/glad/Readme.md
vendored
5
externals/glad/Readme.md
vendored
@ -1,5 +0,0 @@
|
||||
These files were generated by the [glad](https://github.com/Dav1dde/glad) OpenGL loader generator and have been checked in as-is. You can re-generate them using glad with the following command:
|
||||
|
||||
```
|
||||
python -m glad --profile core --out-path glad/ --api "gl=3.3,gles2=3.2" --generator=c
|
||||
```
|
282
externals/glad/include/KHR/khrplatform.h
vendored
282
externals/glad/include/KHR/khrplatform.h
vendored
@ -1,282 +0,0 @@
|
||||
#ifndef __khrplatform_h_
|
||||
#define __khrplatform_h_
|
||||
|
||||
/*
|
||||
** Copyright (c) 2008-2018 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
/* Khronos platform-specific types and definitions.
|
||||
*
|
||||
* The master copy of khrplatform.h is maintained in the Khronos EGL
|
||||
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
|
||||
* The last semantic modification to khrplatform.h was at commit ID:
|
||||
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
|
||||
*
|
||||
* Adopters may modify this file to suit their platform. Adopters are
|
||||
* encouraged to submit platform specific modifications to the Khronos
|
||||
* group so that they can be included in future versions of this file.
|
||||
* Please submit changes by filing pull requests or issues on
|
||||
* the EGL Registry repository linked above.
|
||||
*
|
||||
*
|
||||
* See the Implementer's Guidelines for information about where this file
|
||||
* should be located on your system and for more details of its use:
|
||||
* http://www.khronos.org/registry/implementers_guide.pdf
|
||||
*
|
||||
* This file should be included as
|
||||
* #include <KHR/khrplatform.h>
|
||||
* by Khronos client API header files that use its types and defines.
|
||||
*
|
||||
* The types in khrplatform.h should only be used to define API-specific types.
|
||||
*
|
||||
* Types defined in khrplatform.h:
|
||||
* khronos_int8_t signed 8 bit
|
||||
* khronos_uint8_t unsigned 8 bit
|
||||
* khronos_int16_t signed 16 bit
|
||||
* khronos_uint16_t unsigned 16 bit
|
||||
* khronos_int32_t signed 32 bit
|
||||
* khronos_uint32_t unsigned 32 bit
|
||||
* khronos_int64_t signed 64 bit
|
||||
* khronos_uint64_t unsigned 64 bit
|
||||
* khronos_intptr_t signed same number of bits as a pointer
|
||||
* khronos_uintptr_t unsigned same number of bits as a pointer
|
||||
* khronos_ssize_t signed size
|
||||
* khronos_usize_t unsigned size
|
||||
* khronos_float_t signed 32 bit floating point
|
||||
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
|
||||
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
|
||||
* nanoseconds
|
||||
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
|
||||
* khronos_boolean_enum_t enumerated boolean type. This should
|
||||
* only be used as a base type when a client API's boolean type is
|
||||
* an enum. Client APIs which use an integer or other type for
|
||||
* booleans cannot use this as the base type for their boolean.
|
||||
*
|
||||
* Tokens defined in khrplatform.h:
|
||||
*
|
||||
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
|
||||
*
|
||||
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
|
||||
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
|
||||
*
|
||||
* Calling convention macros defined in this file:
|
||||
* KHRONOS_APICALL
|
||||
* KHRONOS_APIENTRY
|
||||
* KHRONOS_APIATTRIBUTES
|
||||
*
|
||||
* These may be used in function prototypes as:
|
||||
*
|
||||
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
|
||||
* int arg1,
|
||||
* int arg2) KHRONOS_APIATTRIBUTES;
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APICALL
|
||||
*-------------------------------------------------------------------------
|
||||
* This precedes the return type of the function in the function prototype.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||
# define KHRONOS_APICALL __declspec(dllimport)
|
||||
#elif defined (__SYMBIAN32__)
|
||||
# define KHRONOS_APICALL IMPORT_C
|
||||
#elif defined(__ANDROID__)
|
||||
# define KHRONOS_APICALL __attribute__((visibility("default")))
|
||||
#else
|
||||
# define KHRONOS_APICALL
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIENTRY
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the return type of the function and precedes the function
|
||||
* name in the function prototype.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
|
||||
/* Win32 but not WinCE */
|
||||
# define KHRONOS_APIENTRY __stdcall
|
||||
#else
|
||||
# define KHRONOS_APIENTRY
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIATTRIBUTES
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the closing parenthesis of the function prototype arguments.
|
||||
*/
|
||||
#if defined (__ARMCC_2__)
|
||||
#define KHRONOS_APIATTRIBUTES __softfp
|
||||
#else
|
||||
#define KHRONOS_APIATTRIBUTES
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* basic type definitions
|
||||
*-----------------------------------------------------------------------*/
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
||||
|
||||
|
||||
/*
|
||||
* Using <stdint.h>
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(__VMS ) || defined(__sgi)
|
||||
|
||||
/*
|
||||
* Using <inttypes.h>
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||
|
||||
/*
|
||||
* Win32
|
||||
*/
|
||||
typedef __int32 khronos_int32_t;
|
||||
typedef unsigned __int32 khronos_uint32_t;
|
||||
typedef __int64 khronos_int64_t;
|
||||
typedef unsigned __int64 khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(__sun__) || defined(__digital__)
|
||||
|
||||
/*
|
||||
* Sun or Digital
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#if defined(__arch64__) || defined(_LP64)
|
||||
typedef long int khronos_int64_t;
|
||||
typedef unsigned long int khronos_uint64_t;
|
||||
#else
|
||||
typedef long long int khronos_int64_t;
|
||||
typedef unsigned long long int khronos_uint64_t;
|
||||
#endif /* __arch64__ */
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif 0
|
||||
|
||||
/*
|
||||
* Hypothetical platform with no float or int64 support
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#define KHRONOS_SUPPORT_INT64 0
|
||||
#define KHRONOS_SUPPORT_FLOAT 0
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Generic fallback
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Types that are (so far) the same on all platforms
|
||||
*/
|
||||
typedef signed char khronos_int8_t;
|
||||
typedef unsigned char khronos_uint8_t;
|
||||
typedef signed short int khronos_int16_t;
|
||||
typedef unsigned short int khronos_uint16_t;
|
||||
|
||||
/*
|
||||
* Types that differ between LLP64 and LP64 architectures - in LLP64,
|
||||
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
|
||||
* to be the only LLP64 architecture in current use.
|
||||
*/
|
||||
#ifdef _WIN64
|
||||
typedef signed long long int khronos_intptr_t;
|
||||
typedef unsigned long long int khronos_uintptr_t;
|
||||
typedef signed long long int khronos_ssize_t;
|
||||
typedef unsigned long long int khronos_usize_t;
|
||||
#else
|
||||
typedef signed long int khronos_intptr_t;
|
||||
typedef unsigned long int khronos_uintptr_t;
|
||||
typedef signed long int khronos_ssize_t;
|
||||
typedef unsigned long int khronos_usize_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_FLOAT
|
||||
/*
|
||||
* Float type
|
||||
*/
|
||||
typedef float khronos_float_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_INT64
|
||||
/* Time types
|
||||
*
|
||||
* These types can be used to represent a time interval in nanoseconds or
|
||||
* an absolute Unadjusted System Time. Unadjusted System Time is the number
|
||||
* of nanoseconds since some arbitrary system event (e.g. since the last
|
||||
* time the system booted). The Unadjusted System Time is an unsigned
|
||||
* 64 bit value that wraps back to 0 every 584 years. Time intervals
|
||||
* may be either signed or unsigned.
|
||||
*/
|
||||
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
|
||||
typedef khronos_int64_t khronos_stime_nanoseconds_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dummy value used to pad enum types to 32 bits.
|
||||
*/
|
||||
#ifndef KHRONOS_MAX_ENUM
|
||||
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enumerated boolean type
|
||||
*
|
||||
* Values other than zero should be considered to be true. Therefore
|
||||
* comparisons should not be made against KHRONOS_TRUE.
|
||||
*/
|
||||
typedef enum {
|
||||
KHRONOS_FALSE = 0,
|
||||
KHRONOS_TRUE = 1,
|
||||
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
|
||||
} khronos_boolean_enum_t;
|
||||
|
||||
#endif /* __khrplatform_h_ */
|
19704
externals/glad/include/glad/glad.h
vendored
19704
externals/glad/include/glad/glad.h
vendored
File diff suppressed because one or more lines are too long
11469
externals/glad/src/glad.c
vendored
11469
externals/glad/src/glad.c
vendored
File diff suppressed because one or more lines are too long
16
externals/httplib/README.md
vendored
16
externals/httplib/README.md
vendored
@ -1,16 +0,0 @@
|
||||
From https://github.com/yhirose/cpp-httplib/commit/b251668522dd459d2c6a75c10390a11b640be708
|
||||
|
||||
MIT License
|
||||
|
||||
===
|
||||
|
||||
cpp-httplib
|
||||
|
||||
A C++11 header-only HTTP library.
|
||||
|
||||
It's extremely easy to setup. Just include httplib.h file in your code!
|
||||
|
||||
Inspired by Sinatra and express.
|
||||
|
||||
© 2017 Yuji Hirose
|
||||
|
7464
externals/httplib/httplib.h
vendored
7464
externals/httplib/httplib.h
vendored
File diff suppressed because it is too large
Load Diff
2
externals/inih/CMakeLists.txt
vendored
2
externals/inih/CMakeLists.txt
vendored
@ -6,4 +6,4 @@ add_library(inih
|
||||
)
|
||||
|
||||
create_target_directory_groups(inih)
|
||||
target_include_directories(inih INTERFACE .)
|
||||
target_include_directories(inih INTERFACE .)
|
2
externals/inih/inih
vendored
2
externals/inih/inih
vendored
Submodule externals/inih/inih updated: 1e80a47dff...5e1d9e2625
9
externals/json/README.md
vendored
9
externals/json/README.md
vendored
@ -1,9 +0,0 @@
|
||||
JSON for Modern C++
|
||||
===================
|
||||
|
||||
v3.9.0
|
||||
|
||||
This is a mirror providing the single required header file.
|
||||
|
||||
The original repository can be found at:
|
||||
https://github.com/nlohmann/json/commit/d34771cafc87b358ba421faca28facc7f8080174
|
25347
externals/json/json.hpp
vendored
25347
externals/json/json.hpp
vendored
File diff suppressed because it is too large
Load Diff
1
externals/libressl
vendored
1
externals/libressl
vendored
Submodule externals/libressl deleted from 039d945419
152
externals/libusb/CMakeLists.txt
vendored
152
externals/libusb/CMakeLists.txt
vendored
@ -1,152 +0,0 @@
|
||||
# Ensure libusb compiles with UTF-8 encoding on MSVC
|
||||
if(MSVC)
|
||||
add_compile_options(/utf-8)
|
||||
endif()
|
||||
|
||||
add_library(usb STATIC EXCLUDE_FROM_ALL
|
||||
libusb/libusb/core.c
|
||||
libusb/libusb/core.c
|
||||
libusb/libusb/descriptor.c
|
||||
libusb/libusb/hotplug.c
|
||||
libusb/libusb/io.c
|
||||
libusb/libusb/strerror.c
|
||||
libusb/libusb/sync.c
|
||||
)
|
||||
set_target_properties(usb PROPERTIES VERSION 1.0.23)
|
||||
if(WIN32)
|
||||
target_include_directories(usb
|
||||
BEFORE
|
||||
PUBLIC
|
||||
libusb/libusb
|
||||
|
||||
PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
|
||||
if (NOT MINGW)
|
||||
target_include_directories(usb BEFORE PRIVATE libusb/msvc)
|
||||
endif()
|
||||
else()
|
||||
target_include_directories(usb
|
||||
# turns out other projects also have "config.h", so make sure the
|
||||
# LibUSB one comes first
|
||||
BEFORE
|
||||
|
||||
PUBLIC
|
||||
libusb/libusb
|
||||
|
||||
PRIVATE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WIN32 OR CYGWIN)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/threads_windows.c
|
||||
libusb/libusb/os/windows_winusb.c
|
||||
libusb/libusb/os/windows_usbdk.c
|
||||
libusb/libusb/os/windows_nt_common.c
|
||||
)
|
||||
set(OS_WINDOWS TRUE)
|
||||
elseif(APPLE)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/darwin_usb.c
|
||||
)
|
||||
find_library(COREFOUNDATION_LIBRARY CoreFoundation)
|
||||
find_library(IOKIT_LIBRARY IOKit)
|
||||
find_library(OBJC_LIBRARY objc)
|
||||
target_link_libraries(usb PRIVATE
|
||||
${COREFOUNDATION_LIBRARY}
|
||||
${IOKIT_LIBRARY}
|
||||
${OBJC_LIBRARY}
|
||||
)
|
||||
set(OS_DARWIN TRUE)
|
||||
elseif(ANDROID)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/linux_usbfs.c
|
||||
libusb/libusb/os/linux_netlink.c
|
||||
)
|
||||
find_library(LOG_LIBRARY log)
|
||||
target_link_libraries(usb PRIVATE ${LOG_LIBRARY})
|
||||
set(OS_LINUX TRUE)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/linux_usbfs.c
|
||||
)
|
||||
find_package(Libudev)
|
||||
if(LIBUDEV_FOUND)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/linux_udev.c
|
||||
)
|
||||
target_link_libraries(usb PRIVATE "${LIBUDEV_LIBRARIES}")
|
||||
target_include_directories(usb PRIVATE "${LIBUDEV_INCLUDE_DIR}")
|
||||
set(HAVE_LIBUDEV TRUE)
|
||||
set(USE_UDEV TRUE)
|
||||
else()
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/linux_netlink.c
|
||||
)
|
||||
endif()
|
||||
set(OS_LINUX TRUE)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/netbsd_usb.c
|
||||
)
|
||||
set(OS_NETBSD TRUE)
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/openbsd_usb.c
|
||||
)
|
||||
set(OS_OPENBSD TRUE)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/poll_posix.c
|
||||
libusb/libusb/os/threads_posix.c
|
||||
)
|
||||
find_package(Threads REQUIRED)
|
||||
if(THREADS_HAVE_PTHREAD_ARG)
|
||||
target_compile_options(usb PUBLIC "-pthread")
|
||||
endif()
|
||||
if(CMAKE_THREAD_LIBS_INIT)
|
||||
target_link_libraries(usb PRIVATE "${CMAKE_THREAD_LIBS_INIT}")
|
||||
endif()
|
||||
set(THREADS_POSIX TRUE)
|
||||
elseif(WIN32)
|
||||
target_sources(usb PRIVATE
|
||||
libusb/libusb/os/poll_windows.c
|
||||
libusb/libusb/os/threads_windows.c
|
||||
)
|
||||
endif()
|
||||
|
||||
include(CheckFunctionExists)
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckTypeSize)
|
||||
check_include_files(asm/types.h HAVE_ASM_TYPES_H)
|
||||
check_function_exists(gettimeofday HAVE_GETTIMEOFDAY)
|
||||
check_include_files(linux/filter.h HAVE_LINUX_FILTER_H)
|
||||
check_include_files(linux/netlink.h HAVE_LINUX_NETLINK_H)
|
||||
check_include_files(poll.h HAVE_POLL_H)
|
||||
check_include_files(signal.h HAVE_SIGNAL_H)
|
||||
check_include_files(strings.h HAVE_STRINGS_H)
|
||||
check_type_size("struct timespec" STRUCT_TIMESPEC)
|
||||
check_function_exists(syslog HAVE_SYSLOG_FUNC)
|
||||
check_include_files(syslog.h HAVE_SYSLOG_H)
|
||||
check_include_files(sys/socket.h HAVE_SYS_SOCKET_H)
|
||||
check_include_files(sys/time.h HAVE_SYS_TIME_H)
|
||||
check_include_files(sys/types.h HAVE_SYS_TYPES_H)
|
||||
|
||||
set(CMAKE_EXTRA_INCLUDE_FILES poll.h)
|
||||
check_type_size("nfds_t" nfds_t)
|
||||
unset(CMAKE_EXTRA_INCLUDE_FILES)
|
||||
if(HAVE_NFDS_T)
|
||||
set(POLL_NFDS_TYPE "nfds_t")
|
||||
else()
|
||||
set(POLL_NFDS_TYPE "unsigned int")
|
||||
endif()
|
||||
|
||||
check_include_files(sys/timerfd.h USBI_TIMERFD_AVAILABLE)
|
||||
|
||||
|
||||
configure_file(config.h.in config.h)
|
90
externals/libusb/config.h.in
vendored
90
externals/libusb/config.h.in
vendored
@ -1,90 +0,0 @@
|
||||
/* Default visibility */
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define DEFAULT_VISIBILITY __attribute__((visibility("default")))
|
||||
#elif defined(_MSC_VER)
|
||||
#define DEFAULT_VISIBILITY __declspec(dllexport)
|
||||
#endif
|
||||
|
||||
/* Start with debug message logging enabled */
|
||||
#undef ENABLE_DEBUG_LOGGING
|
||||
|
||||
/* Message logging */
|
||||
#undef ENABLE_LOGGING
|
||||
|
||||
/* Define to 1 if you have the <asm/types.h> header file. */
|
||||
#cmakedefine HAVE_ASM_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#cmakedefine HAVE_GETTIMEOFDAY 1
|
||||
|
||||
/* Define to 1 if you have the `udev' library (-ludev). */
|
||||
#cmakedefine HAVE_LIBUDEV 1
|
||||
|
||||
/* Define to 1 if you have the <linux/filter.h> header file. */
|
||||
#cmakedefine HAVE_LINUX_FILTER_H 1
|
||||
|
||||
/* Define to 1 if you have the <linux/netlink.h> header file. */
|
||||
#cmakedefine HAVE_LINUX_NETLINK_H 1
|
||||
|
||||
/* Define to 1 if you have the <poll.h> header file. */
|
||||
#cmakedefine HAVE_POLL_H 1
|
||||
|
||||
/* Define to 1 if you have the <signal.h> header file. */
|
||||
#cmakedefine HAVE_SIGNAL_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#cmakedefine HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if the system has the type `struct timespec'. */
|
||||
#cmakedefine HAVE_STRUCT_TIMESPEC 1
|
||||
|
||||
/* syslog() function available */
|
||||
#cmakedefine HAVE_SYSLOG_FUNC 1
|
||||
|
||||
/* Define to 1 if you have the <syslog.h> header file. */
|
||||
#cmakedefine HAVE_SYSLOG_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#cmakedefine HAVE_SYS_SOCKET_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#cmakedefine HAVE_SYS_TIME_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#cmakedefine HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Darwin backend */
|
||||
#cmakedefine OS_DARWIN 1
|
||||
|
||||
/* Linux backend */
|
||||
#cmakedefine OS_LINUX 1
|
||||
|
||||
/* NetBSD backend */
|
||||
#cmakedefine OS_NETBSD 1
|
||||
|
||||
/* OpenBSD backend */
|
||||
#cmakedefine OS_OPENBSD 1
|
||||
|
||||
/* Windows backend */
|
||||
#cmakedefine OS_WINDOWS 1
|
||||
|
||||
/* type of second poll() argument */
|
||||
#define POLL_NFDS_TYPE @POLL_NFDS_TYPE@
|
||||
|
||||
/* Use POSIX Threads */
|
||||
#cmakedefine THREADS_POSIX
|
||||
|
||||
/* timerfd headers available */
|
||||
#cmakedefine USBI_TIMERFD_AVAILABLE 1
|
||||
|
||||
/* Enable output to system log */
|
||||
#define USE_SYSTEM_LOGGING_FACILITY 1
|
||||
|
||||
/* Use udev for device enumeration/hotplug */
|
||||
#cmakedefine USE_UDEV 1
|
||||
|
||||
/* Use GNU extensions */
|
||||
#define _GNU_SOURCE
|
||||
|
||||
/* Oldest Windows version supported */
|
||||
#define WINVER 0x0501
|
1
externals/libusb/libusb
vendored
1
externals/libusb/libusb
vendored
Submodule externals/libusb/libusb deleted from e782eeb251
1
externals/libyuv
vendored
1
externals/libyuv
vendored
Submodule externals/libyuv deleted from 19d71f6b35
7
externals/lodepng/CMakeLists.txt
vendored
7
externals/lodepng/CMakeLists.txt
vendored
@ -1,7 +0,0 @@
|
||||
add_library(lodepng
|
||||
lodepng/lodepng.cpp
|
||||
lodepng/lodepng.h
|
||||
)
|
||||
|
||||
create_target_directory_groups(lodepng)
|
||||
target_include_directories(lodepng INTERFACE lodepng)
|
1
externals/lodepng/lodepng
vendored
1
externals/lodepng/lodepng
vendored
Submodule externals/lodepng/lodepng deleted from 31d9704fdc
4
externals/microprofile/microprofile.h
vendored
4
externals/microprofile/microprofile.h
vendored
@ -832,7 +832,7 @@ struct MicroProfile
|
||||
#define MP_LOG_LEAVE 0x0
|
||||
|
||||
|
||||
inline int MicroProfileLogType(MicroProfileLogEntry Index)
|
||||
inline uint64_t MicroProfileLogType(MicroProfileLogEntry Index)
|
||||
{
|
||||
return ((MP_LOG_BEGIN_MASK & Index)>>62) & 0x3;
|
||||
}
|
||||
@ -845,7 +845,7 @@ inline uint64_t MicroProfileLogTimerIndex(MicroProfileLogEntry Index)
|
||||
inline MicroProfileLogEntry MicroProfileMakeLogIndex(uint64_t nBegin, MicroProfileToken nToken, int64_t nTick)
|
||||
{
|
||||
MicroProfileLogEntry Entry = (nBegin<<62) | ((0x3fff&nToken)<<48) | (MP_LOG_TICK_MASK&nTick);
|
||||
int t = MicroProfileLogType(Entry);
|
||||
uint64_t t = MicroProfileLogType(Entry);
|
||||
uint64_t nTimerIndex = MicroProfileLogTimerIndex(Entry);
|
||||
MP_ASSERT(t == nBegin);
|
||||
MP_ASSERT(nTimerIndex == (nToken&0x3fff));
|
||||
|
1
externals/vcpkg
vendored
Submodule
1
externals/vcpkg
vendored
Submodule
Submodule externals/vcpkg added at d293ac220d
1
externals/vma
vendored
Submodule
1
externals/vma
vendored
Submodule
Submodule externals/vma added at 5ab8c1752a
1
externals/xbyak
vendored
1
externals/xbyak
vendored
Submodule externals/xbyak deleted from c306b8e578
1
externals/zstd
vendored
1
externals/zstd
vendored
Submodule externals/zstd deleted from 97a3da1df0
@ -67,7 +67,7 @@ elseif(ENABLE_FDK)
|
||||
hle/fdk_decoder.cpp
|
||||
hle/fdk_decoder.h
|
||||
)
|
||||
target_link_libraries(audio_core PRIVATE ${FDK_AAC})
|
||||
target_link_libraries(audio_core PRIVATE FDK-AAC::fdk-aac)
|
||||
target_compile_definitions(audio_core PUBLIC HAVE_FDK)
|
||||
endif()
|
||||
|
||||
@ -80,7 +80,7 @@ if(ANDROID)
|
||||
endif()
|
||||
|
||||
if(SDL2_FOUND)
|
||||
target_link_libraries(audio_core PRIVATE SDL2)
|
||||
target_link_libraries(audio_core PRIVATE SDL2::SDL2)
|
||||
target_compile_definitions(audio_core PRIVATE HAVE_SDL2)
|
||||
endif()
|
||||
|
||||
|
@ -450,7 +450,7 @@ void DspLle::SetServiceToInterrupt(std::weak_ptr<Service::DSP::DSP_DSP> dsp) {
|
||||
return;
|
||||
if (pipe == 0) {
|
||||
// pipe 0 is for debug. 3DS automatically drains this pipe and discards the data
|
||||
impl->ReadPipe(pipe, impl->GetPipeReadableSize(pipe));
|
||||
impl->ReadPipe(static_cast<u8>(pipe), impl->GetPipeReadableSize(pipe));
|
||||
} else {
|
||||
std::lock_guard lock(HLE::g_hle_lock);
|
||||
if (auto locked = dsp.lock()) {
|
||||
|
@ -16,11 +16,11 @@ add_executable(citra
|
||||
create_target_directory_groups(citra)
|
||||
|
||||
target_link_libraries(citra PRIVATE common core input_common network)
|
||||
target_link_libraries(citra PRIVATE inih glad lodepng)
|
||||
target_link_libraries(citra PRIVATE inih nihstro-headers glad::glad lodepng)
|
||||
if (MSVC)
|
||||
target_link_libraries(citra PRIVATE getopt)
|
||||
endif()
|
||||
target_link_libraries(citra PRIVATE ${PLATFORM_LIBRARIES} SDL2 Threads::Threads)
|
||||
target_link_libraries(citra PRIVATE ${PLATFORM_LIBRARIES} SDL2::SDL2 Threads::Threads)
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
install(TARGETS citra RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
|
||||
|
@ -43,7 +43,9 @@
|
||||
#include "core/movie.h"
|
||||
#include "core/settings.h"
|
||||
#include "network/network.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/common/renderer.h"
|
||||
#include "video_core/common/rasterizer.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
#undef _UNICODE
|
||||
#include <getopt.h>
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "input_common/motion_emu.h"
|
||||
#include "input_common/sdl/sdl.h"
|
||||
#include "network/network.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/common/renderer.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
SharedContext_SDL2::SharedContext_SDL2() {
|
||||
|
@ -259,8 +259,11 @@ endif()
|
||||
create_target_directory_groups(citra-qt)
|
||||
|
||||
target_link_libraries(citra-qt PRIVATE audio_core common core input_common network video_core)
|
||||
target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt5::Widgets Qt5::Multimedia)
|
||||
target_link_libraries(citra-qt PRIVATE Boost::boost glad::glad nihstro-headers Qt5::Widgets Qt5::Multimedia)
|
||||
target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
target_include_directories(citra-qt PRIVATE ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
target_compile_definitions(citra-qt PRIVATE
|
||||
# Use QStringBuilder for string concatenation to reduce
|
||||
|
@ -7,9 +7,9 @@
|
||||
#include <QHBoxLayout>
|
||||
#include <QKeyEvent>
|
||||
#include <QOffscreenSurface>
|
||||
#include <glad/glad.h>
|
||||
#include <QOpenGLContext>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QOpenGLFunctions_3_3_Core>
|
||||
#include <QMessageBox>
|
||||
#include <fmt/format.h>
|
||||
#include "citra_qt/bootmanager.h"
|
||||
#include "citra_qt/main.h"
|
||||
@ -24,9 +24,15 @@
|
||||
#include "input_common/main.h"
|
||||
#include "input_common/motion_emu.h"
|
||||
#include "network/network.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/common/rasterizer.h"
|
||||
#include "video_core/common/pipeline_cache.h"
|
||||
#include "video_core/common/renderer.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
#if !defined(WIN32)
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#endif
|
||||
|
||||
EmuThread::EmuThread(Frontend::GraphicsContext& core_context) : core_context(core_context) {}
|
||||
|
||||
EmuThread::~EmuThread() = default;
|
||||
@ -52,6 +58,7 @@ void EmuThread::run() {
|
||||
});
|
||||
|
||||
emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
|
||||
emit HideLoadingScreen();
|
||||
|
||||
if (Core::System::GetInstance().frame_limiter.IsFrameAdvancing()) {
|
||||
// Usually the loading screen is hidden after the first frame is drawn. In this case
|
||||
@ -89,7 +96,12 @@ void EmuThread::run() {
|
||||
emit DebugModeLeft();
|
||||
|
||||
exec_step = false;
|
||||
Core::System::GetInstance().SingleStep();
|
||||
const auto result = Core::System::GetInstance().SingleStep();
|
||||
if (result != Core::System::ResultStatus::Success) {
|
||||
this->SetRunning(false);
|
||||
emit ErrorThrown(result, Core::System::GetInstance().GetStatusDetails());
|
||||
}
|
||||
|
||||
emit DebugModeEntered();
|
||||
yieldCurrentThread();
|
||||
|
||||
@ -108,87 +120,163 @@ void EmuThread::run() {
|
||||
#endif
|
||||
}
|
||||
|
||||
OpenGLWindow::OpenGLWindow(QWindow* parent, QWidget* event_handler, QOpenGLContext* shared_context)
|
||||
: QWindow(parent), context(std::make_unique<QOpenGLContext>(shared_context->parent())),
|
||||
event_handler(event_handler) {
|
||||
class DummyContext : public Frontend::GraphicsContext {};
|
||||
|
||||
// disable vsync for any shared contexts
|
||||
auto format = shared_context->format();
|
||||
format.setSwapInterval(Settings::values.use_vsync_new ? 1 : 0);
|
||||
this->setFormat(format);
|
||||
class OpenGLSharedContext : public Frontend::GraphicsContext {
|
||||
public:
|
||||
/// Create the original context that should be shared from
|
||||
explicit OpenGLSharedContext(QSurface* surface) : surface(surface) {
|
||||
QSurfaceFormat format;
|
||||
format.setVersion(4, 6);
|
||||
format.setProfile(QSurfaceFormat::CompatibilityProfile);
|
||||
format.setOption(QSurfaceFormat::FormatOption::DeprecatedFunctions);
|
||||
format.setOption(QSurfaceFormat::FormatOption::DebugContext);
|
||||
|
||||
context->setShareContext(shared_context);
|
||||
context->setScreen(this->screen());
|
||||
context->setFormat(format);
|
||||
context->create();
|
||||
// TODO: expose a setting for buffer value (ie default/single/double/triple)
|
||||
format.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior);
|
||||
format.setSwapInterval(0);
|
||||
|
||||
setSurfaceType(QWindow::OpenGLSurface);
|
||||
|
||||
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
|
||||
// WA_DontShowOnScreen, WA_DeleteOnClose
|
||||
}
|
||||
|
||||
OpenGLWindow::~OpenGLWindow() {
|
||||
context->doneCurrent();
|
||||
}
|
||||
|
||||
void OpenGLWindow::Present() {
|
||||
if (!isExposed())
|
||||
return;
|
||||
|
||||
context->makeCurrent(this);
|
||||
if (VideoCore::g_renderer) {
|
||||
VideoCore::g_renderer->TryPresent(100);
|
||||
context = std::make_unique<QOpenGLContext>();
|
||||
context->setFormat(format);
|
||||
if (!context->create()) {
|
||||
LOG_ERROR(Frontend, "Unable to create main openGL context");
|
||||
}
|
||||
}
|
||||
context->swapBuffers(this);
|
||||
auto f = context->versionFunctions<QOpenGLFunctions_3_3_Core>();
|
||||
f->glFinish();
|
||||
QWindow::requestUpdate();
|
||||
}
|
||||
|
||||
bool OpenGLWindow::event(QEvent* event) {
|
||||
switch (event->type()) {
|
||||
case QEvent::UpdateRequest:
|
||||
Present();
|
||||
return true;
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::MouseButtonDblClick:
|
||||
case QEvent::MouseMove:
|
||||
case QEvent::KeyPress:
|
||||
case QEvent::KeyRelease:
|
||||
case QEvent::FocusIn:
|
||||
case QEvent::FocusOut:
|
||||
case QEvent::FocusAboutToChange:
|
||||
case QEvent::Enter:
|
||||
case QEvent::Leave:
|
||||
case QEvent::Wheel:
|
||||
case QEvent::TabletMove:
|
||||
case QEvent::TabletPress:
|
||||
case QEvent::TabletRelease:
|
||||
case QEvent::TabletEnterProximity:
|
||||
case QEvent::TabletLeaveProximity:
|
||||
case QEvent::TouchBegin:
|
||||
case QEvent::TouchUpdate:
|
||||
case QEvent::TouchEnd:
|
||||
case QEvent::InputMethodQuery:
|
||||
case QEvent::TouchCancel:
|
||||
return QCoreApplication::sendEvent(event_handler, event);
|
||||
case QEvent::Drop:
|
||||
GetMainWindow()->DropAction(static_cast<QDropEvent*>(event));
|
||||
return true;
|
||||
case QEvent::DragEnter:
|
||||
case QEvent::DragMove:
|
||||
GetMainWindow()->AcceptDropEvent(static_cast<QDropEvent*>(event));
|
||||
return true;
|
||||
default:
|
||||
return QWindow::event(event);
|
||||
/// Create the shared contexts for rendering and presentation
|
||||
explicit OpenGLSharedContext(QOpenGLContext* share_context, QSurface* main_surface = nullptr) {
|
||||
|
||||
// disable vsync for any shared contexts
|
||||
auto format = share_context->format();
|
||||
format.setSwapInterval(0);
|
||||
|
||||
context = std::make_unique<QOpenGLContext>();
|
||||
context->setShareContext(share_context);
|
||||
context->setFormat(format);
|
||||
if (!context->create()) {
|
||||
LOG_ERROR(Frontend, "Unable to create shared openGL context");
|
||||
}
|
||||
|
||||
if (!main_surface) {
|
||||
offscreen_surface = std::make_unique<QOffscreenSurface>(nullptr);
|
||||
offscreen_surface->setFormat(format);
|
||||
offscreen_surface->create();
|
||||
surface = offscreen_surface.get();
|
||||
} else {
|
||||
surface = main_surface;
|
||||
}
|
||||
}
|
||||
|
||||
~OpenGLSharedContext() {
|
||||
DoneCurrent();
|
||||
}
|
||||
|
||||
void SwapBuffers() override {
|
||||
context->swapBuffers(surface);
|
||||
}
|
||||
|
||||
void MakeCurrent() override {
|
||||
// We can't track the current state of the underlying context in this wrapper class because
|
||||
// Qt may make the underlying context not current for one reason or another. In particular,
|
||||
// the WebBrowser uses GL, so it seems to conflict if we aren't careful.
|
||||
// Instead of always just making the context current (which does not have any caching to
|
||||
// check if the underlying context is already current) we can check for the current context
|
||||
// in the thread local data by calling `currentContext()` and checking if its ours.
|
||||
if (QOpenGLContext::currentContext() != context.get()) {
|
||||
context->makeCurrent(surface);
|
||||
}
|
||||
}
|
||||
|
||||
void DoneCurrent() override {
|
||||
context->doneCurrent();
|
||||
}
|
||||
|
||||
QOpenGLContext* GetShareContext() {
|
||||
return context.get();
|
||||
}
|
||||
|
||||
const QOpenGLContext* GetShareContext() const {
|
||||
return context.get();
|
||||
}
|
||||
|
||||
private:
|
||||
// Avoid using Qt parent system here since we might move the QObjects to new threads
|
||||
// As a note, this means we should avoid using slots/signals with the objects too
|
||||
std::unique_ptr<QOpenGLContext> context;
|
||||
std::unique_ptr<QOffscreenSurface> offscreen_surface{};
|
||||
QSurface* surface;
|
||||
};
|
||||
|
||||
class RenderWidget : public QWidget {
|
||||
public:
|
||||
explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) {
|
||||
setAttribute(Qt::WA_NativeWindow);
|
||||
setAttribute(Qt::WA_PaintOnScreen);
|
||||
}
|
||||
|
||||
virtual ~RenderWidget() = default;
|
||||
|
||||
QPaintEngine* paintEngine() const override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
GRenderWindow* render_window;
|
||||
};
|
||||
|
||||
class OpenGLRenderWidget : public RenderWidget {
|
||||
public:
|
||||
explicit OpenGLRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {
|
||||
windowHandle()->setSurfaceType(QWindow::OpenGLSurface);
|
||||
}
|
||||
|
||||
void SetContext(std::unique_ptr<Frontend::GraphicsContext>&& context_) {
|
||||
context = std::move(context_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Frontend::GraphicsContext> context;
|
||||
};
|
||||
|
||||
class VulkanRenderWidget : public RenderWidget {
|
||||
public:
|
||||
explicit VulkanRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {
|
||||
windowHandle()->setSurfaceType(QWindow::VulkanSurface);
|
||||
}
|
||||
};
|
||||
|
||||
static Frontend::WindowSystemType GetWindowSystemType() {
|
||||
// Determine WSI type based on Qt platform.
|
||||
QString platform_name = QGuiApplication::platformName();
|
||||
if (platform_name == QStringLiteral("windows"))
|
||||
return Frontend::WindowSystemType::Windows;
|
||||
else if (platform_name == QStringLiteral("xcb"))
|
||||
return Frontend::WindowSystemType::X11;
|
||||
else if (platform_name == QStringLiteral("wayland"))
|
||||
return Frontend::WindowSystemType::Wayland;
|
||||
|
||||
LOG_CRITICAL(Frontend, "Unknown Qt platform!");
|
||||
return Frontend::WindowSystemType::Windows;
|
||||
}
|
||||
|
||||
void OpenGLWindow::exposeEvent(QExposeEvent* event) {
|
||||
QWindow::requestUpdate();
|
||||
QWindow::exposeEvent(event);
|
||||
static Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) {
|
||||
Frontend::EmuWindow::WindowSystemInfo wsi;
|
||||
wsi.type = GetWindowSystemType();
|
||||
|
||||
// Our Win32 Qt external doesn't have the private API.
|
||||
#if defined(WIN32) || defined(__APPLE__)
|
||||
wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
|
||||
#else
|
||||
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
|
||||
wsi.display_connection = pni->nativeResourceForWindow("display", window);
|
||||
if (wsi.type == Frontend::WindowSystemType::Wayland)
|
||||
wsi.render_surface = window ? pni->nativeResourceForWindow("surface", window) : nullptr;
|
||||
else
|
||||
wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
|
||||
#endif
|
||||
wsi.render_surface_scale = window ? static_cast<float>(window->devicePixelRatio()) : 1.0f;
|
||||
|
||||
return wsi;
|
||||
}
|
||||
|
||||
GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread)
|
||||
@ -215,11 +303,11 @@ GRenderWindow::~GRenderWindow() {
|
||||
}
|
||||
|
||||
void GRenderWindow::MakeCurrent() {
|
||||
core_context->MakeCurrent();
|
||||
main_context->MakeCurrent();
|
||||
}
|
||||
|
||||
void GRenderWindow::DoneCurrent() {
|
||||
core_context->DoneCurrent();
|
||||
main_context->DoneCurrent();
|
||||
}
|
||||
|
||||
void GRenderWindow::PollEvents() {
|
||||
@ -384,25 +472,51 @@ void GRenderWindow::resizeEvent(QResizeEvent* event) {
|
||||
OnFramebufferSizeChanged();
|
||||
}
|
||||
|
||||
void GRenderWindow::InitRenderTarget() {
|
||||
bool GRenderWindow::InitRenderTarget() {
|
||||
ReleaseRenderTarget();
|
||||
|
||||
{
|
||||
// Create a dummy render widget so that Qt
|
||||
// places the render window at the correct position.
|
||||
const RenderWidget dummy_widget{this};
|
||||
}
|
||||
|
||||
first_frame = false;
|
||||
|
||||
GMainWindow* parent = GetMainWindow();
|
||||
QWindow* parent_win_handle = parent ? parent->windowHandle() : nullptr;
|
||||
child_window = new OpenGLWindow(parent_win_handle, this, QOpenGLContext::globalShareContext());
|
||||
child_window->create();
|
||||
child_widget = createWindowContainer(child_window, this);
|
||||
switch (Settings::values.renderer_backend) {
|
||||
case Settings::RendererBackend::OpenGL:
|
||||
if (!InitializeOpenGL()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Settings::RendererBackend::Vulkan:
|
||||
if (!InitializeVulkan()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
child_widget->resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight);
|
||||
|
||||
layout()->addWidget(child_widget);
|
||||
// Reset minimum required size to avoid resizing issues on the main window after restarting.
|
||||
setMinimumSize(1, 1);
|
||||
|
||||
core_context = CreateSharedContext();
|
||||
resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight);
|
||||
|
||||
// Update the Window System information with the new render target
|
||||
window_info = GetWindowSystemInfo(child_widget->windowHandle());
|
||||
|
||||
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
|
||||
OnFramebufferSizeChanged();
|
||||
BackupGeometry();
|
||||
|
||||
if (Settings::values.renderer_backend == Settings::RendererBackend::OpenGL) {
|
||||
if (!LoadOpenGL()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GRenderWindow::ReleaseRenderTarget() {
|
||||
@ -413,6 +527,54 @@ void GRenderWindow::ReleaseRenderTarget() {
|
||||
}
|
||||
}
|
||||
|
||||
bool GRenderWindow::InitializeOpenGL() {
|
||||
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
|
||||
// WA_DontShowOnScreen, WA_DeleteOnClose
|
||||
auto child = new OpenGLRenderWidget(this);
|
||||
child_widget = child;
|
||||
child_widget->windowHandle()->create();
|
||||
auto context = std::make_shared<OpenGLSharedContext>(child->windowHandle());
|
||||
main_context = context;
|
||||
child->SetContext(
|
||||
std::make_unique<OpenGLSharedContext>(context->GetShareContext(), child->windowHandle()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GRenderWindow::InitializeVulkan() {
|
||||
auto child = new VulkanRenderWidget(this);
|
||||
child_widget = child;
|
||||
child_widget->windowHandle()->create();
|
||||
main_context = std::make_unique<DummyContext>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GRenderWindow::LoadOpenGL() {
|
||||
auto context = CreateSharedContext();
|
||||
auto scope = context->Acquire();
|
||||
if (!gladLoadGL()) {
|
||||
QMessageBox::warning(
|
||||
this, tr("Error while initializing OpenGL!"),
|
||||
tr("Your GPU may not support OpenGL, or you do not have the latest graphics driver."));
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString renderer =
|
||||
QString::fromUtf8(reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
|
||||
|
||||
if (!GLAD_GL_ES_VERSION_3_2) {
|
||||
LOG_ERROR(Frontend, "GPU does not support OpenGL ES 3.2: {}", renderer.toStdString());
|
||||
QMessageBox::warning(this, tr("Error while initializing OpenGL ES 3.2!"),
|
||||
tr("Your GPU may not support OpenGL ES 3.2, or you do not have the "
|
||||
"latest graphics driver.<br><br>GL Renderer:<br>%1")
|
||||
.arg(renderer));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) {
|
||||
if (res_scale == 0)
|
||||
res_scale = VideoCore::GetResolutionScaleFactor();
|
||||
@ -448,29 +610,13 @@ void GRenderWindow::showEvent(QShowEvent* event) {
|
||||
}
|
||||
|
||||
std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
|
||||
return std::make_unique<GLContext>(QOpenGLContext::globalShareContext());
|
||||
}
|
||||
|
||||
GLContext::GLContext(QOpenGLContext* shared_context)
|
||||
: context(std::make_unique<QOpenGLContext>(shared_context->parent())),
|
||||
surface(std::make_unique<QOffscreenSurface>(nullptr)) {
|
||||
|
||||
// disable vsync for any shared contexts
|
||||
auto format = shared_context->format();
|
||||
format.setSwapInterval(0);
|
||||
|
||||
context->setShareContext(shared_context);
|
||||
context->setFormat(format);
|
||||
context->create();
|
||||
surface->setParent(shared_context->parent());
|
||||
surface->setFormat(format);
|
||||
surface->create();
|
||||
}
|
||||
|
||||
void GLContext::MakeCurrent() {
|
||||
context->makeCurrent(surface.get());
|
||||
}
|
||||
|
||||
void GLContext::DoneCurrent() {
|
||||
context->doneCurrent();
|
||||
if (Settings::values.renderer_backend == Settings::RendererBackend::OpenGL) {
|
||||
auto c = static_cast<OpenGLSharedContext*>(main_context.get());
|
||||
// Bind the shared contexts to the main surface in case the backend wants to take over
|
||||
// presentation
|
||||
return std::make_unique<OpenGLSharedContext>(c->GetShareContext(),
|
||||
child_widget->windowHandle());
|
||||
}
|
||||
|
||||
return std::make_unique<DummyContext>();
|
||||
}
|
||||
|
@ -24,22 +24,9 @@ class GMainWindow;
|
||||
class GRenderWindow;
|
||||
|
||||
namespace VideoCore {
|
||||
enum class LoadCallbackStage;
|
||||
enum class LoadCallbackStage : u8;
|
||||
}
|
||||
|
||||
class GLContext : public Frontend::GraphicsContext {
|
||||
public:
|
||||
explicit GLContext(QOpenGLContext* shared_context);
|
||||
|
||||
void MakeCurrent() override;
|
||||
|
||||
void DoneCurrent() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<QOpenGLContext> context;
|
||||
std::unique_ptr<QOffscreenSurface> surface;
|
||||
};
|
||||
|
||||
class EmuThread final : public QThread {
|
||||
Q_OBJECT
|
||||
|
||||
@ -126,24 +113,6 @@ signals:
|
||||
void HideLoadingScreen();
|
||||
};
|
||||
|
||||
class OpenGLWindow : public QWindow {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OpenGLWindow(QWindow* parent, QWidget* event_handler, QOpenGLContext* shared_context);
|
||||
|
||||
~OpenGLWindow();
|
||||
|
||||
void Present();
|
||||
|
||||
protected:
|
||||
bool event(QEvent* event) override;
|
||||
void exposeEvent(QExposeEvent* event) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<QOpenGLContext> context;
|
||||
QWidget* event_handler;
|
||||
};
|
||||
|
||||
class GRenderWindow : public QWidget, public Frontend::EmuWindow {
|
||||
Q_OBJECT
|
||||
|
||||
@ -179,7 +148,7 @@ public:
|
||||
|
||||
void focusOutEvent(QFocusEvent* event) override;
|
||||
|
||||
void InitRenderTarget();
|
||||
bool InitRenderTarget();
|
||||
|
||||
/// Destroy the previous run's child_widget which should also destroy the child_window
|
||||
void ReleaseRenderTarget();
|
||||
@ -212,13 +181,13 @@ private:
|
||||
|
||||
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
|
||||
|
||||
std::unique_ptr<GraphicsContext> core_context;
|
||||
bool LoadOpenGL();
|
||||
bool InitializeOpenGL();
|
||||
bool InitializeVulkan();
|
||||
|
||||
std::shared_ptr<Frontend::GraphicsContext> main_context;
|
||||
QByteArray geometry;
|
||||
|
||||
/// Native window handle that backs this presentation widget
|
||||
QWindow* child_window = nullptr;
|
||||
|
||||
/// In order to embed the window into GRenderWindow, you need to use createWindowContainer to
|
||||
/// put the child_window into a widget then add it to the layout. This child_widget can be
|
||||
/// parented to GRenderWindow and use Qt's lifetime system
|
||||
|
@ -49,9 +49,10 @@ CheatDialog::~CheatDialog() = default;
|
||||
void CheatDialog::LoadCheats() {
|
||||
cheats = Core::System::GetInstance().CheatEngine().GetCheats();
|
||||
|
||||
ui->tableCheats->setRowCount(cheats.size());
|
||||
int cheat_count = static_cast<int>(cheats.size());
|
||||
ui->tableCheats->setRowCount(cheat_count);
|
||||
|
||||
for (size_t i = 0; i < cheats.size(); i++) {
|
||||
for (int i = 0; i < cheat_count; i++) {
|
||||
QCheckBox* enabled = new QCheckBox();
|
||||
enabled->setChecked(cheats[i]->IsEnabled());
|
||||
enabled->setStyleSheet(QStringLiteral("margin-left:7px;"));
|
||||
|
@ -944,14 +944,14 @@ void Config::SaveMultiplayerValues() {
|
||||
// Write ban list
|
||||
qt_config->beginWriteArray(QStringLiteral("username_ban_list"));
|
||||
for (std::size_t i = 0; i < UISettings::values.ban_list.first.size(); ++i) {
|
||||
qt_config->setArrayIndex(i);
|
||||
qt_config->setArrayIndex(static_cast<int>(i));
|
||||
WriteSetting(QStringLiteral("username"),
|
||||
QString::fromStdString(UISettings::values.ban_list.first[i]));
|
||||
}
|
||||
qt_config->endArray();
|
||||
qt_config->beginWriteArray(QStringLiteral("ip_ban_list"));
|
||||
for (std::size_t i = 0; i < UISettings::values.ban_list.second.size(); ++i) {
|
||||
qt_config->setArrayIndex(i);
|
||||
qt_config->setArrayIndex(static_cast<int>(i));
|
||||
WriteSetting(QStringLiteral("ip"),
|
||||
QString::fromStdString(UISettings::values.ban_list.second[i]));
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ void ConfigureCamera::SetConfiguration() {
|
||||
int index = GetSelectedCameraIndex();
|
||||
for (std::size_t i = 0; i < Implementations.size(); i++) {
|
||||
if (Implementations[i] == camera_name[index]) {
|
||||
ui->image_source->setCurrentIndex(i);
|
||||
ui->image_source->setCurrentIndex(static_cast<int>(i));
|
||||
}
|
||||
}
|
||||
if (camera_name[index] == "image") {
|
||||
|
@ -14,8 +14,8 @@ ConfigureEnhancements::ConfigureEnhancements(QWidget* parent)
|
||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureEnhancements>()) {
|
||||
ui->setupUi(this);
|
||||
|
||||
for (const auto& filter : OpenGL::TextureFilterer::GetFilterNames())
|
||||
ui->texture_filter_combobox->addItem(QString::fromStdString(filter.data()));
|
||||
//for (const auto& filter : OpenGL::TextureFilterer::GetFilterNames())
|
||||
// ui->texture_filter_combobox->addItem(QString::fromStdString(filter.data()));
|
||||
|
||||
SetConfiguration();
|
||||
|
||||
@ -89,12 +89,12 @@ void ConfigureEnhancements::updateShaders(Settings::StereoRenderOption stereo_op
|
||||
|
||||
ui->shader_combobox->setCurrentIndex(0);
|
||||
|
||||
for (const auto& shader : OpenGL::GetPostProcessingShaderList(
|
||||
/*for (const auto& shader : OpenGL::GetPostProcessingShaderList(
|
||||
stereo_option == Settings::StereoRenderOption::Anaglyph)) {
|
||||
ui->shader_combobox->addItem(QString::fromStdString(shader));
|
||||
if (Settings::values.pp_shader_name == shader)
|
||||
ui->shader_combobox->setCurrentIndex(ui->shader_combobox->count() - 1);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void ConfigureEnhancements::RetranslateUI() {
|
||||
|
@ -76,7 +76,7 @@ void IPCRecorderWidget::OnEntryUpdated(IPCDebugger::RequestRecord record) {
|
||||
QTreeWidgetItem entry{
|
||||
{QString::number(record.id), GetStatusStr(record), service, GetFunctionName(record)}};
|
||||
|
||||
const int row_id = record.id - id_offset;
|
||||
const std::size_t row_id = record.id - id_offset;
|
||||
if (ui->main->invisibleRootItem()->childCount() > row_id) {
|
||||
records[row_id] = record;
|
||||
(*ui->main->invisibleRootItem()->child(row_id)) = entry;
|
||||
|
@ -45,7 +45,7 @@ private:
|
||||
// The offset between record id and row id, assuming record ids are assigned
|
||||
// continuously and only the 'Clear' action can be performed, this is enough.
|
||||
// The initial value is 1, which means record 1 = row 0.
|
||||
int id_offset = 1;
|
||||
std::size_t id_offset = 1;
|
||||
std::vector<IPCDebugger::RequestRecord> records;
|
||||
};
|
||||
|
||||
|
@ -579,8 +579,8 @@ void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) {
|
||||
void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
|
||||
const int game_dir_index = selected.data(GameListDir::GameDirRole).toInt();
|
||||
|
||||
QAction* move_up = context_menu.addAction(tr(u8"\U000025b2 Move Up"));
|
||||
QAction* move_down = context_menu.addAction(tr(u8"\U000025bc Move Down "));
|
||||
QAction* move_up = context_menu.addAction(tr("Move Up"));
|
||||
QAction* move_down = context_menu.addAction(tr("Move Down"));
|
||||
QAction* open_directory_location = context_menu.addAction(tr("Open Directory Location"));
|
||||
|
||||
const int row = selected.row();
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/loader/smdh.h"
|
||||
#include "ui_loading_screen.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "video_core/common/pipeline_cache.h"
|
||||
|
||||
constexpr char PROGRESSBAR_STYLE_PREPARE[] = R"(
|
||||
QProgressBar {}
|
||||
|
@ -17,7 +17,7 @@ class LoadingScreen;
|
||||
}
|
||||
|
||||
namespace VideoCore {
|
||||
enum class LoadCallbackStage;
|
||||
enum class LoadCallbackStage : unsigned char;
|
||||
}
|
||||
|
||||
class QGraphicsOpacityEffect;
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include <QFutureWatcher>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QOpenGLFunctions_3_3_Core>
|
||||
#include <QSysInfo>
|
||||
#include <QtConcurrent/QtConcurrentRun>
|
||||
#include <QtGui>
|
||||
@ -764,7 +763,7 @@ void GMainWindow::ConnectMenuEvents() {
|
||||
connect(ui->action_Close_Movie, &QAction::triggered, this, &GMainWindow::OnCloseMovie);
|
||||
connect(ui->action_Save_Movie, &QAction::triggered, this, &GMainWindow::OnSaveMovie);
|
||||
connect(ui->action_Movie_Read_Only_Mode, &QAction::toggled, this,
|
||||
[this](bool checked) { Core::Movie::GetInstance().SetReadOnly(checked); });
|
||||
[](bool checked) { Core::Movie::GetInstance().SetReadOnly(checked); });
|
||||
connect(ui->action_Enable_Frame_Advancing, &QAction::triggered, this, [this] {
|
||||
if (emulation_running) {
|
||||
Core::System::GetInstance().frame_limiter.SetFrameAdvancing(
|
||||
@ -911,19 +910,12 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
||||
if (emu_thread != nullptr)
|
||||
ShutdownGame();
|
||||
|
||||
render_window->InitRenderTarget();
|
||||
|
||||
Frontend::ScopeAcquireContext scope(*render_window);
|
||||
|
||||
const QString below_gl33_title = tr("OpenGL 3.3 Unsupported");
|
||||
const QString below_gl33_message = tr("Your GPU may not support OpenGL 3.3, or you do not "
|
||||
"have the latest graphics driver.");
|
||||
|
||||
if (!QOpenGLContext::globalShareContext()->versionFunctions<QOpenGLFunctions_3_3_Core>()) {
|
||||
QMessageBox::critical(this, below_gl33_title, below_gl33_message);
|
||||
if (!render_window->InitRenderTarget()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Frontend::ScopeAcquireContext scope(*render_window);
|
||||
|
||||
Core::System& system{Core::System::GetInstance()};
|
||||
|
||||
const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};
|
||||
@ -990,10 +982,6 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
||||
"proper drivers for your graphics card from the manufacturer's website."));
|
||||
break;
|
||||
|
||||
case Core::System::ResultStatus::ErrorVideoCore_ErrorBelowGL33:
|
||||
QMessageBox::critical(this, below_gl33_title, below_gl33_message);
|
||||
break;
|
||||
|
||||
default:
|
||||
QMessageBox::critical(
|
||||
this, tr("Error while loading ROM!"),
|
||||
@ -1511,7 +1499,7 @@ void GMainWindow::InstallCIA(QStringList filepaths) {
|
||||
const auto cia_progress = [&](std::size_t written, std::size_t total) {
|
||||
emit UpdateProgress(written, total);
|
||||
};
|
||||
for (const auto current_path : filepaths) {
|
||||
for (const auto& current_path : filepaths) {
|
||||
status = Service::AM::InstallCIA(current_path.toStdString(), cia_progress);
|
||||
emit CIAInstallReport(status, current_path);
|
||||
}
|
||||
@ -1963,7 +1951,8 @@ void GMainWindow::OnCaptureScreenshot() {
|
||||
png_dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
png_dialog.setDefaultSuffix(QStringLiteral("png"));
|
||||
if (png_dialog.exec()) {
|
||||
const QString path = png_dialog.selectedFiles().first();
|
||||
const QList selected = png_dialog.selectedFiles();
|
||||
const QString path = selected.first();
|
||||
if (!path.isEmpty()) {
|
||||
UISettings::values.screenshot_path = QFileInfo(path).path();
|
||||
render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, path);
|
||||
@ -2446,8 +2435,6 @@ int main(int argc, char* argv[]) {
|
||||
std::string bin_path = FileUtil::GetBundleDirectory() + DIR_SEP + "..";
|
||||
chdir(bin_path.c_str());
|
||||
#endif
|
||||
QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
|
||||
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
|
||||
QApplication app(argc, argv);
|
||||
|
||||
// Qt changes the locale and causes issues in float conversion using std::to_string() when
|
||||
|
@ -56,9 +56,11 @@ add_library(common STATIC
|
||||
announce_multiplayer_room.h
|
||||
archives.h
|
||||
assert.h
|
||||
atomic_ops.h
|
||||
detached_tasks.cpp
|
||||
detached_tasks.h
|
||||
bit_field.h
|
||||
bit_field_array.h
|
||||
bit_set.h
|
||||
cityhash.cpp
|
||||
cityhash.h
|
||||
@ -69,7 +71,9 @@ add_library(common STATIC
|
||||
construct.h
|
||||
file_util.cpp
|
||||
file_util.h
|
||||
flag.h
|
||||
hash.h
|
||||
intrusive_ptr.h
|
||||
linear_disk_cache.h
|
||||
logging/backend.cpp
|
||||
logging/backend.h
|
||||
@ -85,6 +89,8 @@ add_library(common STATIC
|
||||
microprofile.h
|
||||
microprofileui.h
|
||||
misc.cpp
|
||||
object_pool.cpp
|
||||
object_pool.h
|
||||
param_package.cpp
|
||||
param_package.h
|
||||
quaternion.h
|
||||
@ -92,6 +98,7 @@ add_library(common STATIC
|
||||
scm_rev.cpp
|
||||
scm_rev.h
|
||||
scope_exit.h
|
||||
semaphore.h
|
||||
serialization/atomic.h
|
||||
serialization/boost_discrete_interval.hpp
|
||||
serialization/boost_flat_set.h
|
||||
@ -125,12 +132,18 @@ if(ARCHITECTURE_x86_64)
|
||||
x64/xbyak_abi.h
|
||||
x64/xbyak_util.h
|
||||
)
|
||||
elseif(ARCHITECTURE_arm64)
|
||||
target_sources(common
|
||||
PRIVATE
|
||||
aarch64/cpu_detect.cpp
|
||||
aarch64/cpu_detect.h
|
||||
)
|
||||
endif()
|
||||
|
||||
create_target_directory_groups(common)
|
||||
|
||||
target_link_libraries(common PUBLIC fmt microprofile Boost::boost Boost::serialization)
|
||||
target_link_libraries(common PRIVATE libzstd_static)
|
||||
target_link_libraries(common PUBLIC fmt::fmt microprofile Boost::boost Boost::serialization)
|
||||
target_link_libraries(common PRIVATE zstd::libzstd_shared)
|
||||
if (ARCHITECTURE_x86_64)
|
||||
target_link_libraries(common PRIVATE xbyak)
|
||||
target_link_libraries(common PRIVATE xbyak::xbyak)
|
||||
endif()
|
||||
|
112
src/common/aarch64/cpu_detect.cpp
Normal file
112
src/common/aarch64/cpu_detect.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
// Copyright 2013 Dolphin Emulator Project / 2022 Citra Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#ifdef __APPLE__
|
||||
// clang-format off
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
// clang-format on
|
||||
#elif !defined(_WIN32)
|
||||
#ifndef __FreeBSD__
|
||||
#include <asm/hwcap.h>
|
||||
#endif // __FreeBSD__
|
||||
#include <sys/auxv.h>
|
||||
#include <unistd.h>
|
||||
#endif // __APPLE__
|
||||
|
||||
#include "common/aarch64/cpu_detect.h"
|
||||
#include "common/file_util.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
#ifdef __APPLE__
|
||||
static std::string GetCPUString() {
|
||||
char buf[128];
|
||||
size_t buf_len = sizeof(buf);
|
||||
if (sysctlbyname("machdep.cpu.brand_string", &buf, &buf_len, NULL, 0) == -1) {
|
||||
return "Unknown";
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
#elif !defined(WIN32)
|
||||
static std::string GetCPUString() {
|
||||
constexpr char procfile[] = "/proc/cpuinfo";
|
||||
constexpr char marker[] = "Hardware\t: ";
|
||||
std::string cpu_string = "Unknown";
|
||||
|
||||
std::string line;
|
||||
std::ifstream file;
|
||||
OpenFStream(file, procfile, std::ios_base::in);
|
||||
|
||||
if (!file)
|
||||
return cpu_string;
|
||||
|
||||
while (std::getline(file, line)) {
|
||||
if (line.find(marker) != std::string::npos) {
|
||||
cpu_string = line.substr(strlen(marker));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return cpu_string;
|
||||
}
|
||||
#endif // __APPLE__
|
||||
|
||||
// Detects the various CPU features
|
||||
static CPUCaps Detect() {
|
||||
CPUCaps caps;
|
||||
// Set some defaults here
|
||||
caps.fma = true;
|
||||
caps.afp = false;
|
||||
|
||||
#ifdef __APPLE__
|
||||
// M-series CPUs have all of these
|
||||
caps.fp = true;
|
||||
caps.asimd = true;
|
||||
caps.aes = true;
|
||||
caps.crc32 = true;
|
||||
caps.sha1 = true;
|
||||
caps.sha2 = true;
|
||||
caps.cpu_string = GetCPUString();
|
||||
#elif defined(_WIN32)
|
||||
// Windows does not provide any mechanism for querying the system registers on ARMv8, unlike
|
||||
// Linux which traps the register reads and emulates them in the kernel. There are environment
|
||||
// variables containing some of the CPU-specific values, which we could use for a lookup table
|
||||
// in the future. For now, assume all features are present as all known devices which are
|
||||
// Windows-on-ARM compatible also support these extensions.
|
||||
caps.fp = true;
|
||||
caps.asimd = true;
|
||||
caps.aes = true;
|
||||
caps.crc32 = true;
|
||||
caps.sha1 = true;
|
||||
caps.sha2 = true;
|
||||
#else
|
||||
caps.cpu_string = GetCPUString();
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
u_long hwcaps = 0;
|
||||
elf_aux_info(AT_HWCAP, &hwcaps, sizeof(u_long));
|
||||
#else
|
||||
unsigned long hwcaps = getauxval(AT_HWCAP);
|
||||
#endif // __FreeBSD__
|
||||
caps.fp = hwcaps & HWCAP_FP;
|
||||
caps.asimd = hwcaps & HWCAP_ASIMD;
|
||||
caps.aes = hwcaps & HWCAP_AES;
|
||||
caps.crc32 = hwcaps & HWCAP_CRC32;
|
||||
caps.sha1 = hwcaps & HWCAP_SHA1;
|
||||
caps.sha2 = hwcaps & HWCAP_SHA2;
|
||||
#endif // __APPLE__
|
||||
return caps;
|
||||
}
|
||||
|
||||
const CPUCaps& GetCPUCaps() {
|
||||
static CPUCaps caps = Detect();
|
||||
return caps;
|
||||
}
|
||||
|
||||
} // namespace Common
|
31
src/common/aarch64/cpu_detect.h
Normal file
31
src/common/aarch64/cpu_detect.h
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2013 Dolphin Emulator Project / 2021 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Common {
|
||||
|
||||
/// Arm64 CPU capabilities that may be detected by this module
|
||||
struct CPUCaps {
|
||||
std::string cpu_string;
|
||||
|
||||
bool aes;
|
||||
bool afp; // Alternate floating-point behavior
|
||||
bool asimd;
|
||||
bool crc32;
|
||||
bool fma;
|
||||
bool fp;
|
||||
bool sha1;
|
||||
bool sha2;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the supported capabilities of the host CPU
|
||||
* @return Reference to a CPUCaps struct with the detected host CPU capabilities
|
||||
*/
|
||||
const CPUCaps& GetCPUCaps();
|
||||
|
||||
} // namespace Common
|
@ -10,7 +10,7 @@ namespace Common {
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr T AlignUp(T value, std::size_t size) {
|
||||
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
|
||||
auto mod{value % size};
|
||||
auto mod = static_cast<T>(value % size);
|
||||
value -= mod;
|
||||
return static_cast<T>(mod == T{0} ? value : value + size);
|
||||
}
|
||||
|
166
src/common/atomic_ops.h
Normal file
166
src/common/atomic_ops.h
Normal file
@ -0,0 +1,166 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
#if _MSC_VER
|
||||
#include <intrin.h>
|
||||
#else
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
namespace Common {
|
||||
|
||||
#if _MSC_VER
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
|
||||
const u8 result =
|
||||
_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected);
|
||||
return result == expected;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
|
||||
const u16 result =
|
||||
_InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected);
|
||||
return result == expected;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
|
||||
const u32 result =
|
||||
_InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected);
|
||||
return result == expected;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
|
||||
const u64 result = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer),
|
||||
value, expected);
|
||||
return result == expected;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
|
||||
return _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1],
|
||||
value[0],
|
||||
reinterpret_cast<__int64*>(expected.data())) != 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected,
|
||||
u8& actual) {
|
||||
actual =
|
||||
_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected);
|
||||
return actual == expected;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected,
|
||||
u16& actual) {
|
||||
actual =
|
||||
_InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected);
|
||||
return actual == expected;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected,
|
||||
u32& actual) {
|
||||
actual =
|
||||
_InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected);
|
||||
return actual == expected;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected,
|
||||
u64& actual) {
|
||||
actual = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer), value,
|
||||
expected);
|
||||
return actual == expected;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected,
|
||||
u128& actual) {
|
||||
const bool result =
|
||||
_InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1],
|
||||
value[0], reinterpret_cast<__int64*>(expected.data())) != 0;
|
||||
actual = expected;
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline u128 AtomicLoad128(volatile u64* pointer) {
|
||||
u128 result{};
|
||||
_InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), result[1],
|
||||
result[0], reinterpret_cast<__int64*>(result.data()));
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
|
||||
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
|
||||
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
|
||||
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
|
||||
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
|
||||
unsigned __int128 value_a;
|
||||
unsigned __int128 expected_a;
|
||||
std::memcpy(&value_a, value.data(), sizeof(u128));
|
||||
std::memcpy(&expected_a, expected.data(), sizeof(u128));
|
||||
return __sync_bool_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected,
|
||||
u8& actual) {
|
||||
actual = __sync_val_compare_and_swap(pointer, expected, value);
|
||||
return actual == expected;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected,
|
||||
u16& actual) {
|
||||
actual = __sync_val_compare_and_swap(pointer, expected, value);
|
||||
return actual == expected;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected,
|
||||
u32& actual) {
|
||||
actual = __sync_val_compare_and_swap(pointer, expected, value);
|
||||
return actual == expected;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected,
|
||||
u64& actual) {
|
||||
actual = __sync_val_compare_and_swap(pointer, expected, value);
|
||||
return actual == expected;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected,
|
||||
u128& actual) {
|
||||
unsigned __int128 value_a;
|
||||
unsigned __int128 expected_a;
|
||||
unsigned __int128 actual_a;
|
||||
std::memcpy(&value_a, value.data(), sizeof(u128));
|
||||
std::memcpy(&expected_a, expected.data(), sizeof(u128));
|
||||
actual_a = __sync_val_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a);
|
||||
std::memcpy(actual.data(), &actual_a, sizeof(u128));
|
||||
return actual_a == expected_a;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline u128 AtomicLoad128(volatile u64* pointer) {
|
||||
unsigned __int128 zeros_a = 0;
|
||||
unsigned __int128 result_a =
|
||||
__sync_val_compare_and_swap((unsigned __int128*)pointer, zeros_a, zeros_a);
|
||||
|
||||
u128 result;
|
||||
std::memcpy(result.data(), &result_a, sizeof(u128));
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace Common
|
@ -36,6 +36,18 @@
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/swap.h"
|
||||
|
||||
// User defined types to need to specialize this
|
||||
template <typename T>
|
||||
struct MakeUnsigned {
|
||||
using type = std::make_unsigned_t<T>;
|
||||
};
|
||||
|
||||
// Ensure that user defined types are sane
|
||||
template <class T>
|
||||
concept ValidType = requires(T t) {
|
||||
static_cast<typename MakeUnsigned<T>::type>(t);
|
||||
};
|
||||
|
||||
/*
|
||||
* Abstract bitfield class
|
||||
*
|
||||
@ -110,6 +122,7 @@
|
||||
*/
|
||||
#pragma pack(1)
|
||||
template <std::size_t Position, std::size_t Bits, typename T, typename EndianTag = LETag>
|
||||
requires ValidType<T>
|
||||
struct BitField {
|
||||
private:
|
||||
// UnderlyingType is T for non-enum types and the underlying type of T if
|
||||
@ -120,7 +133,7 @@ private:
|
||||
std::enable_if<true, T>>::type;
|
||||
|
||||
// We store the value as the unsigned type to avoid undefined behaviour on value shifting
|
||||
using StorageType = std::make_unsigned_t<UnderlyingType>;
|
||||
using StorageType = typename MakeUnsigned<UnderlyingType>::type;
|
||||
|
||||
using StorageTypeWithEndian = typename AddEndian<StorageType, EndianTag>::type;
|
||||
|
||||
@ -199,3 +212,38 @@ private:
|
||||
|
||||
template <std::size_t Position, std::size_t Bits, typename T>
|
||||
using BitFieldBE = BitField<Position, Bits, T, BETag>;
|
||||
|
||||
/**
|
||||
* Abstract bit flag class. This is basically a specialization of BitField for single-bit fields.
|
||||
* Instead of being cast to the underlying type, it acts like a boolean.
|
||||
*/
|
||||
#pragma pack(1)
|
||||
template <std::size_t Position, typename T, typename EndianTag = LETag>
|
||||
struct BitFlag : protected BitField<Position, 1, T, EndianTag> {
|
||||
private:
|
||||
BitFlag(T val) = delete;
|
||||
|
||||
using ParentType = BitField<Position, 1, T>;
|
||||
|
||||
public:
|
||||
BitFlag() = default;
|
||||
BitFlag& operator=(const BitFlag&) = delete;
|
||||
|
||||
constexpr BitFlag& operator=(bool val) {
|
||||
Assign(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr void Assign(bool value) {
|
||||
ParentType::Assign(value);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr operator bool() const {
|
||||
return Value();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool Value() const {
|
||||
return ParentType::Value() != 0;
|
||||
}
|
||||
};
|
||||
#pragma pack()
|
||||
|
279
src/common/bit_field_array.h
Normal file
279
src/common/bit_field_array.h
Normal file
@ -0,0 +1,279 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include "common/swap.h"
|
||||
|
||||
// Language limitations require the following to make these formattable
|
||||
// (formatter<BitFieldArray<position, bits, size, T>::Ref> is not legal)
|
||||
template <std::size_t position, std::size_t bits, std::size_t size, typename T, typename S>
|
||||
class BitFieldArrayConstRef;
|
||||
template <std::size_t position, std::size_t bits, std::size_t size, typename T, typename S>
|
||||
class BitFieldArrayRef;
|
||||
template <std::size_t position, std::size_t bits, std::size_t size, typename T, typename S>
|
||||
class BitFieldArrayConstIterator;
|
||||
template <std::size_t position, std::size_t bits, std::size_t size, typename T, typename S>
|
||||
class BitFieldArrayIterator;
|
||||
|
||||
#pragma pack(1)
|
||||
template <std::size_t position, std::size_t bits, std::size_t size, typename T,
|
||||
// StorageType is T for non-enum types and the underlying type of T if
|
||||
// T is an enumeration. Note that T is wrapped within an enable_if in the
|
||||
// former case to workaround compile errors which arise when using
|
||||
// std::underlying_type<T>::type directly.
|
||||
typename StorageType = typename std::conditional_t<
|
||||
std::is_enum<T>::value, std::underlying_type<T>, std::enable_if<true, T>>::type>
|
||||
struct BitFieldArray
|
||||
{
|
||||
using Ref = BitFieldArrayRef<position, bits, size, T, StorageType>;
|
||||
using ConstRef = BitFieldArrayConstRef<position, bits, size, T, StorageType>;
|
||||
using Iterator = BitFieldArrayIterator<position, bits, size, T, StorageType>;
|
||||
using ConstIterator = BitFieldArrayConstIterator<position, bits, size, T, StorageType>;
|
||||
|
||||
private:
|
||||
// This constructor might be considered ambiguous:
|
||||
// Would it initialize the storage or just the bitfield?
|
||||
// Hence, delete it. Use the assignment operator to set bitfield values!
|
||||
BitFieldArray(T val) = delete;
|
||||
|
||||
public:
|
||||
// Force default constructor to be created
|
||||
// so that we can use this within unions
|
||||
constexpr BitFieldArray() = default;
|
||||
|
||||
// Initializer list constructor
|
||||
constexpr BitFieldArray(std::initializer_list<T> items) : storage(StorageType{}) {
|
||||
u32 index = 0;
|
||||
for (auto& item : items) {
|
||||
SetValue(index++, item);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr bool IsSigned() const { return std::is_signed<T>(); }
|
||||
constexpr std::size_t StartBit() const { return position; }
|
||||
constexpr std::size_t NumBits() const { return bits; }
|
||||
constexpr std::size_t Size() const { return size; }
|
||||
constexpr std::size_t TotalNumBits() const { return bits * size; }
|
||||
|
||||
constexpr T Value(size_t index) const { return Value(std::is_signed<T>(), index); }
|
||||
constexpr void SetValue(size_t index, T value) {
|
||||
const size_t pos = position + bits * index;
|
||||
storage = (storage & ~GetElementMask(index)) |
|
||||
((static_cast<StorageType>(value) << pos) & GetElementMask(index));
|
||||
}
|
||||
Ref operator[](size_t index) { return Ref(this, index); }
|
||||
constexpr const ConstRef operator[](size_t index) const { return ConstRef(this, index); }
|
||||
|
||||
constexpr Iterator begin() { return Iterator(this, 0); }
|
||||
constexpr Iterator end() { return Iterator(this, size); }
|
||||
constexpr ConstIterator begin() const { return ConstIterator(this, 0); }
|
||||
constexpr ConstIterator end() const { return ConstIterator(this, size); }
|
||||
constexpr ConstIterator cbegin() const { return begin(); }
|
||||
constexpr ConstIterator cend() const { return end(); }
|
||||
|
||||
private:
|
||||
// Unsigned version of StorageType
|
||||
using StorageTypeU = std::make_unsigned_t<StorageType>;
|
||||
|
||||
constexpr T Value(std::true_type, size_t index) const
|
||||
{
|
||||
const size_t pos = position + bits * index;
|
||||
const size_t shift_amount = 8 * sizeof(StorageType) - bits;
|
||||
return static_cast<T>((storage << (shift_amount - pos)) >> shift_amount);
|
||||
}
|
||||
|
||||
constexpr T Value(std::false_type, size_t index) const
|
||||
{
|
||||
const size_t pos = position + bits * index;
|
||||
return static_cast<T>((storage & GetElementMask(index)) >> pos);
|
||||
}
|
||||
|
||||
static constexpr StorageType GetElementMask(size_t index)
|
||||
{
|
||||
const size_t pos = position + bits * index;
|
||||
return (std::numeric_limits<StorageTypeU>::max() >> (8 * sizeof(StorageType) - bits)) << pos;
|
||||
}
|
||||
|
||||
StorageType storage;
|
||||
|
||||
static_assert(bits * size + position <= 8 * sizeof(StorageType), "Bitfield array out of range");
|
||||
static_assert(sizeof(T) <= sizeof(StorageType), "T must fit in StorageType");
|
||||
|
||||
// And, you know, just in case people specify something stupid like bits=position=0x80000000
|
||||
static_assert(position < 8 * sizeof(StorageType), "Invalid position");
|
||||
static_assert(bits <= 8 * sizeof(T), "Invalid number of bits");
|
||||
static_assert(bits > 0, "Invalid number of bits");
|
||||
static_assert(size <= 8 * sizeof(StorageType), "Invalid size");
|
||||
static_assert(size > 0, "Invalid size");
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
template <std::size_t position, std::size_t bits, std::size_t size, typename T, typename S>
|
||||
class BitFieldArrayConstRef
|
||||
{
|
||||
friend struct BitFieldArray<position, bits, size, T, S>;
|
||||
friend class BitFieldArrayConstIterator<position, bits, size, T, S>;
|
||||
|
||||
public:
|
||||
constexpr T Value() const { return m_array->Value(m_index); };
|
||||
constexpr operator T() const { return Value(); }
|
||||
|
||||
private:
|
||||
constexpr BitFieldArrayConstRef(const BitFieldArray<position, bits, size, T, S>* array,
|
||||
size_t index)
|
||||
: m_array(array), m_index(index)
|
||||
{
|
||||
}
|
||||
|
||||
const BitFieldArray<position, bits, size, T, S>* const m_array;
|
||||
const size_t m_index;
|
||||
};
|
||||
|
||||
template <std::size_t position, std::size_t bits, std::size_t size, typename T, typename S>
|
||||
class BitFieldArrayRef
|
||||
{
|
||||
friend struct BitFieldArray<position, bits, size, T, S>;
|
||||
friend class BitFieldArrayIterator<position, bits, size, T, S>;
|
||||
|
||||
public:
|
||||
constexpr T Value() const { return m_array->Value(m_index); };
|
||||
constexpr operator T() const { return Value(); }
|
||||
T operator=(const BitFieldArrayRef<position, bits, size, T, S>& value) const
|
||||
{
|
||||
m_array->SetValue(m_index, value);
|
||||
return value;
|
||||
}
|
||||
T operator=(T value) const
|
||||
{
|
||||
m_array->SetValue(m_index, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr BitFieldArrayRef(BitFieldArray<position, bits, size, T, S>* array, size_t index)
|
||||
: m_array(array), m_index(index)
|
||||
{
|
||||
}
|
||||
|
||||
BitFieldArray<position, bits, size, T, S>* const m_array;
|
||||
const size_t m_index;
|
||||
};
|
||||
|
||||
// Satisfies LegacyOutputIterator / std::output_iterator.
|
||||
// Does not satisfy LegacyInputIterator / std::input_iterator as std::output_iterator_tag does not
|
||||
// extend std::input_iterator_tag.
|
||||
// Does not satisfy LegacyForwardIterator / std::forward_iterator, as that requires use of real
|
||||
// references instead of proxy objects.
|
||||
// This iterator allows use of BitFieldArray in range-based for loops, and with fmt::join.
|
||||
template <std::size_t position, std::size_t bits, std::size_t size, typename T, typename S>
|
||||
class BitFieldArrayIterator
|
||||
{
|
||||
friend struct BitFieldArray<position, bits, size, T, S>;
|
||||
|
||||
public:
|
||||
using iterator_category = std::output_iterator_tag;
|
||||
using value_type = T;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = void;
|
||||
using reference = BitFieldArrayRef<position, bits, size, T, S>;
|
||||
|
||||
private:
|
||||
constexpr BitFieldArrayIterator(BitFieldArray<position, bits, size, T, S>* array, size_t index)
|
||||
: m_array(array), m_index(index)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
// Required by std::input_or_output_iterator
|
||||
constexpr BitFieldArrayIterator() = default;
|
||||
// Required by LegacyIterator
|
||||
constexpr BitFieldArrayIterator(const BitFieldArrayIterator& other) = default;
|
||||
// Required by LegacyIterator
|
||||
BitFieldArrayIterator& operator=(const BitFieldArrayIterator& other) = default;
|
||||
// Move constructor and assignment operators, explicitly defined for completeness
|
||||
constexpr BitFieldArrayIterator(BitFieldArrayIterator&& other) = default;
|
||||
BitFieldArrayIterator& operator=(BitFieldArrayIterator&& other) = default;
|
||||
|
||||
public:
|
||||
BitFieldArrayIterator& operator++()
|
||||
{
|
||||
m_index++;
|
||||
return *this;
|
||||
}
|
||||
BitFieldArrayIterator operator++(int)
|
||||
{
|
||||
BitFieldArrayIterator other(*this);
|
||||
++*this;
|
||||
return other;
|
||||
}
|
||||
constexpr reference operator*() const { return reference(m_array, m_index); }
|
||||
constexpr bool operator==(BitFieldArrayIterator other) const { return m_index == other.m_index; }
|
||||
constexpr bool operator!=(BitFieldArrayIterator other) const { return m_index != other.m_index; }
|
||||
|
||||
private:
|
||||
BitFieldArray<position, bits, size, T, S>* m_array;
|
||||
size_t m_index;
|
||||
};
|
||||
|
||||
// Satisfies LegacyInputIterator / std::input_iterator.
|
||||
// Does not satisfy LegacyForwardIterator / std::forward_iterator, as that requires use of real
|
||||
// references instead of proxy objects.
|
||||
// This iterator allows use of BitFieldArray in range-based for loops, and with fmt::join.
|
||||
template <std::size_t position, std::size_t bits, std::size_t size, typename T, typename S>
|
||||
class BitFieldArrayConstIterator
|
||||
{
|
||||
friend struct BitFieldArray<position, bits, size, T, S>;
|
||||
|
||||
public:
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = T;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = void;
|
||||
using reference = BitFieldArrayConstRef<position, bits, size, T, S>;
|
||||
|
||||
private:
|
||||
constexpr BitFieldArrayConstIterator(const BitFieldArray<position, bits, size, T, S>* array,
|
||||
size_t index)
|
||||
: m_array(array), m_index(index)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
// Required by std::input_or_output_iterator
|
||||
constexpr BitFieldArrayConstIterator() = default;
|
||||
// Required by LegacyIterator
|
||||
constexpr BitFieldArrayConstIterator(const BitFieldArrayConstIterator& other) = default;
|
||||
// Required by LegacyIterator
|
||||
BitFieldArrayConstIterator& operator=(const BitFieldArrayConstIterator& other) = default;
|
||||
// Move constructor and assignment operators, explicitly defined for completeness
|
||||
constexpr BitFieldArrayConstIterator(BitFieldArrayConstIterator&& other) = default;
|
||||
BitFieldArrayConstIterator& operator=(BitFieldArrayConstIterator&& other) = default;
|
||||
|
||||
public:
|
||||
BitFieldArrayConstIterator& operator++()
|
||||
{
|
||||
m_index++;
|
||||
return *this;
|
||||
}
|
||||
BitFieldArrayConstIterator operator++(int)
|
||||
{
|
||||
BitFieldArrayConstIterator other(*this);
|
||||
++*this;
|
||||
return other;
|
||||
}
|
||||
constexpr reference operator*() const { return reference(m_array, m_index); }
|
||||
constexpr bool operator==(BitFieldArrayConstIterator other) const
|
||||
{
|
||||
return m_index == other.m_index;
|
||||
}
|
||||
constexpr bool operator!=(BitFieldArrayConstIterator other) const
|
||||
{
|
||||
return m_index != other.m_index;
|
||||
}
|
||||
|
||||
private:
|
||||
const BitFieldArray<position, bits, size, T, S>* m_array;
|
||||
size_t m_index;
|
||||
};
|
@ -21,6 +21,13 @@
|
||||
#define INSERT_PADDING_BYTES(num_bytes) u8 CONCAT2(pad, __LINE__)[(num_bytes)]
|
||||
#define INSERT_PADDING_WORDS(num_words) u32 CONCAT2(pad, __LINE__)[(num_words)]
|
||||
|
||||
/// These are similar to the INSERT_PADDING_* macros but do not zero-initialize the contents.
|
||||
/// This keeps the structure trivial to construct.
|
||||
#define INSERT_PADDING_BYTES_NOINIT(num_bytes) \
|
||||
[[maybe_unused]] std::array<u8, num_bytes> CONCAT2(pad, __LINE__)
|
||||
#define INSERT_PADDING_WORDS_NOINIT(num_words) \
|
||||
[[maybe_unused]] std::array<u32, num_words> CONCAT2(pad, __LINE__)
|
||||
|
||||
// Inlining
|
||||
#ifdef _WIN32
|
||||
#define FORCE_INLINE __forceinline
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@ -50,6 +51,9 @@ typedef double f64; ///< 64-bit floating point
|
||||
typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space.
|
||||
typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space.
|
||||
|
||||
using u128 = std::array<std::uint64_t, 2>;
|
||||
static_assert(sizeof(u128) == 16, "u128 must be 128 bits wide");
|
||||
|
||||
// An inheritable class to disallow the copy constructor and operator= functions
|
||||
class NonCopyable {
|
||||
protected:
|
||||
|
45
src/common/flag.h
Normal file
45
src/common/flag.h
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright 2014 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Abstraction for a simple flag that can be toggled in a multithreaded way.
|
||||
//
|
||||
// Simple API:
|
||||
// * Set(bool = true): sets the Flag
|
||||
// * IsSet(): tests if the flag is set
|
||||
// * Clear(): clears the flag (equivalent to Set(false)).
|
||||
//
|
||||
// More advanced features:
|
||||
// * TestAndSet(bool = true): sets the flag to the given value. If a change was
|
||||
// needed (the flag did not already have this value)
|
||||
// the function returns true. Else, false.
|
||||
// * TestAndClear(): alias for TestAndSet(false).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace Common
|
||||
{
|
||||
class Flag final
|
||||
{
|
||||
public:
|
||||
// Declared as explicit since we do not want "= true" to work on a flag
|
||||
// object - it should be made explicit that a flag is *not* a normal
|
||||
// variable.
|
||||
explicit Flag(bool initial_value = false) : m_val(initial_value) {}
|
||||
void Set(bool val = true) { m_val.store(val); }
|
||||
void Clear() { Set(false); }
|
||||
bool IsSet() const { return m_val.load(); }
|
||||
bool TestAndSet(bool val = true)
|
||||
{
|
||||
bool expected = !val;
|
||||
return m_val.compare_exchange_strong(expected, val);
|
||||
}
|
||||
|
||||
bool TestAndClear() { return TestAndSet(false); }
|
||||
|
||||
private:
|
||||
std::atomic_bool m_val;
|
||||
};
|
||||
|
||||
} // namespace Common
|
@ -11,6 +11,15 @@
|
||||
|
||||
namespace Common {
|
||||
|
||||
/**
|
||||
* Disables rehashing for std::unordered_map
|
||||
*/
|
||||
struct IdentityHash {
|
||||
u64 operator()(const u64 hash) const {
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Computes a 64-bit hash over the specified block of data
|
||||
* @param data Block of data to compute hash over
|
||||
@ -33,6 +42,14 @@ static inline u64 ComputeStructHash64(const T& data) noexcept {
|
||||
return ComputeHash64(&data, sizeof(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines hash lhs with hash rhs providing a unique result.
|
||||
*/
|
||||
static inline std::size_t HashCombine(std::size_t lhs, std::size_t rhs) noexcept {
|
||||
lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
/// A helper template that ensures the padding in a struct is initialized by memsetting to 0.
|
||||
template <typename T>
|
||||
struct HashableStruct {
|
||||
|
261
src/common/intrusive_ptr.h
Normal file
261
src/common/intrusive_ptr.h
Normal file
@ -0,0 +1,261 @@
|
||||
/* Copyright (c) 2017-2022 Hans-Kristian Arntzen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <type_traits>
|
||||
|
||||
/// Simple reference counter for single threaded environments
|
||||
class SingleThreadCounter {
|
||||
public:
|
||||
inline void AddRef() {
|
||||
count++;
|
||||
}
|
||||
|
||||
inline bool Release() {
|
||||
return --count == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t count = 1;
|
||||
};
|
||||
|
||||
/// Thread-safe reference counter with atomics
|
||||
class MultiThreadCounter {
|
||||
public:
|
||||
MultiThreadCounter() {
|
||||
count.store(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline void AddRef() {
|
||||
count.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline bool Release() {
|
||||
auto result = count.fetch_sub(1, std::memory_order_acq_rel);
|
||||
return result == 1;
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic_size_t count;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class IntrusivePtr;
|
||||
|
||||
template <typename T, typename Deleter = std::default_delete<T>,
|
||||
typename ReferenceOps = SingleThreadCounter>
|
||||
class IntrusivePtrEnabled {
|
||||
public:
|
||||
using IntrusivePtrType = IntrusivePtr<T>;
|
||||
using EnabledBase = T;
|
||||
using EnabledDeleter = Deleter;
|
||||
using EnabledReferenceOp = ReferenceOps;
|
||||
|
||||
IntrusivePtrEnabled() = default;
|
||||
IntrusivePtrEnabled(const IntrusivePtrEnabled &) = delete;
|
||||
void operator=(const IntrusivePtrEnabled &) = delete;
|
||||
|
||||
/// Decrement the reference counter and optionally free the memory
|
||||
inline void ReleaseRef() {
|
||||
if (ref_counter.Release()) {
|
||||
Deleter()(static_cast<T*>(this));
|
||||
}
|
||||
}
|
||||
|
||||
/// Increment the reference counter
|
||||
inline void AddRef() {
|
||||
ref_counter.AddRef();
|
||||
}
|
||||
|
||||
protected:
|
||||
IntrusivePtr<T> RefFromThis();
|
||||
|
||||
private:
|
||||
ReferenceOps ref_counter;
|
||||
};
|
||||
|
||||
/**
|
||||
* Lightweight alternative to std::shared_ptr for reference counting
|
||||
* usecases
|
||||
*/
|
||||
template <typename T>
|
||||
class IntrusivePtr {
|
||||
using ReferenceBase = IntrusivePtrEnabled<
|
||||
typename T::EnabledBase,
|
||||
typename T::EnabledDeleter,
|
||||
typename T::EnabledReferenceOp>;
|
||||
|
||||
template <typename U>
|
||||
friend class IntrusivePtr;
|
||||
public:
|
||||
IntrusivePtr() = default;
|
||||
explicit IntrusivePtr(T *handle) : data(handle) {}
|
||||
|
||||
template <typename U>
|
||||
IntrusivePtr(const IntrusivePtr<U> &other) {
|
||||
*this = other;
|
||||
}
|
||||
|
||||
IntrusivePtr(const IntrusivePtr &other) {
|
||||
*this = other;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
IntrusivePtr(IntrusivePtr<U> &&other) noexcept {
|
||||
*this = std::move(other);
|
||||
}
|
||||
|
||||
IntrusivePtr(IntrusivePtr &&other) noexcept {
|
||||
*this = std::move(other);
|
||||
}
|
||||
|
||||
~IntrusivePtr() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
/// Returns a reference to the underlying data
|
||||
T& operator*() {
|
||||
return *data;
|
||||
}
|
||||
|
||||
/// Returns an immutable reference to the underlying data
|
||||
const T& operator*() const {
|
||||
return *data;
|
||||
}
|
||||
|
||||
/// Returns a pointer to the underlying data
|
||||
T* operator->() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/// Returns an immutable pointer to the underlying data
|
||||
const T* operator->() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
/// Returns true if the underlaying pointer it valid
|
||||
bool IsValid() const {
|
||||
return data != nullptr;
|
||||
}
|
||||
|
||||
/// Default comparison operators
|
||||
auto operator<=>(const IntrusivePtr& other) const = default;
|
||||
|
||||
/// Returns the raw pointer to the data
|
||||
T* Get() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/// Returns an immutable raw pointer to the data
|
||||
const T* Get() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
// Static up-cast here to avoid potential issues with multiple intrusive inheritance.
|
||||
// Also makes sure that the pointer type actually inherits from this type.
|
||||
if (data)
|
||||
static_cast<ReferenceBase*>(data)->ReleaseRef();
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
IntrusivePtr& operator=(const IntrusivePtr<U>& other) {
|
||||
static_assert(std::is_base_of_v<T, U>, "Cannot safely assign downcasted intrusive pointers.");
|
||||
|
||||
Reset();
|
||||
data = static_cast<T*>(other.data);
|
||||
|
||||
// Static up-cast here to avoid potential issues with multiple intrusive inheritance.
|
||||
// Also makes sure that the pointer type actually inherits from this type.
|
||||
if (data) {
|
||||
static_cast<ReferenceBase*>(data)->ReleaseRef();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
IntrusivePtr& operator=(const IntrusivePtr& other) {
|
||||
if (this != &other) {
|
||||
Reset();
|
||||
data = other.data;
|
||||
if (data)
|
||||
static_cast<ReferenceBase*>(data)->AddRef();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
IntrusivePtr &operator=(IntrusivePtr<U> &&other) noexcept {
|
||||
Reset();
|
||||
data = std::exchange(other.data, nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
IntrusivePtr &operator=(IntrusivePtr &&other) noexcept {
|
||||
if (this != &other) {
|
||||
Reset();
|
||||
data = std::exchange(other.data, nullptr);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
T* Release() & {
|
||||
return std::exchange(data, nullptr);
|
||||
}
|
||||
|
||||
T* Release() && {
|
||||
return std::exchange(data, nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
T* data = nullptr;
|
||||
};
|
||||
|
||||
template <typename T, typename Deleter, typename ReferenceOps>
|
||||
IntrusivePtr<T> IntrusivePtrEnabled<T, Deleter, ReferenceOps>::RefFromThis() {
|
||||
AddRef();
|
||||
return IntrusivePtr<T>(static_cast<T*>(this));
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
using DerivedIntrusivePtrType = IntrusivePtr<Derived>;
|
||||
|
||||
template <typename T, typename... P>
|
||||
DerivedIntrusivePtrType<T> MakeHandle(P &&... p) {
|
||||
return DerivedIntrusivePtrType<T>(new T(std::forward<P>(p)...));
|
||||
}
|
||||
|
||||
template <typename Base, typename Derived, typename... P>
|
||||
typename Base::IntrusivePtrType MakeDerivedHandle(P &&... p) {
|
||||
return typename Base::IntrusivePtrType(new Derived(std::forward<P>(p)...));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
using ThreadSafeIntrusivePtrEnabled = IntrusivePtrEnabled<T, std::default_delete<T>, MultiThreadCounter>;
|
@ -9,7 +9,7 @@
|
||||
#include "common/common_types.h"
|
||||
|
||||
// defined in Version.cpp
|
||||
extern const char* scm_rev_git_str;
|
||||
const char* scm_rev_git_str = "DUMMY";
|
||||
|
||||
// On disk format:
|
||||
// header{
|
||||
|
@ -235,6 +235,7 @@ void DebuggerBackend::Write(const Entry& entry) {
|
||||
CLS(Render) \
|
||||
SUB(Render, Software) \
|
||||
SUB(Render, OpenGL) \
|
||||
SUB(Render, Vulkan) \
|
||||
CLS(Audio) \
|
||||
SUB(Audio, DSP) \
|
||||
SUB(Audio, Sink) \
|
||||
|
@ -4,10 +4,24 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <type_traits>
|
||||
#include <fmt/format.h>
|
||||
#include "common/common_types.h"
|
||||
|
||||
// adapted from https://github.com/fmtlib/fmt/issues/2704
|
||||
// a generic formatter for enum classes (<= 32 bits)
|
||||
#if FMT_VERSION >= 80100
|
||||
template <typename T>
|
||||
struct fmt::formatter<T, std::enable_if_t<std::is_enum_v<T>, char>> : formatter<u32> {
|
||||
template <typename FormatContext>
|
||||
auto format(const T& value, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||
return fmt::formatter<u32>::format(static_cast<u32>(value), ctx);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
namespace Log {
|
||||
|
||||
// trims up to and including the last of ../, ..\, src/, src\ in a string
|
||||
@ -102,6 +116,7 @@ enum class Class : ClassType {
|
||||
Render, ///< Emulator video output and hardware acceleration
|
||||
Render_Software, ///< Software renderer backend
|
||||
Render_OpenGL, ///< OpenGL backend
|
||||
Render_Vulkan, ///< Vulkan backend
|
||||
Audio, ///< Audio emulation
|
||||
Audio_DSP, ///< The HLE and LLE implementations of the DSP
|
||||
Audio_Sink, ///< Emulator audio output backend
|
||||
|
@ -39,6 +39,11 @@ struct Rectangle {
|
||||
return Rectangle{left, top, static_cast<T>(left + GetWidth() * s),
|
||||
static_cast<T>(top + GetHeight() * s)};
|
||||
}
|
||||
[[nodiscard]] Rectangle<T> operator *(const T num) const {
|
||||
return Rectangle{left * num, top * num, right * num, bottom * num};
|
||||
}
|
||||
|
||||
auto operator <=> (const Rectangle<T>& other) const = default;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
70
src/common/object_pool.cpp
Normal file
70
src/common/object_pool.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
/* Copyright (c) 2017-2022 Hans-Kristian Arntzen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "common/object_pool.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#ifdef _WIN32
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
void* memalign_alloc(size_t boundary, size_t size) {
|
||||
#if defined(_WIN32)
|
||||
return _aligned_malloc(size, boundary);
|
||||
#elif defined(_ISOC11_SOURCE)
|
||||
return aligned_alloc(boundary, size);
|
||||
#elif (_POSIX_C_SOURCE >= 200112L) || (_XOPEN_SOURCE >= 600)
|
||||
void *ptr = nullptr;
|
||||
if (posix_memalign(&ptr, boundary, size) < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return ptr;
|
||||
#else
|
||||
// Align stuff ourselves. Kinda ugly, but will work anywhere.
|
||||
void **place;
|
||||
uintptr_t addr = 0;
|
||||
void *ptr = malloc(boundary + size + sizeof(uintptr_t));
|
||||
|
||||
if (ptr == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
addr = ((uintptr_t)ptr + sizeof(uintptr_t) + boundary) & ~(boundary - 1);
|
||||
place = (void **) addr;
|
||||
place[-1] = ptr;
|
||||
|
||||
return (void *) addr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void memalign_free(void *ptr) {
|
||||
#if defined(_WIN32)
|
||||
_aligned_free(ptr);
|
||||
#elif !defined(_ISOC11_SOURCE) && !((_POSIX_C_SOURCE >= 200112L) || (_XOPEN_SOURCE >= 600))
|
||||
if (ptr != nullptr) {
|
||||
void **p = (void **) ptr;
|
||||
free(p[-1]);
|
||||
}
|
||||
#else
|
||||
free(ptr);
|
||||
#endif
|
||||
}
|
152
src/common/object_pool.h
Normal file
152
src/common/object_pool.h
Normal file
@ -0,0 +1,152 @@
|
||||
/* Copyright (c) 2017-2022 Hans-Kristian Arntzen
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
|
||||
void *memalign_alloc(size_t boundary, size_t size);
|
||||
void memalign_free(void *ptr);
|
||||
|
||||
template <typename T>
|
||||
struct AlignedAllocation {
|
||||
static void* operator new(size_t size) {
|
||||
void* ret = memalign_alloc(alignof(T), size);
|
||||
if (!ret) throw std::bad_alloc();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void* operator new[](size_t size) {
|
||||
void* ret = memalign_alloc(alignof(T), size);
|
||||
if (!ret) throw std::bad_alloc();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void operator delete(void *ptr) {
|
||||
return memalign_free(ptr);
|
||||
}
|
||||
|
||||
static void operator delete[](void *ptr) {
|
||||
return memalign_free(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocates objects of type T in batches of 64 * n where
|
||||
* n is the number of times the pool has grown. So the first
|
||||
* time it will allocate 64, then 128 objects etc.
|
||||
*/
|
||||
template<typename T>
|
||||
class ObjectPool {
|
||||
public:
|
||||
ObjectPool() {
|
||||
vacants.reserve(32);
|
||||
}
|
||||
|
||||
template<typename... P>
|
||||
T* Allocate(P&&... p) {
|
||||
#ifndef OBJECT_POOL_DEBUG
|
||||
if (vacants.empty()) {
|
||||
unsigned num_objects = 64u << memory.size();
|
||||
T *ptr = static_cast<T*>(memalign_alloc(std::max<unsigned>(64, alignof(T)),
|
||||
num_objects * sizeof(T)));
|
||||
if (!ptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < num_objects; i++) {
|
||||
vacants.push_back(&ptr[i]);
|
||||
}
|
||||
|
||||
memory.emplace_back(ptr);
|
||||
}
|
||||
|
||||
T *ptr = vacants.back();
|
||||
vacants.pop_back();
|
||||
new(ptr) T(std::forward<P>(p)...);
|
||||
return ptr;
|
||||
#else
|
||||
return new T(std::forward<P>(p)...);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Free(T *ptr) {
|
||||
#ifndef OBJECT_POOL_DEBUG
|
||||
ptr->~T();
|
||||
vacants.push_back(ptr);
|
||||
#else
|
||||
delete ptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
#ifndef OBJECT_POOL_DEBUG
|
||||
vacants.clear();
|
||||
memory.clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
#ifndef OBJECT_POOL_DEBUG
|
||||
std::vector<T*> vacants;
|
||||
|
||||
struct MallocDeleter {
|
||||
void operator()(T *ptr) {
|
||||
memalign_free(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<std::unique_ptr<T, MallocDeleter>> memory;
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class ThreadSafeObjectPool : private ObjectPool<T> {
|
||||
public:
|
||||
template<typename... P>
|
||||
T* Allocate(P &&... p) {
|
||||
std::lock_guard<std::mutex> holder{lock};
|
||||
return ObjectPool<T>::Allocate(std::forward<P>(p)...);
|
||||
}
|
||||
|
||||
void Free(T *ptr) {
|
||||
#ifndef OBJECT_POOL_DEBUG
|
||||
ptr->~T();
|
||||
std::lock_guard<std::mutex> holder{lock};
|
||||
this->vacants.push_back(ptr);
|
||||
#else
|
||||
delete ptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
std::lock_guard<std::mutex> holder{lock};
|
||||
ObjectPool<T>::Clear();
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex lock;
|
||||
};
|
72
src/common/semaphore.h
Normal file
72
src/common/semaphore.h
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
namespace Common
|
||||
{
|
||||
class Semaphore
|
||||
{
|
||||
public:
|
||||
Semaphore(int initial_count, int maximum_count)
|
||||
{
|
||||
m_handle = CreateSemaphoreA(nullptr, initial_count, maximum_count, nullptr);
|
||||
}
|
||||
|
||||
~Semaphore() { CloseHandle(m_handle); }
|
||||
void Wait() { WaitForSingleObject(m_handle, INFINITE); }
|
||||
void Post() { ReleaseSemaphore(m_handle, 1, nullptr); }
|
||||
|
||||
private:
|
||||
HANDLE m_handle;
|
||||
};
|
||||
} // namespace Common
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
#include <dispatch/dispatch.h>
|
||||
|
||||
namespace Common
|
||||
{
|
||||
class Semaphore
|
||||
{
|
||||
public:
|
||||
Semaphore(int initial_count, int maximum_count)
|
||||
{
|
||||
m_handle = dispatch_semaphore_create(0);
|
||||
for (int i = 0; i < initial_count; i++)
|
||||
dispatch_semaphore_signal(m_handle);
|
||||
}
|
||||
~Semaphore() { dispatch_release(m_handle); }
|
||||
void Wait() { dispatch_semaphore_wait(m_handle, DISPATCH_TIME_FOREVER); }
|
||||
void Post() { dispatch_semaphore_signal(m_handle); }
|
||||
|
||||
private:
|
||||
dispatch_semaphore_t m_handle;
|
||||
};
|
||||
} // namespace Common
|
||||
|
||||
#else
|
||||
|
||||
#include <semaphore.h>
|
||||
|
||||
namespace Common
|
||||
{
|
||||
class Semaphore
|
||||
{
|
||||
public:
|
||||
Semaphore(int initial_count, int maximum_count) { sem_init(&m_handle, 0, initial_count); }
|
||||
~Semaphore() { sem_destroy(&m_handle); }
|
||||
void Wait() { sem_wait(&m_handle); }
|
||||
void Post() { sem_post(&m_handle); }
|
||||
|
||||
private:
|
||||
sem_t m_handle;
|
||||
};
|
||||
} // namespace Common
|
||||
|
||||
#endif // _WIN32
|
@ -12,8 +12,8 @@ void FlipRGBA8Texture(std::vector<u8>& tex, u64 width, u64 height) {
|
||||
ASSERT(tex.size() == width * height * 4);
|
||||
const u64 line_size = width * 4;
|
||||
for (u64 line = 0; line < height / 2; line++) {
|
||||
const u32 offset_1 = line * line_size;
|
||||
const u32 offset_2 = (height - line - 1) * line_size;
|
||||
const u64 offset_1 = line * line_size;
|
||||
const u64 offset_2 = (height - line - 1) * line_size;
|
||||
// Swap lines
|
||||
std::swap_ranges(tex.begin() + offset_1, tex.begin() + offset_1 + line_size,
|
||||
tex.begin() + offset_2);
|
||||
|
@ -72,6 +72,9 @@ public:
|
||||
return Vec2{f, f};
|
||||
}
|
||||
|
||||
// Default comparison operators
|
||||
[[nodiscard]] auto operator<=>(const Vec2& other) const = default;
|
||||
|
||||
[[nodiscard]] constexpr Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
|
||||
return {x + other.x, y + other.y};
|
||||
}
|
||||
@ -184,6 +187,8 @@ template <typename T, typename V>
|
||||
}
|
||||
|
||||
using Vec2f = Vec2<float>;
|
||||
using Vec2u = Vec2<unsigned>;
|
||||
using Vec2i = Vec2<int>;
|
||||
|
||||
template <>
|
||||
inline float Vec2<float>::Length() const {
|
||||
@ -228,6 +233,9 @@ public:
|
||||
return Vec3(f, f, f);
|
||||
}
|
||||
|
||||
// Default comparison operators
|
||||
[[nodiscard]] auto operator<=>(const Vec3& other) const = default;
|
||||
|
||||
[[nodiscard]] constexpr Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
|
||||
return {x + other.x, y + other.y, z + other.z};
|
||||
}
|
||||
@ -412,6 +420,8 @@ inline float Vec3<float>::Normalize() {
|
||||
}
|
||||
|
||||
using Vec3f = Vec3<float>;
|
||||
using Vec3u = Vec3<unsigned>;
|
||||
using Vec3i = Vec3<int>;
|
||||
|
||||
template <typename T>
|
||||
class Vec4 {
|
||||
@ -448,6 +458,9 @@ public:
|
||||
return Vec4(f, f, f, f);
|
||||
}
|
||||
|
||||
// Default comparison operators
|
||||
[[nodiscard]] auto operator<=>(const Vec4& other) const = default;
|
||||
|
||||
[[nodiscard]] constexpr Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
|
||||
return {x + other.x, y + other.y, z + other.z, w + other.w};
|
||||
}
|
||||
@ -623,6 +636,8 @@ template <typename T, typename V>
|
||||
}
|
||||
|
||||
using Vec4f = Vec4<float>;
|
||||
using Vec4u = Vec4<unsigned>;
|
||||
using Vec4i = Vec4<int>;
|
||||
|
||||
template <typename T>
|
||||
constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b) {
|
||||
|
@ -158,10 +158,10 @@ struct ABIFrameInfo {
|
||||
|
||||
inline ABIFrameInfo ABI_CalculateFrameSize(std::bitset<32> regs, std::size_t rsp_alignment,
|
||||
std::size_t needed_frame_size) {
|
||||
int count = (regs & ABI_ALL_GPRS).count();
|
||||
std::size_t count = (regs & ABI_ALL_GPRS).count();
|
||||
rsp_alignment -= count * 8;
|
||||
std::size_t subtraction = 0;
|
||||
int xmm_count = (regs & ABI_ALL_XMMS).count();
|
||||
std::size_t xmm_count = (regs & ABI_ALL_XMMS).count();
|
||||
if (xmm_count) {
|
||||
// If we have any XMMs to save, we must align the stack here.
|
||||
subtraction = rsp_alignment & 0xF;
|
||||
|
@ -14,6 +14,8 @@ add_library(core STATIC
|
||||
arm/dyncom/arm_dyncom_thumb.h
|
||||
arm/dyncom/arm_dyncom_trans.cpp
|
||||
arm/dyncom/arm_dyncom_trans.h
|
||||
arm/exclusive_monitor.cpp
|
||||
arm/exclusive_monitor.h
|
||||
arm/skyeye_common/arm_regformat.h
|
||||
arm/skyeye_common/armstate.cpp
|
||||
arm/skyeye_common/armstate.h
|
||||
@ -473,7 +475,7 @@ endif()
|
||||
create_target_directory_groups(core)
|
||||
|
||||
target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core)
|
||||
target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp fmt open_source_archives Boost::serialization)
|
||||
target_link_libraries(core PUBLIC Boost::boost PRIVATE nihstro-headers cryptopp-static fmt::fmt open_source_archives Boost::serialization)
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE -DCPPHTTPLIB_OPENSSL_SUPPORT)
|
||||
@ -483,12 +485,14 @@ if (ENABLE_WEB_SERVICE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_ARM64)
|
||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||
target_sources(core PRIVATE
|
||||
arm/dynarmic/arm_dynarmic.cpp
|
||||
arm/dynarmic/arm_dynarmic.h
|
||||
arm/dynarmic/arm_dynarmic_cp15.cpp
|
||||
arm/dynarmic/arm_dynarmic_cp15.h
|
||||
arm/dynarmic/arm_exclusive_monitor.cpp
|
||||
arm/dynarmic/arm_exclusive_monitor.h
|
||||
)
|
||||
target_link_libraries(core PRIVATE dynarmic)
|
||||
endif()
|
||||
|
@ -122,6 +122,9 @@ public:
|
||||
*/
|
||||
virtual void InvalidateCacheRange(u32 start_address, std::size_t length) = 0;
|
||||
|
||||
/// Clears the exclusive monitor's state.
|
||||
virtual void ClearExclusiveState() = 0;
|
||||
|
||||
/// Notify CPU emulation that page tables have changed
|
||||
virtual void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) = 0;
|
||||
|
||||
|
@ -3,12 +3,14 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstring>
|
||||
#include <dynarmic/A32/a32.h>
|
||||
#include <dynarmic/A32/context.h>
|
||||
#include <dynarmic/interface/A32/a32.h>
|
||||
#include <dynarmic/interface/A32/context.h>
|
||||
#include <dynarmic/interface/optimization_flags.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
|
||||
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
@ -100,10 +102,23 @@ public:
|
||||
memory.Write64(vaddr, value);
|
||||
}
|
||||
|
||||
bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override {
|
||||
return memory.WriteExclusive8(vaddr, value, expected);
|
||||
}
|
||||
bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override {
|
||||
return memory.WriteExclusive16(vaddr, value, expected);
|
||||
}
|
||||
bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override {
|
||||
return memory.WriteExclusive32(vaddr, value, expected);
|
||||
}
|
||||
bool MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expected) override {
|
||||
return memory.WriteExclusive64(vaddr, value, expected);
|
||||
}
|
||||
|
||||
void InterpreterFallback(VAddr pc, std::size_t num_instructions) override {
|
||||
// Should never happen.
|
||||
UNREACHABLE_MSG("InterpeterFallback reached with pc = 0x{:08x}, code = 0x{:08x}, num = {}",
|
||||
pc, MemoryReadCode(pc), num_instructions);
|
||||
pc, MemoryReadCode(pc).value(), num_instructions);
|
||||
}
|
||||
|
||||
void CallSVC(std::uint32_t swi) override {
|
||||
@ -133,7 +148,7 @@ public:
|
||||
return;
|
||||
}
|
||||
ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", exception,
|
||||
pc, MemoryReadCode(pc));
|
||||
pc, MemoryReadCode(pc).value());
|
||||
}
|
||||
|
||||
void AddTicks(std::uint64_t ticks) override {
|
||||
@ -149,10 +164,12 @@ public:
|
||||
Memory::MemorySystem& memory;
|
||||
};
|
||||
|
||||
ARM_Dynarmic::ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory, u32 id,
|
||||
std::shared_ptr<Core::Timing::Timer> timer)
|
||||
: ARM_Interface(id, timer), system(*system), memory(memory),
|
||||
cb(std::make_unique<DynarmicUserCallbacks>(*this)) {
|
||||
ARM_Dynarmic::ARM_Dynarmic(Core::System* system_, Memory::MemorySystem& memory_, u32 core_id_,
|
||||
std::shared_ptr<Core::Timing::Timer> timer_,
|
||||
Core::ExclusiveMonitor& exclusive_monitor_)
|
||||
: ARM_Interface(core_id_, timer_), system(*system_), memory(memory_),
|
||||
cb(std::make_unique<DynarmicUserCallbacks>(*this)),
|
||||
exclusive_monitor{dynamic_cast<Core::DynarmicExclusiveMonitor&>(exclusive_monitor_)} {
|
||||
SetPageTable(memory.GetCurrentPageTable());
|
||||
}
|
||||
|
||||
@ -291,6 +308,10 @@ void ARM_Dynarmic::InvalidateCacheRange(u32 start_address, std::size_t length) {
|
||||
jit->InvalidateCacheRange(start_address, length);
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::ClearExclusiveState() {
|
||||
jit->ClearExclusiveState();
|
||||
}
|
||||
|
||||
std::shared_ptr<Memory::PageTable> ARM_Dynarmic::GetPageTable() const {
|
||||
return current_page_table;
|
||||
}
|
||||
@ -328,6 +349,11 @@ std::unique_ptr<Dynarmic::A32::Jit> ARM_Dynarmic::MakeJit() {
|
||||
config.page_table = ¤t_page_table->GetPointerArray();
|
||||
config.coprocessors[15] = std::make_shared<DynarmicCP15>(cp15_state);
|
||||
config.define_unpredictable_behaviour = true;
|
||||
|
||||
// Multi-process state
|
||||
config.processor_id = GetID();
|
||||
config.global_monitor = &exclusive_monitor.monitor;
|
||||
|
||||
return std::make_unique<Dynarmic::A32::Jit>(config);
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <dynarmic/A32/a32.h>
|
||||
#include <dynarmic/interface/A32/a32.h>
|
||||
#include "common/common_types.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
|
||||
@ -17,6 +17,8 @@ class MemorySystem;
|
||||
} // namespace Memory
|
||||
|
||||
namespace Core {
|
||||
class DynarmicExclusiveMonitor;
|
||||
class ExclusiveMonitor;
|
||||
class System;
|
||||
}
|
||||
|
||||
@ -24,8 +26,9 @@ class DynarmicUserCallbacks;
|
||||
|
||||
class ARM_Dynarmic final : public ARM_Interface {
|
||||
public:
|
||||
ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory, u32 id,
|
||||
std::shared_ptr<Core::Timing::Timer> timer);
|
||||
explicit ARM_Dynarmic(Core::System* system_, Memory::MemorySystem& memory_, u32 core_id_,
|
||||
std::shared_ptr<Core::Timing::Timer> timer,
|
||||
Core::ExclusiveMonitor& exclusive_monitor_);
|
||||
~ARM_Dynarmic() override;
|
||||
|
||||
void Run() override;
|
||||
@ -52,6 +55,7 @@ public:
|
||||
|
||||
void ClearInstructionCache() override;
|
||||
void InvalidateCacheRange(u32 start_address, std::size_t length) override;
|
||||
void ClearExclusiveState() override;
|
||||
void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) override;
|
||||
void PurgeState() override;
|
||||
|
||||
@ -69,6 +73,7 @@ private:
|
||||
|
||||
u32 fpexc = 0;
|
||||
CP15State cp15_state;
|
||||
Core::DynarmicExclusiveMonitor& exclusive_monitor;
|
||||
|
||||
Dynarmic::A32::Jit* jit = nullptr;
|
||||
std::shared_ptr<Memory::PageTable> current_page_table = nullptr;
|
||||
|
@ -5,7 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <dynarmic/A32/coprocessor.h>
|
||||
#include <dynarmic/interface/A32/coprocessor.h>
|
||||
#include "common/common_types.h"
|
||||
|
||||
struct CP15State {
|
||||
|
58
src/core/arm/dynarmic/arm_exclusive_monitor.cpp
Normal file
58
src/core/arm/dynarmic/arm_exclusive_monitor.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
DynarmicExclusiveMonitor::DynarmicExclusiveMonitor(Memory::MemorySystem& memory_, std::size_t core_count_)
|
||||
: monitor{core_count_}, memory{memory_} {}
|
||||
|
||||
DynarmicExclusiveMonitor::~DynarmicExclusiveMonitor() = default;
|
||||
|
||||
u8 DynarmicExclusiveMonitor::ExclusiveRead8(std::size_t core_index, VAddr addr) {
|
||||
return monitor.ReadAndMark<u8>(core_index, addr, [&]() -> u8 { return memory.Read8(addr); });
|
||||
}
|
||||
|
||||
u16 DynarmicExclusiveMonitor::ExclusiveRead16(std::size_t core_index, VAddr addr) {
|
||||
return monitor.ReadAndMark<u16>(core_index, addr, [&]() -> u16 { return memory.Read16(addr); });
|
||||
}
|
||||
|
||||
u32 DynarmicExclusiveMonitor::ExclusiveRead32(std::size_t core_index, VAddr addr) {
|
||||
return monitor.ReadAndMark<u32>(core_index, addr, [&]() -> u32 { return memory.Read32(addr); });
|
||||
}
|
||||
|
||||
u64 DynarmicExclusiveMonitor::ExclusiveRead64(std::size_t core_index, VAddr addr) {
|
||||
return monitor.ReadAndMark<u64>(core_index, addr, [&]() -> u64 { return memory.Read64(addr); });
|
||||
}
|
||||
|
||||
void DynarmicExclusiveMonitor::ClearExclusive(std::size_t core_index) {
|
||||
monitor.ClearProcessor(core_index);
|
||||
}
|
||||
|
||||
bool DynarmicExclusiveMonitor::ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) {
|
||||
return monitor.DoExclusiveOperation<u8>(core_index, vaddr, [&](u8 expected) -> bool {
|
||||
return memory.WriteExclusive8(vaddr, value, expected);
|
||||
});
|
||||
}
|
||||
|
||||
bool DynarmicExclusiveMonitor::ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) {
|
||||
return monitor.DoExclusiveOperation<u16>(core_index, vaddr, [&](u16 expected) -> bool {
|
||||
return memory.WriteExclusive16(vaddr, value, expected);
|
||||
});
|
||||
}
|
||||
|
||||
bool DynarmicExclusiveMonitor::ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) {
|
||||
return monitor.DoExclusiveOperation<u32>(core_index, vaddr, [&](u32 expected) -> bool {
|
||||
return memory.WriteExclusive32(vaddr, value, expected);
|
||||
});
|
||||
}
|
||||
|
||||
bool DynarmicExclusiveMonitor::ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) {
|
||||
return monitor.DoExclusiveOperation<u64>(core_index, vaddr, [&](u64 expected) -> bool {
|
||||
return memory.WriteExclusive64(vaddr, value, expected);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Core
|
40
src/core/arm/dynarmic/arm_exclusive_monitor.h
Normal file
40
src/core/arm/dynarmic/arm_exclusive_monitor.h
Normal file
@ -0,0 +1,40 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <dynarmic/interface/exclusive_monitor.h>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/arm/dynarmic/arm_dynarmic.h"
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
|
||||
namespace Memory {
|
||||
class MemorySystem;
|
||||
}
|
||||
|
||||
namespace Core {
|
||||
|
||||
class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
|
||||
public:
|
||||
explicit DynarmicExclusiveMonitor( Memory::MemorySystem& memory_, std::size_t core_count_);
|
||||
~DynarmicExclusiveMonitor() override;
|
||||
|
||||
u8 ExclusiveRead8(std::size_t core_index, VAddr addr) override;
|
||||
u16 ExclusiveRead16(std::size_t core_index, VAddr addr) override;
|
||||
u32 ExclusiveRead32(std::size_t core_index, VAddr addr) override;
|
||||
u64 ExclusiveRead64(std::size_t core_index, VAddr addr) override;
|
||||
void ClearExclusive(std::size_t core_index) override;
|
||||
|
||||
bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) override;
|
||||
bool ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) override;
|
||||
bool ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) override;
|
||||
bool ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) override;
|
||||
|
||||
private:
|
||||
friend class ::ARM_Dynarmic;
|
||||
Dynarmic::ExclusiveMonitor monitor;
|
||||
Memory::MemorySystem& memory;
|
||||
};
|
||||
|
||||
} // namespace Core
|
@ -30,6 +30,7 @@ public:
|
||||
|
||||
void ClearInstructionCache() override;
|
||||
void InvalidateCacheRange(u32 start_address, std::size_t length) override;
|
||||
void ClearExclusiveState() override {};
|
||||
|
||||
void SetPC(u32 pc) override;
|
||||
u32 GetPC() const override;
|
||||
|
26
src/core/arm/exclusive_monitor.cpp
Normal file
26
src/core/arm/exclusive_monitor.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
|
||||
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
|
||||
#endif
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
ExclusiveMonitor::~ExclusiveMonitor() = default;
|
||||
|
||||
std::unique_ptr<Core::ExclusiveMonitor> MakeExclusiveMonitor(Memory::MemorySystem& memory,
|
||||
std::size_t num_cores) {
|
||||
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
|
||||
if (Settings::values.use_cpu_jit) {
|
||||
return std::make_unique<Core::DynarmicExclusiveMonitor>(memory, num_cores);
|
||||
}
|
||||
#endif
|
||||
// TODO(merry): Passthrough exclusive monitor
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace Core
|
35
src/core/arm/exclusive_monitor.h
Normal file
35
src/core/arm/exclusive_monitor.h
Normal file
@ -0,0 +1,35 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Memory {
|
||||
class MemorySystem;
|
||||
}
|
||||
|
||||
namespace Core {
|
||||
|
||||
class ExclusiveMonitor {
|
||||
public:
|
||||
virtual ~ExclusiveMonitor();
|
||||
|
||||
virtual u8 ExclusiveRead8(std::size_t core_index, VAddr addr) = 0;
|
||||
virtual u16 ExclusiveRead16(std::size_t core_index, VAddr addr) = 0;
|
||||
virtual u32 ExclusiveRead32(std::size_t core_index, VAddr addr) = 0;
|
||||
virtual u64 ExclusiveRead64(std::size_t core_index, VAddr addr) = 0;
|
||||
virtual void ClearExclusive(std::size_t core_index) = 0;
|
||||
|
||||
virtual bool ExclusiveWrite8(std::size_t core_index, VAddr vaddr, u8 value) = 0;
|
||||
virtual bool ExclusiveWrite16(std::size_t core_index, VAddr vaddr, u16 value) = 0;
|
||||
virtual bool ExclusiveWrite32(std::size_t core_index, VAddr vaddr, u32 value) = 0;
|
||||
virtual bool ExclusiveWrite64(std::size_t core_index, VAddr vaddr, u64 value) = 0;
|
||||
};
|
||||
|
||||
std::unique_ptr<Core::ExclusiveMonitor> MakeExclusiveMonitor(Memory::MemorySystem& memory,
|
||||
std::size_t num_cores);
|
||||
|
||||
} // namespace Core
|
@ -13,7 +13,8 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "common/texture.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_ARM64)
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
|
||||
#include "core/arm/dynarmic/arm_dynarmic.h"
|
||||
#endif
|
||||
#include "core/arm/dyncom/arm_dyncom.h"
|
||||
@ -46,7 +47,7 @@
|
||||
#include "core/rpc/rpc_server.h"
|
||||
#include "core/settings.h"
|
||||
#include "network/network.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/common/renderer.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
namespace Core {
|
||||
@ -364,11 +365,12 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
|
||||
kernel = std::make_unique<Kernel::KernelSystem>(
|
||||
*memory, *timing, [this] { PrepareReschedule(); }, system_mode, num_cores, n3ds_mode);
|
||||
|
||||
exclusive_monitor = MakeExclusiveMonitor(*memory, num_cores);
|
||||
if (Settings::values.use_cpu_jit) {
|
||||
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_ARM64)
|
||||
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
|
||||
for (u32 i = 0; i < num_cores; ++i) {
|
||||
cpu_cores.push_back(
|
||||
std::make_shared<ARM_Dynarmic>(this, *memory, i, timing->GetTimer(i)));
|
||||
std::make_shared<ARM_Dynarmic>(this, *memory, i, timing->GetTimer(i), *exclusive_monitor));
|
||||
}
|
||||
#else
|
||||
for (u32 i = 0; i < num_cores; ++i) {
|
||||
@ -436,7 +438,7 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
|
||||
RendererBase& System::Renderer() {
|
||||
VideoCore::DisplayRenderer& System::Renderer() {
|
||||
return *VideoCore::g_renderer;
|
||||
}
|
||||
|
||||
@ -543,6 +545,7 @@ void System::Shutdown(bool is_deserializing) {
|
||||
dsp_core.reset();
|
||||
kernel.reset();
|
||||
cpu_cores.clear();
|
||||
exclusive_monitor.reset();
|
||||
timing.reset();
|
||||
|
||||
if (video_dumper && video_dumper->IsDumping()) {
|
||||
|
@ -57,10 +57,13 @@ namespace VideoDumper {
|
||||
class Backend;
|
||||
}
|
||||
|
||||
class RendererBase;
|
||||
namespace VideoCore {
|
||||
class DisplayRenderer;
|
||||
}
|
||||
|
||||
namespace Core {
|
||||
|
||||
class ExclusiveMonitor;
|
||||
class Timing;
|
||||
|
||||
class System {
|
||||
@ -205,7 +208,7 @@ public:
|
||||
return *dsp_core;
|
||||
}
|
||||
|
||||
[[nodiscard]] RendererBase& Renderer();
|
||||
[[nodiscard]] VideoCore::DisplayRenderer& Renderer();
|
||||
|
||||
/**
|
||||
* Gets a reference to the service manager.
|
||||
@ -363,6 +366,8 @@ private:
|
||||
std::unique_ptr<Kernel::KernelSystem> kernel;
|
||||
std::unique_ptr<Timing> timing;
|
||||
|
||||
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
|
||||
|
||||
private:
|
||||
static System s_instance;
|
||||
|
||||
|
@ -101,7 +101,7 @@ struct ArchiveFormatInfo {
|
||||
u32_le number_files; ///< The pre-defined number of files in the archive.
|
||||
u8 duplicate_data; ///< Whether the archive should duplicate the data.
|
||||
};
|
||||
static_assert(std::is_pod<ArchiveFormatInfo>::value, "ArchiveFormatInfo is not POD");
|
||||
static_assert(std::is_trivial_v<ArchiveFormatInfo>, "ArchiveFormatInfo is not POD");
|
||||
|
||||
class ArchiveBackend : NonCopyable {
|
||||
public:
|
||||
|
@ -12,6 +12,15 @@
|
||||
|
||||
namespace Frontend {
|
||||
|
||||
/// Information for the Graphics Backends signifying what type of screen pointer is in
|
||||
/// WindowInformation
|
||||
enum class WindowSystemType {
|
||||
Headless,
|
||||
Windows,
|
||||
X11,
|
||||
Wayland,
|
||||
};
|
||||
|
||||
struct Frame;
|
||||
/**
|
||||
* For smooth Vsync rendering, we want to always present the latest frame that the core generates,
|
||||
@ -52,19 +61,48 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a graphics context that can be used for background computation or drawing. If the
|
||||
* graphics backend doesn't require the context, then the implementation of these methods can be
|
||||
* stubs
|
||||
* Represents a drawing context that supports graphics operations.
|
||||
*/
|
||||
class GraphicsContext {
|
||||
public:
|
||||
virtual ~GraphicsContext();
|
||||
|
||||
/// Inform the driver to swap the front/back buffers and present the current image
|
||||
virtual void SwapBuffers() {}
|
||||
|
||||
/// Makes the graphics context current for the caller thread
|
||||
virtual void MakeCurrent() = 0;
|
||||
virtual void MakeCurrent() {}
|
||||
|
||||
/// Releases (dunno if this is the "right" word) the context from the caller thread
|
||||
virtual void DoneCurrent() = 0;
|
||||
virtual void DoneCurrent() {}
|
||||
|
||||
class Scoped {
|
||||
public:
|
||||
[[nodiscard]] explicit Scoped(GraphicsContext& context_) : context(context_) {
|
||||
context.MakeCurrent();
|
||||
}
|
||||
~Scoped() {
|
||||
if (active) {
|
||||
context.DoneCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
/// In the event that context was destroyed before the Scoped is destroyed, this provides a
|
||||
/// mechanism to prevent calling a destroyed object's method during the deconstructor
|
||||
void Cancel() {
|
||||
active = false;
|
||||
}
|
||||
|
||||
private:
|
||||
GraphicsContext& context;
|
||||
bool active{true};
|
||||
};
|
||||
|
||||
/// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value
|
||||
/// ends
|
||||
[[nodiscard]] Scoped Acquire() {
|
||||
return Scoped{*this};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -95,6 +133,23 @@ public:
|
||||
std::pair<unsigned, unsigned> min_client_area_size;
|
||||
};
|
||||
|
||||
/// Data describing host window system information
|
||||
struct WindowSystemInfo {
|
||||
// Window system type. Determines which GL context or Vulkan WSI is used.
|
||||
WindowSystemType type = WindowSystemType::Headless;
|
||||
|
||||
// Connection to a display server. This is used on X11 and Wayland platforms.
|
||||
void* display_connection = nullptr;
|
||||
|
||||
// Render surface. This is a pointer to the native window handle, which depends
|
||||
// on the platform. e.g. HWND for Windows, Window for X11. If the surface is
|
||||
// set to nullptr, the video backend will run in headless mode.
|
||||
void* render_surface = nullptr;
|
||||
|
||||
// Scale of the render surface. For hidpi systems, this will be >1.
|
||||
float render_surface_scale = 1.0f;
|
||||
};
|
||||
|
||||
/// Polls window events
|
||||
virtual void PollEvents() = 0;
|
||||
|
||||
@ -148,6 +203,13 @@ public:
|
||||
config = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns system information about the drawing area.
|
||||
*/
|
||||
const WindowSystemInfo& GetWindowInfo() const {
|
||||
return window_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the framebuffer layout (width, height, and screen regions)
|
||||
* @note This method is thread-safe
|
||||
@ -194,6 +256,8 @@ protected:
|
||||
framebuffer_layout = layout;
|
||||
}
|
||||
|
||||
WindowSystemInfo window_info;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Handler called when the minimal client area was requested to be changed via SetConfig.
|
||||
|
@ -20,8 +20,8 @@
|
||||
#include "core/tracer/recorder.h"
|
||||
#include "video_core/command_processor.h"
|
||||
#include "video_core/debug_utils/debug_utils.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/common/rasterizer.h"
|
||||
#include "video_core/common/renderer.h"
|
||||
#include "video_core/utils.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "audio_core/dsp_interface.h"
|
||||
#include "common/archives.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/atomic_ops.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/swap.h"
|
||||
@ -20,7 +21,9 @@
|
||||
#include "core/hle/lock.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/settings.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
//#include "video_core/renderer_base.h"
|
||||
#include "video_core/common/renderer.h"
|
||||
#include "video_core/common/rasterizer.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(Memory::MemorySystem::BackingMemImpl<Memory::Region::FCRAM>)
|
||||
@ -373,6 +376,38 @@ void MemorySystem::Write(const VAddr vaddr, const T data) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool MemorySystem::WriteExclusive(const VAddr vaddr, const T data, const T expected) {
|
||||
u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS];
|
||||
|
||||
if (page_pointer) {
|
||||
const auto volatile_pointer = reinterpret_cast<volatile T*>(&page_pointer[vaddr & PAGE_MASK]);
|
||||
return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
|
||||
}
|
||||
|
||||
PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS];
|
||||
switch (type) {
|
||||
case PageType::Unmapped:
|
||||
LOG_ERROR(HW_Memory, "unmapped Write{} 0x{:08X} @ 0x{:08X} at PC 0x{:08X}",
|
||||
sizeof(data) * 8, (u32)data, vaddr, Core::GetRunningCore().GetPC());
|
||||
return true;
|
||||
case PageType::Memory:
|
||||
ASSERT_MSG(false, "Mapped memory page without a pointer @ {:08X}", vaddr);
|
||||
return true;
|
||||
case PageType::RasterizerCachedMemory: {
|
||||
RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Invalidate);
|
||||
const auto volatile_pointer = reinterpret_cast<volatile T*>(GetPointerForRasterizerCache(vaddr).GetPtr());
|
||||
return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
|
||||
}
|
||||
case PageType::Special:
|
||||
WriteMMIO<T>(GetMMIOHandler(*impl->current_page_table, vaddr), vaddr, data);
|
||||
return false;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
|
||||
auto& page_table = *process.vm_manager.page_table;
|
||||
|
||||
@ -732,6 +767,22 @@ void MemorySystem::Write64(const VAddr addr, const u64 data) {
|
||||
Write<u64_le>(addr, data);
|
||||
}
|
||||
|
||||
bool MemorySystem::WriteExclusive8(const VAddr addr, const u8 data, const u8 expected) {
|
||||
return WriteExclusive<u8>(addr, data, expected);
|
||||
}
|
||||
|
||||
bool MemorySystem::WriteExclusive16(const VAddr addr, const u16 data, const u16 expected) {
|
||||
return WriteExclusive<u16_le>(addr, data, expected);
|
||||
}
|
||||
|
||||
bool MemorySystem::WriteExclusive32(const VAddr addr, const u32 data, const u32 expected) {
|
||||
return WriteExclusive<u32_le>(addr, data, expected);
|
||||
}
|
||||
|
||||
bool MemorySystem::WriteExclusive64(const VAddr addr, const u64 data, const u64 expected) {
|
||||
return WriteExclusive<u64_le>(addr, data, expected);
|
||||
}
|
||||
|
||||
void MemorySystem::WriteBlock(const Kernel::Process& process, const VAddr dest_addr,
|
||||
const void* src_buffer, const std::size_t size) {
|
||||
auto& page_table = *process.vm_manager.page_table;
|
||||
|
@ -327,6 +327,23 @@ public:
|
||||
void Write32(VAddr addr, u32 data);
|
||||
void Write64(VAddr addr, u64 data);
|
||||
|
||||
/**
|
||||
* Writes a {8, 16, 32, 64}-bit unsigned integer to the given virtual address in
|
||||
* the current process' address space if and only if the address contains
|
||||
* the expected value. This operation is atomic.
|
||||
*
|
||||
* @param addr The virtual address to write the X-bit unsigned integer to.
|
||||
* @param data The X-bit unsigned integer to write to the given virtual address.
|
||||
* @param expected The X-bit unsigned integer to check against the given virtual address.
|
||||
* @returns true if the operation failed
|
||||
*
|
||||
* @post The memory range [addr, sizeof(data)) contains the given data value.
|
||||
*/
|
||||
bool WriteExclusive8(const VAddr addr, const u8 data, const u8 expected);
|
||||
bool WriteExclusive16(const VAddr addr, const u16 data, const u16 expected);
|
||||
bool WriteExclusive32(const VAddr addr, const u32 data, const u32 expected);
|
||||
bool WriteExclusive64(const VAddr addr, const u64 data, const u64 expected);
|
||||
|
||||
void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer,
|
||||
std::size_t size);
|
||||
void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
|
||||
@ -384,6 +401,9 @@ private:
|
||||
template <typename T>
|
||||
void Write(const VAddr vaddr, const T data);
|
||||
|
||||
template <typename T>
|
||||
bool WriteExclusive(const VAddr vaddr, const T data, const T expected);
|
||||
|
||||
/**
|
||||
* Gets the pointer for virtual memory where the page is marked as RasterizerCachedMemory.
|
||||
* This is used to access the memory where the page pointer is nullptr due to rasterizer cache.
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "core/hle/service/ir/ir_user.h"
|
||||
#include "core/hle/service/mic_u.h"
|
||||
#include "core/settings.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/common/renderer.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
namespace Settings {
|
||||
|
@ -14,6 +14,11 @@
|
||||
|
||||
namespace Settings {
|
||||
|
||||
enum class RendererBackend : u32 {
|
||||
OpenGL = 0,
|
||||
Vulkan = 1,
|
||||
};
|
||||
|
||||
enum class InitClock {
|
||||
SystemTime = 0,
|
||||
FixedTime = 1,
|
||||
@ -24,11 +29,9 @@ enum class LayoutOption {
|
||||
SingleScreen,
|
||||
LargeScreen,
|
||||
SideScreen,
|
||||
|
||||
// Similiar to default, but better for mobile devices in portrait mode. Top screen in clamped to
|
||||
// the top of the frame, and the bottom screen is enlarged to match the top screen.
|
||||
MobilePortrait,
|
||||
|
||||
// Similiar to LargeScreen, but better for mobile devices in landscape mode. The screens are
|
||||
// clamped to the top of the frame, and the bottom screen is a bit bigger.
|
||||
MobileLandscape,
|
||||
@ -111,7 +114,6 @@ namespace NativeAnalog {
|
||||
enum Values {
|
||||
CirclePad,
|
||||
CStick,
|
||||
|
||||
NumAnalogs,
|
||||
};
|
||||
|
||||
@ -164,6 +166,8 @@ struct Values {
|
||||
u64 init_time;
|
||||
|
||||
// Renderer
|
||||
RendererBackend renderer_backend = RendererBackend::Vulkan;
|
||||
bool renderer_debug = true;
|
||||
bool use_gles;
|
||||
bool use_hw_renderer;
|
||||
bool use_hw_shader;
|
||||
|
@ -13,7 +13,7 @@ if (ENABLE_WEB_SERVICE)
|
||||
target_link_libraries(citra-room PRIVATE web_service)
|
||||
endif()
|
||||
|
||||
target_link_libraries(citra-room PRIVATE cryptopp glad)
|
||||
target_link_libraries(citra-room PRIVATE cryptopp-static glad::glad)
|
||||
if (MSVC)
|
||||
target_link_libraries(citra-room PRIVATE getopt)
|
||||
endif()
|
||||
|
@ -28,7 +28,7 @@ if(SDL2_FOUND)
|
||||
sdl/sdl_impl.cpp
|
||||
sdl/sdl_impl.h
|
||||
)
|
||||
target_link_libraries(input_common PRIVATE SDL2)
|
||||
target_link_libraries(input_common PRIVATE SDL2::SDL2)
|
||||
target_compile_definitions(input_common PRIVATE HAVE_SDL2)
|
||||
endif()
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include "core/3ds.h"
|
||||
#include "core/settings.h"
|
||||
#include "input_common/touch_from_button.h"
|
||||
|
@ -13,4 +13,4 @@ add_library(network STATIC
|
||||
|
||||
create_target_directory_groups(network)
|
||||
|
||||
target_link_libraries(network PRIVATE common enet Boost::serialization)
|
||||
target_link_libraries(network PRIVATE common unofficial::enet::enet Boost::serialization)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user