Compare commits
80 Commits
vulkan-sch
...
vulkan
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"]
|
[submodule "nihstro"]
|
||||||
path = externals/nihstro
|
path = externals/nihstro
|
||||||
url = https://github.com/neobrain/nihstro.git
|
url = https://github.com/neobrain/nihstro.git
|
||||||
[submodule "soundtouch"]
|
[submodule "soundtouch"]
|
||||||
path = externals/soundtouch
|
path = externals/soundtouch
|
||||||
url = https://github.com/citra-emu/ext-soundtouch.git
|
url = https://github.com/citra-emu/ext-soundtouch.git
|
||||||
[submodule "catch"]
|
|
||||||
path = externals/catch
|
|
||||||
url = https://github.com/philsquared/Catch.git
|
|
||||||
[submodule "dynarmic"]
|
[submodule "dynarmic"]
|
||||||
path = externals/dynarmic
|
path = externals/dynarmic
|
||||||
url = https://github.com/citra-emu/dynarmic.git
|
url = https://github.com/merryhime/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
|
|
||||||
[submodule "cubeb"]
|
[submodule "cubeb"]
|
||||||
path = externals/cubeb
|
path = externals/cubeb
|
||||||
url = https://github.com/kinetiknz/cubeb.git
|
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"]
|
[submodule "teakra"]
|
||||||
path = externals/teakra
|
path = externals/teakra
|
||||||
url = https://github.com/wwylele/teakra.git
|
url = https://github.com/wwylele/teakra.git
|
||||||
[submodule "lodepng"]
|
[submodule "externals/vma"]
|
||||||
path = externals/lodepng/lodepng
|
path = externals/vma
|
||||||
url = https://github.com/lvandeve/lodepng.git
|
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
|
||||||
[submodule "zstd"]
|
[submodule "externals/Vulkan-Headers"]
|
||||||
path = externals/zstd
|
path = externals/Vulkan-Headers
|
||||||
url = https://github.com/facebook/zstd.git
|
url = https://github.com/KhronosGroup/Vulkan-Headers
|
||||||
[submodule "libyuv"]
|
[submodule "externals/vcpkg"]
|
||||||
path = externals/libyuv
|
path = externals/vcpkg
|
||||||
url = https://github.com/lemenkov/libyuv.git
|
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 3.12 required for 20 to be a valid value for CXX_STANDARD
|
||||||
cmake_minimum_required(VERSION 3.8)
|
cmake_minimum_required(VERSION 3.12)
|
||||||
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.15)
|
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.15)
|
||||||
# Don't override the warning flags in MSVC:
|
# Don't override the warning flags in MSVC:
|
||||||
cmake_policy(SET CMP0092 NEW)
|
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}/CMakeModules")
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
|
||||||
include(DownloadExternals)
|
include(DownloadExternals)
|
||||||
@ -14,7 +17,6 @@ project(citra LANGUAGES C CXX ASM)
|
|||||||
# Set bundled sdl2/qt as dependent options.
|
# Set bundled sdl2/qt as dependent options.
|
||||||
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
|
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
|
||||||
option(ENABLE_SDL2 "Enable the SDL2 frontend" 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 "Enable the Qt frontend" ON)
|
||||||
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
|
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)
|
set(ENABLE_FFMPEG ON)
|
||||||
endif()
|
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)
|
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(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)
|
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)
|
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)
|
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)
|
DESTINATION ${PROJECT_SOURCE_DIR}/.git/hooks)
|
||||||
endif()
|
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
|
# Sanity check : Check that all submodules are present
|
||||||
# =======================================================================
|
# =======================================================================
|
||||||
|
|
||||||
@ -126,47 +132,123 @@ message(STATUS "Target architecture: ${ARCHITECTURE}")
|
|||||||
# Configure C++ standard
|
# Configure C++ standard
|
||||||
# ===========================
|
# ===========================
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
# set up output paths for executable binaries
|
# set up output paths for executable binaries
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin/$<CONFIG>)
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin/$<CONFIG>)
|
||||||
|
|
||||||
|
|
||||||
# System imported libraries
|
# 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.
|
# Prefer the -pthread flag on Linux.
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
find_package(Threads REQUIRED)
|
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 (ENABLE_SDL2)
|
||||||
if (CITRA_USE_BUNDLED_SDL2)
|
find_package(SDL2 CONFIG REQUIRED)
|
||||||
# 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()
|
|
||||||
else()
|
else()
|
||||||
set(SDL2_FOUND NO)
|
set(SDL2_FOUND NO)
|
||||||
endif()
|
endif()
|
||||||
@ -174,7 +256,7 @@ endif()
|
|||||||
if (ENABLE_QT)
|
if (ENABLE_QT)
|
||||||
if (CITRA_USE_BUNDLED_QT)
|
if (CITRA_USE_BUNDLED_QT)
|
||||||
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
|
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()
|
else()
|
||||||
message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable CITRA_USE_BUNDLED_QT and provide your own.")
|
message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable CITRA_USE_BUNDLED_QT and provide your own.")
|
||||||
endif()
|
endif()
|
||||||
@ -203,45 +285,24 @@ if(NOT APPLE)
|
|||||||
find_package(LibUSB)
|
find_package(LibUSB)
|
||||||
endif()
|
endif()
|
||||||
if (NOT LIBUSB_FOUND)
|
if (NOT LIBUSB_FOUND)
|
||||||
add_subdirectory(externals/libusb)
|
set(LIBUSB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/externals/libusb/libusb/libusb")
|
||||||
set(LIBUSB_INCLUDE_DIR "")
|
|
||||||
set(LIBUSB_LIBRARIES usb)
|
set(LIBUSB_LIBRARIES usb)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_FFMPEG)
|
if (ENABLE_FFMPEG)
|
||||||
if (CITRA_USE_BUNDLED_FFMPEG)
|
if(ENABLE_FFMPEG_VIDEO_DUMPER)
|
||||||
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
|
set(FFmpeg_COMPONENTS "avcodec avformat avutil swscale swresample")
|
||||||
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)
|
|
||||||
else()
|
else()
|
||||||
find_package(FFmpeg REQUIRED COMPONENTS avcodec)
|
set(FFmpeg_COMPONENTS "avcodec")
|
||||||
endif()
|
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)
|
find_package(FFmpeg REQUIRED COMPONENTS ${FFmpeg_COMPONENTS})
|
||||||
add_definitions(-DENABLE_FFMPEG_VIDEO_DUMPER)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_FDK)
|
if (ENABLE_FDK)
|
||||||
find_library(FDK_AAC fdk-aac DOC "The path to fdk_aac library")
|
find_package(fdk-aac CONFIG REQUIRED)
|
||||||
if(FDK_AAC STREQUAL "FDK_AAC-NOTFOUND")
|
|
||||||
message(FATAL_ERROR "fdk_aac library not found.")
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Platform-specific library requirements
|
# Platform-specific library requirements
|
||||||
# ======================================
|
# ======================================
|
||||||
|
|
||||||
@ -351,21 +412,9 @@ git_describe(GIT_DESC --always --long --dirty)
|
|||||||
git_branch_name(GIT_BRANCH)
|
git_branch_name(GIT_BRANCH)
|
||||||
get_timestamp(BUILD_DATE)
|
get_timestamp(BUILD_DATE)
|
||||||
|
|
||||||
if (NOT USE_SYSTEM_BOOST)
|
|
||||||
add_definitions( -DBOOST_ALL_NO_LIB )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
add_subdirectory(externals)
|
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(src)
|
||||||
add_subdirectory(dist/installer)
|
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(DownloadExternals)
|
||||||
include(ExternalProject)
|
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
|
# Dynarmic
|
||||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_ARM64)
|
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_ARM64)
|
||||||
set(DYNARMIC_TESTS OFF)
|
set(DYNARMIC_TESTS OFF)
|
||||||
@ -45,18 +17,11 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_ARM64)
|
|||||||
add_subdirectory(dynarmic)
|
add_subdirectory(dynarmic)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# libfmt
|
|
||||||
add_subdirectory(fmt)
|
|
||||||
add_library(fmt::fmt ALIAS fmt)
|
|
||||||
|
|
||||||
# getopt
|
# getopt
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
add_subdirectory(getopt)
|
add_subdirectory(getopt)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Glad
|
|
||||||
add_subdirectory(glad)
|
|
||||||
|
|
||||||
# inih
|
# inih
|
||||||
add_subdirectory(inih)
|
add_subdirectory(inih)
|
||||||
|
|
||||||
@ -79,66 +44,13 @@ target_include_directories(SoundTouch INTERFACE ./soundtouch/include)
|
|||||||
# Teakra
|
# Teakra
|
||||||
add_subdirectory(teakra EXCLUDE_FROM_ALL)
|
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
|
# Cubeb
|
||||||
if (ENABLE_CUBEB)
|
if (ENABLE_CUBEB)
|
||||||
set(BUILD_TESTS OFF CACHE BOOL "")
|
set(BUILD_TESTS OFF CACHE BOOL "")
|
||||||
add_subdirectory(cubeb EXCLUDE_FROM_ALL)
|
add_subdirectory(cubeb EXCLUDE_FROM_ALL)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# DiscordRPC
|
if (ENABLE_WEB_SERVICE AND ANDROID)
|
||||||
if (USE_DISCORD_PRESENCE)
|
add_subdirectory(android-ifaddrs)
|
||||||
add_subdirectory(discord-rpc EXCLUDE_FROM_ALL)
|
|
||||||
target_include_directories(discord-rpc INTERFACE ./discord-rpc/include)
|
|
||||||
endif()
|
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)
|
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
|
#define MP_LOG_LEAVE 0x0
|
||||||
|
|
||||||
|
|
||||||
inline int MicroProfileLogType(MicroProfileLogEntry Index)
|
inline uint64_t MicroProfileLogType(MicroProfileLogEntry Index)
|
||||||
{
|
{
|
||||||
return ((MP_LOG_BEGIN_MASK & Index)>>62) & 0x3;
|
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)
|
inline MicroProfileLogEntry MicroProfileMakeLogIndex(uint64_t nBegin, MicroProfileToken nToken, int64_t nTick)
|
||||||
{
|
{
|
||||||
MicroProfileLogEntry Entry = (nBegin<<62) | ((0x3fff&nToken)<<48) | (MP_LOG_TICK_MASK&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);
|
uint64_t nTimerIndex = MicroProfileLogTimerIndex(Entry);
|
||||||
MP_ASSERT(t == nBegin);
|
MP_ASSERT(t == nBegin);
|
||||||
MP_ASSERT(nTimerIndex == (nToken&0x3fff));
|
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.cpp
|
||||||
hle/fdk_decoder.h
|
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)
|
target_compile_definitions(audio_core PUBLIC HAVE_FDK)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ if(ANDROID)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(SDL2_FOUND)
|
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)
|
target_compile_definitions(audio_core PRIVATE HAVE_SDL2)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -450,7 +450,7 @@ void DspLle::SetServiceToInterrupt(std::weak_ptr<Service::DSP::DSP_DSP> dsp) {
|
|||||||
return;
|
return;
|
||||||
if (pipe == 0) {
|
if (pipe == 0) {
|
||||||
// pipe 0 is for debug. 3DS automatically drains this pipe and discards the data
|
// 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 {
|
} else {
|
||||||
std::lock_guard lock(HLE::g_hle_lock);
|
std::lock_guard lock(HLE::g_hle_lock);
|
||||||
if (auto locked = dsp.lock()) {
|
if (auto locked = dsp.lock()) {
|
||||||
|
@ -16,11 +16,11 @@ add_executable(citra
|
|||||||
create_target_directory_groups(citra)
|
create_target_directory_groups(citra)
|
||||||
|
|
||||||
target_link_libraries(citra PRIVATE common core input_common network)
|
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)
|
if (MSVC)
|
||||||
target_link_libraries(citra PRIVATE getopt)
|
target_link_libraries(citra PRIVATE getopt)
|
||||||
endif()
|
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)
|
if(UNIX AND NOT APPLE)
|
||||||
install(TARGETS citra RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
|
install(TARGETS citra RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
|
||||||
|
@ -43,7 +43,9 @@
|
|||||||
#include "core/movie.h"
|
#include "core/movie.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "network/network.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
|
#undef _UNICODE
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include "input_common/motion_emu.h"
|
#include "input_common/motion_emu.h"
|
||||||
#include "input_common/sdl/sdl.h"
|
#include "input_common/sdl/sdl.h"
|
||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
#include "video_core/renderer_base.h"
|
#include "video_core/common/renderer.h"
|
||||||
#include "video_core/video_core.h"
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
SharedContext_SDL2::SharedContext_SDL2() {
|
SharedContext_SDL2::SharedContext_SDL2() {
|
||||||
|
@ -259,8 +259,11 @@ endif()
|
|||||||
create_target_directory_groups(citra-qt)
|
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 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)
|
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
|
target_compile_definitions(citra-qt PRIVATE
|
||||||
# Use QStringBuilder for string concatenation to reduce
|
# Use QStringBuilder for string concatenation to reduce
|
||||||
|
@ -7,9 +7,9 @@
|
|||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QOffscreenSurface>
|
#include <QOffscreenSurface>
|
||||||
|
#include <glad/glad.h>
|
||||||
#include <QOpenGLContext>
|
#include <QOpenGLContext>
|
||||||
#include <QOpenGLFunctions>
|
#include <QMessageBox>
|
||||||
#include <QOpenGLFunctions_3_3_Core>
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include "citra_qt/bootmanager.h"
|
#include "citra_qt/bootmanager.h"
|
||||||
#include "citra_qt/main.h"
|
#include "citra_qt/main.h"
|
||||||
@ -24,9 +24,15 @@
|
|||||||
#include "input_common/main.h"
|
#include "input_common/main.h"
|
||||||
#include "input_common/motion_emu.h"
|
#include "input_common/motion_emu.h"
|
||||||
#include "network/network.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"
|
#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(Frontend::GraphicsContext& core_context) : core_context(core_context) {}
|
||||||
|
|
||||||
EmuThread::~EmuThread() = default;
|
EmuThread::~EmuThread() = default;
|
||||||
@ -52,6 +58,7 @@ void EmuThread::run() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
|
emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
|
||||||
|
emit HideLoadingScreen();
|
||||||
|
|
||||||
if (Core::System::GetInstance().frame_limiter.IsFrameAdvancing()) {
|
if (Core::System::GetInstance().frame_limiter.IsFrameAdvancing()) {
|
||||||
// Usually the loading screen is hidden after the first frame is drawn. In this case
|
// Usually the loading screen is hidden after the first frame is drawn. In this case
|
||||||
@ -89,7 +96,12 @@ void EmuThread::run() {
|
|||||||
emit DebugModeLeft();
|
emit DebugModeLeft();
|
||||||
|
|
||||||
exec_step = false;
|
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();
|
emit DebugModeEntered();
|
||||||
yieldCurrentThread();
|
yieldCurrentThread();
|
||||||
|
|
||||||
@ -108,87 +120,163 @@ void EmuThread::run() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLWindow::OpenGLWindow(QWindow* parent, QWidget* event_handler, QOpenGLContext* shared_context)
|
class DummyContext : public Frontend::GraphicsContext {};
|
||||||
: QWindow(parent), context(std::make_unique<QOpenGLContext>(shared_context->parent())),
|
|
||||||
event_handler(event_handler) {
|
|
||||||
|
|
||||||
// disable vsync for any shared contexts
|
class OpenGLSharedContext : public Frontend::GraphicsContext {
|
||||||
auto format = shared_context->format();
|
public:
|
||||||
format.setSwapInterval(Settings::values.use_vsync_new ? 1 : 0);
|
/// Create the original context that should be shared from
|
||||||
this->setFormat(format);
|
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);
|
// TODO: expose a setting for buffer value (ie default/single/double/triple)
|
||||||
context->setScreen(this->screen());
|
format.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior);
|
||||||
context->setFormat(format);
|
format.setSwapInterval(0);
|
||||||
context->create();
|
|
||||||
|
|
||||||
setSurfaceType(QWindow::OpenGLSurface);
|
context = std::make_unique<QOpenGLContext>();
|
||||||
|
context->setFormat(format);
|
||||||
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
|
if (!context->create()) {
|
||||||
// WA_DontShowOnScreen, WA_DeleteOnClose
|
LOG_ERROR(Frontend, "Unable to create main openGL context");
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLWindow::~OpenGLWindow() {
|
|
||||||
context->doneCurrent();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLWindow::Present() {
|
|
||||||
if (!isExposed())
|
|
||||||
return;
|
|
||||||
|
|
||||||
context->makeCurrent(this);
|
|
||||||
if (VideoCore::g_renderer) {
|
|
||||||
VideoCore::g_renderer->TryPresent(100);
|
|
||||||
}
|
}
|
||||||
context->swapBuffers(this);
|
|
||||||
auto f = context->versionFunctions<QOpenGLFunctions_3_3_Core>();
|
|
||||||
f->glFinish();
|
|
||||||
QWindow::requestUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OpenGLWindow::event(QEvent* event) {
|
/// Create the shared contexts for rendering and presentation
|
||||||
switch (event->type()) {
|
explicit OpenGLSharedContext(QOpenGLContext* share_context, QSurface* main_surface = nullptr) {
|
||||||
case QEvent::UpdateRequest:
|
|
||||||
Present();
|
// disable vsync for any shared contexts
|
||||||
return true;
|
auto format = share_context->format();
|
||||||
case QEvent::MouseButtonPress:
|
format.setSwapInterval(0);
|
||||||
case QEvent::MouseButtonRelease:
|
|
||||||
case QEvent::MouseButtonDblClick:
|
context = std::make_unique<QOpenGLContext>();
|
||||||
case QEvent::MouseMove:
|
context->setShareContext(share_context);
|
||||||
case QEvent::KeyPress:
|
context->setFormat(format);
|
||||||
case QEvent::KeyRelease:
|
if (!context->create()) {
|
||||||
case QEvent::FocusIn:
|
LOG_ERROR(Frontend, "Unable to create shared openGL context");
|
||||||
case QEvent::FocusOut:
|
}
|
||||||
case QEvent::FocusAboutToChange:
|
|
||||||
case QEvent::Enter:
|
if (!main_surface) {
|
||||||
case QEvent::Leave:
|
offscreen_surface = std::make_unique<QOffscreenSurface>(nullptr);
|
||||||
case QEvent::Wheel:
|
offscreen_surface->setFormat(format);
|
||||||
case QEvent::TabletMove:
|
offscreen_surface->create();
|
||||||
case QEvent::TabletPress:
|
surface = offscreen_surface.get();
|
||||||
case QEvent::TabletRelease:
|
} else {
|
||||||
case QEvent::TabletEnterProximity:
|
surface = main_surface;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~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) {
|
static Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) {
|
||||||
QWindow::requestUpdate();
|
Frontend::EmuWindow::WindowSystemInfo wsi;
|
||||||
QWindow::exposeEvent(event);
|
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)
|
GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread)
|
||||||
@ -215,11 +303,11 @@ GRenderWindow::~GRenderWindow() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GRenderWindow::MakeCurrent() {
|
void GRenderWindow::MakeCurrent() {
|
||||||
core_context->MakeCurrent();
|
main_context->MakeCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GRenderWindow::DoneCurrent() {
|
void GRenderWindow::DoneCurrent() {
|
||||||
core_context->DoneCurrent();
|
main_context->DoneCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GRenderWindow::PollEvents() {
|
void GRenderWindow::PollEvents() {
|
||||||
@ -384,25 +472,51 @@ void GRenderWindow::resizeEvent(QResizeEvent* event) {
|
|||||||
OnFramebufferSizeChanged();
|
OnFramebufferSizeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GRenderWindow::InitRenderTarget() {
|
bool GRenderWindow::InitRenderTarget() {
|
||||||
ReleaseRenderTarget();
|
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;
|
first_frame = false;
|
||||||
|
|
||||||
GMainWindow* parent = GetMainWindow();
|
switch (Settings::values.renderer_backend) {
|
||||||
QWindow* parent_win_handle = parent ? parent->windowHandle() : nullptr;
|
case Settings::RendererBackend::OpenGL:
|
||||||
child_window = new OpenGLWindow(parent_win_handle, this, QOpenGLContext::globalShareContext());
|
if (!InitializeOpenGL()) {
|
||||||
child_window->create();
|
return false;
|
||||||
child_widget = createWindowContainer(child_window, this);
|
}
|
||||||
|
break;
|
||||||
|
case Settings::RendererBackend::Vulkan:
|
||||||
|
if (!InitializeVulkan()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
child_widget->resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight);
|
child_widget->resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight);
|
||||||
|
|
||||||
layout()->addWidget(child_widget);
|
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);
|
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);
|
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
|
||||||
OnFramebufferSizeChanged();
|
OnFramebufferSizeChanged();
|
||||||
BackupGeometry();
|
BackupGeometry();
|
||||||
|
|
||||||
|
if (Settings::values.renderer_backend == Settings::RendererBackend::OpenGL) {
|
||||||
|
if (!LoadOpenGL()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GRenderWindow::ReleaseRenderTarget() {
|
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) {
|
void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) {
|
||||||
if (res_scale == 0)
|
if (res_scale == 0)
|
||||||
res_scale = VideoCore::GetResolutionScaleFactor();
|
res_scale = VideoCore::GetResolutionScaleFactor();
|
||||||
@ -448,29 +610,13 @@ void GRenderWindow::showEvent(QShowEvent* event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
|
std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
|
||||||
return std::make_unique<GLContext>(QOpenGLContext::globalShareContext());
|
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
|
||||||
GLContext::GLContext(QOpenGLContext* shared_context)
|
// presentation
|
||||||
: context(std::make_unique<QOpenGLContext>(shared_context->parent())),
|
return std::make_unique<OpenGLSharedContext>(c->GetShareContext(),
|
||||||
surface(std::make_unique<QOffscreenSurface>(nullptr)) {
|
child_widget->windowHandle());
|
||||||
|
}
|
||||||
// disable vsync for any shared contexts
|
|
||||||
auto format = shared_context->format();
|
return std::make_unique<DummyContext>();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
@ -24,22 +24,9 @@ class GMainWindow;
|
|||||||
class GRenderWindow;
|
class GRenderWindow;
|
||||||
|
|
||||||
namespace VideoCore {
|
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 {
|
class EmuThread final : public QThread {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -126,24 +113,6 @@ signals:
|
|||||||
void HideLoadingScreen();
|
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 {
|
class GRenderWindow : public QWidget, public Frontend::EmuWindow {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -179,7 +148,7 @@ public:
|
|||||||
|
|
||||||
void focusOutEvent(QFocusEvent* event) override;
|
void focusOutEvent(QFocusEvent* event) override;
|
||||||
|
|
||||||
void InitRenderTarget();
|
bool InitRenderTarget();
|
||||||
|
|
||||||
/// Destroy the previous run's child_widget which should also destroy the child_window
|
/// Destroy the previous run's child_widget which should also destroy the child_window
|
||||||
void ReleaseRenderTarget();
|
void ReleaseRenderTarget();
|
||||||
@ -212,13 +181,13 @@ private:
|
|||||||
|
|
||||||
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
|
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;
|
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
|
/// 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
|
/// 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
|
/// parented to GRenderWindow and use Qt's lifetime system
|
||||||
|
@ -49,9 +49,10 @@ CheatDialog::~CheatDialog() = default;
|
|||||||
void CheatDialog::LoadCheats() {
|
void CheatDialog::LoadCheats() {
|
||||||
cheats = Core::System::GetInstance().CheatEngine().GetCheats();
|
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();
|
QCheckBox* enabled = new QCheckBox();
|
||||||
enabled->setChecked(cheats[i]->IsEnabled());
|
enabled->setChecked(cheats[i]->IsEnabled());
|
||||||
enabled->setStyleSheet(QStringLiteral("margin-left:7px;"));
|
enabled->setStyleSheet(QStringLiteral("margin-left:7px;"));
|
||||||
|
@ -944,14 +944,14 @@ void Config::SaveMultiplayerValues() {
|
|||||||
// Write ban list
|
// Write ban list
|
||||||
qt_config->beginWriteArray(QStringLiteral("username_ban_list"));
|
qt_config->beginWriteArray(QStringLiteral("username_ban_list"));
|
||||||
for (std::size_t i = 0; i < UISettings::values.ban_list.first.size(); ++i) {
|
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"),
|
WriteSetting(QStringLiteral("username"),
|
||||||
QString::fromStdString(UISettings::values.ban_list.first[i]));
|
QString::fromStdString(UISettings::values.ban_list.first[i]));
|
||||||
}
|
}
|
||||||
qt_config->endArray();
|
qt_config->endArray();
|
||||||
qt_config->beginWriteArray(QStringLiteral("ip_ban_list"));
|
qt_config->beginWriteArray(QStringLiteral("ip_ban_list"));
|
||||||
for (std::size_t i = 0; i < UISettings::values.ban_list.second.size(); ++i) {
|
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"),
|
WriteSetting(QStringLiteral("ip"),
|
||||||
QString::fromStdString(UISettings::values.ban_list.second[i]));
|
QString::fromStdString(UISettings::values.ban_list.second[i]));
|
||||||
}
|
}
|
||||||
|
@ -256,7 +256,7 @@ void ConfigureCamera::SetConfiguration() {
|
|||||||
int index = GetSelectedCameraIndex();
|
int index = GetSelectedCameraIndex();
|
||||||
for (std::size_t i = 0; i < Implementations.size(); i++) {
|
for (std::size_t i = 0; i < Implementations.size(); i++) {
|
||||||
if (Implementations[i] == camera_name[index]) {
|
if (Implementations[i] == camera_name[index]) {
|
||||||
ui->image_source->setCurrentIndex(i);
|
ui->image_source->setCurrentIndex(static_cast<int>(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (camera_name[index] == "image") {
|
if (camera_name[index] == "image") {
|
||||||
|
@ -14,8 +14,8 @@ ConfigureEnhancements::ConfigureEnhancements(QWidget* parent)
|
|||||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureEnhancements>()) {
|
: QWidget(parent), ui(std::make_unique<Ui::ConfigureEnhancements>()) {
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
for (const auto& filter : OpenGL::TextureFilterer::GetFilterNames())
|
//for (const auto& filter : OpenGL::TextureFilterer::GetFilterNames())
|
||||||
ui->texture_filter_combobox->addItem(QString::fromStdString(filter.data()));
|
// ui->texture_filter_combobox->addItem(QString::fromStdString(filter.data()));
|
||||||
|
|
||||||
SetConfiguration();
|
SetConfiguration();
|
||||||
|
|
||||||
@ -89,12 +89,12 @@ void ConfigureEnhancements::updateShaders(Settings::StereoRenderOption stereo_op
|
|||||||
|
|
||||||
ui->shader_combobox->setCurrentIndex(0);
|
ui->shader_combobox->setCurrentIndex(0);
|
||||||
|
|
||||||
for (const auto& shader : OpenGL::GetPostProcessingShaderList(
|
/*for (const auto& shader : OpenGL::GetPostProcessingShaderList(
|
||||||
stereo_option == Settings::StereoRenderOption::Anaglyph)) {
|
stereo_option == Settings::StereoRenderOption::Anaglyph)) {
|
||||||
ui->shader_combobox->addItem(QString::fromStdString(shader));
|
ui->shader_combobox->addItem(QString::fromStdString(shader));
|
||||||
if (Settings::values.pp_shader_name == shader)
|
if (Settings::values.pp_shader_name == shader)
|
||||||
ui->shader_combobox->setCurrentIndex(ui->shader_combobox->count() - 1);
|
ui->shader_combobox->setCurrentIndex(ui->shader_combobox->count() - 1);
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureEnhancements::RetranslateUI() {
|
void ConfigureEnhancements::RetranslateUI() {
|
||||||
|
@ -76,7 +76,7 @@ void IPCRecorderWidget::OnEntryUpdated(IPCDebugger::RequestRecord record) {
|
|||||||
QTreeWidgetItem entry{
|
QTreeWidgetItem entry{
|
||||||
{QString::number(record.id), GetStatusStr(record), service, GetFunctionName(record)}};
|
{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) {
|
if (ui->main->invisibleRootItem()->childCount() > row_id) {
|
||||||
records[row_id] = record;
|
records[row_id] = record;
|
||||||
(*ui->main->invisibleRootItem()->child(row_id)) = entry;
|
(*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
|
// 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.
|
// continuously and only the 'Clear' action can be performed, this is enough.
|
||||||
// The initial value is 1, which means record 1 = row 0.
|
// 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;
|
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) {
|
void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
|
||||||
const int game_dir_index = selected.data(GameListDir::GameDirRole).toInt();
|
const int game_dir_index = selected.data(GameListDir::GameDirRole).toInt();
|
||||||
|
|
||||||
QAction* move_up = context_menu.addAction(tr(u8"\U000025b2 Move Up"));
|
QAction* move_up = context_menu.addAction(tr("Move Up"));
|
||||||
QAction* move_down = context_menu.addAction(tr(u8"\U000025bc Move Down "));
|
QAction* move_down = context_menu.addAction(tr("Move Down"));
|
||||||
QAction* open_directory_location = context_menu.addAction(tr("Open Directory Location"));
|
QAction* open_directory_location = context_menu.addAction(tr("Open Directory Location"));
|
||||||
|
|
||||||
const int row = selected.row();
|
const int row = selected.row();
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
#include "core/loader/smdh.h"
|
#include "core/loader/smdh.h"
|
||||||
#include "ui_loading_screen.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"(
|
constexpr char PROGRESSBAR_STYLE_PREPARE[] = R"(
|
||||||
QProgressBar {}
|
QProgressBar {}
|
||||||
|
@ -17,7 +17,7 @@ class LoadingScreen;
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace VideoCore {
|
namespace VideoCore {
|
||||||
enum class LoadCallbackStage;
|
enum class LoadCallbackStage : unsigned char;
|
||||||
}
|
}
|
||||||
|
|
||||||
class QGraphicsOpacityEffect;
|
class QGraphicsOpacityEffect;
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QOpenGLFunctions_3_3_Core>
|
|
||||||
#include <QSysInfo>
|
#include <QSysInfo>
|
||||||
#include <QtConcurrent/QtConcurrentRun>
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
#include <QtGui>
|
#include <QtGui>
|
||||||
@ -764,7 +763,7 @@ void GMainWindow::ConnectMenuEvents() {
|
|||||||
connect(ui->action_Close_Movie, &QAction::triggered, this, &GMainWindow::OnCloseMovie);
|
connect(ui->action_Close_Movie, &QAction::triggered, this, &GMainWindow::OnCloseMovie);
|
||||||
connect(ui->action_Save_Movie, &QAction::triggered, this, &GMainWindow::OnSaveMovie);
|
connect(ui->action_Save_Movie, &QAction::triggered, this, &GMainWindow::OnSaveMovie);
|
||||||
connect(ui->action_Movie_Read_Only_Mode, &QAction::toggled, this,
|
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] {
|
connect(ui->action_Enable_Frame_Advancing, &QAction::triggered, this, [this] {
|
||||||
if (emulation_running) {
|
if (emulation_running) {
|
||||||
Core::System::GetInstance().frame_limiter.SetFrameAdvancing(
|
Core::System::GetInstance().frame_limiter.SetFrameAdvancing(
|
||||||
@ -911,19 +910,12 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
|||||||
if (emu_thread != nullptr)
|
if (emu_thread != nullptr)
|
||||||
ShutdownGame();
|
ShutdownGame();
|
||||||
|
|
||||||
render_window->InitRenderTarget();
|
if (!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);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Frontend::ScopeAcquireContext scope(*render_window);
|
||||||
|
|
||||||
Core::System& system{Core::System::GetInstance()};
|
Core::System& system{Core::System::GetInstance()};
|
||||||
|
|
||||||
const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};
|
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."));
|
"proper drivers for your graphics card from the manufacturer's website."));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Core::System::ResultStatus::ErrorVideoCore_ErrorBelowGL33:
|
|
||||||
QMessageBox::critical(this, below_gl33_title, below_gl33_message);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
QMessageBox::critical(
|
QMessageBox::critical(
|
||||||
this, tr("Error while loading ROM!"),
|
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) {
|
const auto cia_progress = [&](std::size_t written, std::size_t total) {
|
||||||
emit UpdateProgress(written, 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);
|
status = Service::AM::InstallCIA(current_path.toStdString(), cia_progress);
|
||||||
emit CIAInstallReport(status, current_path);
|
emit CIAInstallReport(status, current_path);
|
||||||
}
|
}
|
||||||
@ -1963,7 +1951,8 @@ void GMainWindow::OnCaptureScreenshot() {
|
|||||||
png_dialog.setAcceptMode(QFileDialog::AcceptSave);
|
png_dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||||
png_dialog.setDefaultSuffix(QStringLiteral("png"));
|
png_dialog.setDefaultSuffix(QStringLiteral("png"));
|
||||||
if (png_dialog.exec()) {
|
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()) {
|
if (!path.isEmpty()) {
|
||||||
UISettings::values.screenshot_path = QFileInfo(path).path();
|
UISettings::values.screenshot_path = QFileInfo(path).path();
|
||||||
render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, 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 + "..";
|
std::string bin_path = FileUtil::GetBundleDirectory() + DIR_SEP + "..";
|
||||||
chdir(bin_path.c_str());
|
chdir(bin_path.c_str());
|
||||||
#endif
|
#endif
|
||||||
QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
|
|
||||||
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
|
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
// Qt changes the locale and causes issues in float conversion using std::to_string() when
|
// 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
|
announce_multiplayer_room.h
|
||||||
archives.h
|
archives.h
|
||||||
assert.h
|
assert.h
|
||||||
|
atomic_ops.h
|
||||||
detached_tasks.cpp
|
detached_tasks.cpp
|
||||||
detached_tasks.h
|
detached_tasks.h
|
||||||
bit_field.h
|
bit_field.h
|
||||||
|
bit_field_array.h
|
||||||
bit_set.h
|
bit_set.h
|
||||||
cityhash.cpp
|
cityhash.cpp
|
||||||
cityhash.h
|
cityhash.h
|
||||||
@ -69,7 +71,9 @@ add_library(common STATIC
|
|||||||
construct.h
|
construct.h
|
||||||
file_util.cpp
|
file_util.cpp
|
||||||
file_util.h
|
file_util.h
|
||||||
|
flag.h
|
||||||
hash.h
|
hash.h
|
||||||
|
intrusive_ptr.h
|
||||||
linear_disk_cache.h
|
linear_disk_cache.h
|
||||||
logging/backend.cpp
|
logging/backend.cpp
|
||||||
logging/backend.h
|
logging/backend.h
|
||||||
@ -85,6 +89,8 @@ add_library(common STATIC
|
|||||||
microprofile.h
|
microprofile.h
|
||||||
microprofileui.h
|
microprofileui.h
|
||||||
misc.cpp
|
misc.cpp
|
||||||
|
object_pool.cpp
|
||||||
|
object_pool.h
|
||||||
param_package.cpp
|
param_package.cpp
|
||||||
param_package.h
|
param_package.h
|
||||||
quaternion.h
|
quaternion.h
|
||||||
@ -92,6 +98,7 @@ add_library(common STATIC
|
|||||||
scm_rev.cpp
|
scm_rev.cpp
|
||||||
scm_rev.h
|
scm_rev.h
|
||||||
scope_exit.h
|
scope_exit.h
|
||||||
|
semaphore.h
|
||||||
serialization/atomic.h
|
serialization/atomic.h
|
||||||
serialization/boost_discrete_interval.hpp
|
serialization/boost_discrete_interval.hpp
|
||||||
serialization/boost_flat_set.h
|
serialization/boost_flat_set.h
|
||||||
@ -125,12 +132,18 @@ if(ARCHITECTURE_x86_64)
|
|||||||
x64/xbyak_abi.h
|
x64/xbyak_abi.h
|
||||||
x64/xbyak_util.h
|
x64/xbyak_util.h
|
||||||
)
|
)
|
||||||
|
elseif(ARCHITECTURE_arm64)
|
||||||
|
target_sources(common
|
||||||
|
PRIVATE
|
||||||
|
aarch64/cpu_detect.cpp
|
||||||
|
aarch64/cpu_detect.h
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
create_target_directory_groups(common)
|
create_target_directory_groups(common)
|
||||||
|
|
||||||
target_link_libraries(common PUBLIC fmt microprofile Boost::boost Boost::serialization)
|
target_link_libraries(common PUBLIC fmt::fmt microprofile Boost::boost Boost::serialization)
|
||||||
target_link_libraries(common PRIVATE libzstd_static)
|
target_link_libraries(common PRIVATE zstd::libzstd_shared)
|
||||||
if (ARCHITECTURE_x86_64)
|
if (ARCHITECTURE_x86_64)
|
||||||
target_link_libraries(common PRIVATE xbyak)
|
target_link_libraries(common PRIVATE xbyak::xbyak)
|
||||||
endif()
|
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>
|
template <typename T>
|
||||||
[[nodiscard]] constexpr T AlignUp(T value, std::size_t size) {
|
[[nodiscard]] constexpr T AlignUp(T value, std::size_t size) {
|
||||||
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
|
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;
|
value -= mod;
|
||||||
return static_cast<T>(mod == T{0} ? value : value + size);
|
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/common_funcs.h"
|
||||||
#include "common/swap.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
|
* Abstract bitfield class
|
||||||
*
|
*
|
||||||
@ -110,6 +122,7 @@
|
|||||||
*/
|
*/
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
template <std::size_t Position, std::size_t Bits, typename T, typename EndianTag = LETag>
|
template <std::size_t Position, std::size_t Bits, typename T, typename EndianTag = LETag>
|
||||||
|
requires ValidType<T>
|
||||||
struct BitField {
|
struct BitField {
|
||||||
private:
|
private:
|
||||||
// UnderlyingType is T for non-enum types and the underlying type of T if
|
// 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;
|
std::enable_if<true, T>>::type;
|
||||||
|
|
||||||
// We store the value as the unsigned type to avoid undefined behaviour on value shifting
|
// 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;
|
using StorageTypeWithEndian = typename AddEndian<StorageType, EndianTag>::type;
|
||||||
|
|
||||||
@ -199,3 +212,38 @@ private:
|
|||||||
|
|
||||||
template <std::size_t Position, std::size_t Bits, typename T>
|
template <std::size_t Position, std::size_t Bits, typename T>
|
||||||
using BitFieldBE = BitField<Position, Bits, T, BETag>;
|
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_BYTES(num_bytes) u8 CONCAT2(pad, __LINE__)[(num_bytes)]
|
||||||
#define INSERT_PADDING_WORDS(num_words) u32 CONCAT2(pad, __LINE__)[(num_words)]
|
#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
|
// Inlining
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define FORCE_INLINE __forceinline
|
#define FORCE_INLINE __forceinline
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#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 VAddr; ///< Represents a pointer in the userspace virtual address space.
|
||||||
typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical 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
|
// An inheritable class to disallow the copy constructor and operator= functions
|
||||||
class NonCopyable {
|
class NonCopyable {
|
||||||
protected:
|
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 {
|
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
|
* Computes a 64-bit hash over the specified block of data
|
||||||
* @param data Block of data to compute hash over
|
* @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));
|
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.
|
/// A helper template that ensures the padding in a struct is initialized by memsetting to 0.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct HashableStruct {
|
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"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
// defined in Version.cpp
|
// defined in Version.cpp
|
||||||
extern const char* scm_rev_git_str;
|
const char* scm_rev_git_str = "DUMMY";
|
||||||
|
|
||||||
// On disk format:
|
// On disk format:
|
||||||
// header{
|
// header{
|
||||||
|
@ -235,6 +235,7 @@ void DebuggerBackend::Write(const Entry& entry) {
|
|||||||
CLS(Render) \
|
CLS(Render) \
|
||||||
SUB(Render, Software) \
|
SUB(Render, Software) \
|
||||||
SUB(Render, OpenGL) \
|
SUB(Render, OpenGL) \
|
||||||
|
SUB(Render, Vulkan) \
|
||||||
CLS(Audio) \
|
CLS(Audio) \
|
||||||
SUB(Audio, DSP) \
|
SUB(Audio, DSP) \
|
||||||
SUB(Audio, Sink) \
|
SUB(Audio, Sink) \
|
||||||
|
@ -4,10 +4,24 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <type_traits>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include "common/common_types.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 {
|
namespace Log {
|
||||||
|
|
||||||
// trims up to and including the last of ../, ..\, src/, src\ in a string
|
// 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, ///< Emulator video output and hardware acceleration
|
||||||
Render_Software, ///< Software renderer backend
|
Render_Software, ///< Software renderer backend
|
||||||
Render_OpenGL, ///< OpenGL backend
|
Render_OpenGL, ///< OpenGL backend
|
||||||
|
Render_Vulkan, ///< Vulkan backend
|
||||||
Audio, ///< Audio emulation
|
Audio, ///< Audio emulation
|
||||||
Audio_DSP, ///< The HLE and LLE implementations of the DSP
|
Audio_DSP, ///< The HLE and LLE implementations of the DSP
|
||||||
Audio_Sink, ///< Emulator audio output backend
|
Audio_Sink, ///< Emulator audio output backend
|
||||||
|
@ -39,6 +39,11 @@ struct Rectangle {
|
|||||||
return Rectangle{left, top, static_cast<T>(left + GetWidth() * s),
|
return Rectangle{left, top, static_cast<T>(left + GetWidth() * s),
|
||||||
static_cast<T>(top + GetHeight() * 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>
|
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);
|
ASSERT(tex.size() == width * height * 4);
|
||||||
const u64 line_size = width * 4;
|
const u64 line_size = width * 4;
|
||||||
for (u64 line = 0; line < height / 2; line++) {
|
for (u64 line = 0; line < height / 2; line++) {
|
||||||
const u32 offset_1 = line * line_size;
|
const u64 offset_1 = line * line_size;
|
||||||
const u32 offset_2 = (height - line - 1) * line_size;
|
const u64 offset_2 = (height - line - 1) * line_size;
|
||||||
// Swap lines
|
// Swap lines
|
||||||
std::swap_ranges(tex.begin() + offset_1, tex.begin() + offset_1 + line_size,
|
std::swap_ranges(tex.begin() + offset_1, tex.begin() + offset_1 + line_size,
|
||||||
tex.begin() + offset_2);
|
tex.begin() + offset_2);
|
||||||
|
@ -72,6 +72,9 @@ public:
|
|||||||
return Vec2{f, f};
|
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 {
|
[[nodiscard]] constexpr Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
|
||||||
return {x + other.x, y + other.y};
|
return {x + other.x, y + other.y};
|
||||||
}
|
}
|
||||||
@ -184,6 +187,8 @@ template <typename T, typename V>
|
|||||||
}
|
}
|
||||||
|
|
||||||
using Vec2f = Vec2<float>;
|
using Vec2f = Vec2<float>;
|
||||||
|
using Vec2u = Vec2<unsigned>;
|
||||||
|
using Vec2i = Vec2<int>;
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline float Vec2<float>::Length() const {
|
inline float Vec2<float>::Length() const {
|
||||||
@ -228,6 +233,9 @@ public:
|
|||||||
return Vec3(f, f, f);
|
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 {
|
[[nodiscard]] constexpr Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
|
||||||
return {x + other.x, y + other.y, z + other.z};
|
return {x + other.x, y + other.y, z + other.z};
|
||||||
}
|
}
|
||||||
@ -412,6 +420,8 @@ inline float Vec3<float>::Normalize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
using Vec3f = Vec3<float>;
|
using Vec3f = Vec3<float>;
|
||||||
|
using Vec3u = Vec3<unsigned>;
|
||||||
|
using Vec3i = Vec3<int>;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class Vec4 {
|
class Vec4 {
|
||||||
@ -448,6 +458,9 @@ public:
|
|||||||
return Vec4(f, f, f, f);
|
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 {
|
[[nodiscard]] constexpr Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
|
||||||
return {x + other.x, y + other.y, z + other.z, w + other.w};
|
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 Vec4f = Vec4<float>;
|
||||||
|
using Vec4u = Vec4<unsigned>;
|
||||||
|
using Vec4i = Vec4<int>;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b) {
|
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,
|
inline ABIFrameInfo ABI_CalculateFrameSize(std::bitset<32> regs, std::size_t rsp_alignment,
|
||||||
std::size_t needed_frame_size) {
|
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;
|
rsp_alignment -= count * 8;
|
||||||
std::size_t subtraction = 0;
|
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 (xmm_count) {
|
||||||
// If we have any XMMs to save, we must align the stack here.
|
// If we have any XMMs to save, we must align the stack here.
|
||||||
subtraction = rsp_alignment & 0xF;
|
subtraction = rsp_alignment & 0xF;
|
||||||
|
@ -14,6 +14,8 @@ add_library(core STATIC
|
|||||||
arm/dyncom/arm_dyncom_thumb.h
|
arm/dyncom/arm_dyncom_thumb.h
|
||||||
arm/dyncom/arm_dyncom_trans.cpp
|
arm/dyncom/arm_dyncom_trans.cpp
|
||||||
arm/dyncom/arm_dyncom_trans.h
|
arm/dyncom/arm_dyncom_trans.h
|
||||||
|
arm/exclusive_monitor.cpp
|
||||||
|
arm/exclusive_monitor.h
|
||||||
arm/skyeye_common/arm_regformat.h
|
arm/skyeye_common/arm_regformat.h
|
||||||
arm/skyeye_common/armstate.cpp
|
arm/skyeye_common/armstate.cpp
|
||||||
arm/skyeye_common/armstate.h
|
arm/skyeye_common/armstate.h
|
||||||
@ -473,7 +475,7 @@ endif()
|
|||||||
create_target_directory_groups(core)
|
create_target_directory_groups(core)
|
||||||
|
|
||||||
target_link_libraries(core PUBLIC common PRIVATE audio_core network video_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)
|
if (ENABLE_WEB_SERVICE)
|
||||||
target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE -DCPPHTTPLIB_OPENSSL_SUPPORT)
|
target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE -DCPPHTTPLIB_OPENSSL_SUPPORT)
|
||||||
@ -483,12 +485,14 @@ if (ENABLE_WEB_SERVICE)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_ARM64)
|
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||||
target_sources(core PRIVATE
|
target_sources(core PRIVATE
|
||||||
arm/dynarmic/arm_dynarmic.cpp
|
arm/dynarmic/arm_dynarmic.cpp
|
||||||
arm/dynarmic/arm_dynarmic.h
|
arm/dynarmic/arm_dynarmic.h
|
||||||
arm/dynarmic/arm_dynarmic_cp15.cpp
|
arm/dynarmic/arm_dynarmic_cp15.cpp
|
||||||
arm/dynarmic/arm_dynarmic_cp15.h
|
arm/dynarmic/arm_dynarmic_cp15.h
|
||||||
|
arm/dynarmic/arm_exclusive_monitor.cpp
|
||||||
|
arm/dynarmic/arm_exclusive_monitor.h
|
||||||
)
|
)
|
||||||
target_link_libraries(core PRIVATE dynarmic)
|
target_link_libraries(core PRIVATE dynarmic)
|
||||||
endif()
|
endif()
|
||||||
|
@ -122,6 +122,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void InvalidateCacheRange(u32 start_address, std::size_t length) = 0;
|
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
|
/// Notify CPU emulation that page tables have changed
|
||||||
virtual void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) = 0;
|
virtual void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) = 0;
|
||||||
|
|
||||||
|
@ -3,12 +3,14 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <dynarmic/A32/a32.h>
|
#include <dynarmic/interface/A32/a32.h>
|
||||||
#include <dynarmic/A32/context.h>
|
#include <dynarmic/interface/A32/context.h>
|
||||||
|
#include <dynarmic/interface/optimization_flags.h>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/microprofile.h"
|
#include "common/microprofile.h"
|
||||||
#include "core/arm/dynarmic/arm_dynarmic.h"
|
#include "core/arm/dynarmic/arm_dynarmic.h"
|
||||||
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
|
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
|
||||||
|
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/gdbstub/gdbstub.h"
|
#include "core/gdbstub/gdbstub.h"
|
||||||
@ -100,10 +102,23 @@ public:
|
|||||||
memory.Write64(vaddr, value);
|
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 {
|
void InterpreterFallback(VAddr pc, std::size_t num_instructions) override {
|
||||||
// Should never happen.
|
// Should never happen.
|
||||||
UNREACHABLE_MSG("InterpeterFallback reached with pc = 0x{:08x}, code = 0x{:08x}, num = {}",
|
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 {
|
void CallSVC(std::uint32_t swi) override {
|
||||||
@ -133,7 +148,7 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", exception,
|
ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", exception,
|
||||||
pc, MemoryReadCode(pc));
|
pc, MemoryReadCode(pc).value());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddTicks(std::uint64_t ticks) override {
|
void AddTicks(std::uint64_t ticks) override {
|
||||||
@ -149,10 +164,12 @@ public:
|
|||||||
Memory::MemorySystem& memory;
|
Memory::MemorySystem& memory;
|
||||||
};
|
};
|
||||||
|
|
||||||
ARM_Dynarmic::ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory, u32 id,
|
ARM_Dynarmic::ARM_Dynarmic(Core::System* system_, Memory::MemorySystem& memory_, u32 core_id_,
|
||||||
std::shared_ptr<Core::Timing::Timer> timer)
|
std::shared_ptr<Core::Timing::Timer> timer_,
|
||||||
: ARM_Interface(id, timer), system(*system), memory(memory),
|
Core::ExclusiveMonitor& exclusive_monitor_)
|
||||||
cb(std::make_unique<DynarmicUserCallbacks>(*this)) {
|
: 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());
|
SetPageTable(memory.GetCurrentPageTable());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,6 +308,10 @@ void ARM_Dynarmic::InvalidateCacheRange(u32 start_address, std::size_t length) {
|
|||||||
jit->InvalidateCacheRange(start_address, length);
|
jit->InvalidateCacheRange(start_address, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ARM_Dynarmic::ClearExclusiveState() {
|
||||||
|
jit->ClearExclusiveState();
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<Memory::PageTable> ARM_Dynarmic::GetPageTable() const {
|
std::shared_ptr<Memory::PageTable> ARM_Dynarmic::GetPageTable() const {
|
||||||
return current_page_table;
|
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.page_table = ¤t_page_table->GetPointerArray();
|
||||||
config.coprocessors[15] = std::make_shared<DynarmicCP15>(cp15_state);
|
config.coprocessors[15] = std::make_shared<DynarmicCP15>(cp15_state);
|
||||||
config.define_unpredictable_behaviour = true;
|
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);
|
return std::make_unique<Dynarmic::A32::Jit>(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <dynarmic/A32/a32.h>
|
#include <dynarmic/interface/A32/a32.h>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
|
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
|
||||||
@ -17,6 +17,8 @@ class MemorySystem;
|
|||||||
} // namespace Memory
|
} // namespace Memory
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
class DynarmicExclusiveMonitor;
|
||||||
|
class ExclusiveMonitor;
|
||||||
class System;
|
class System;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,8 +26,9 @@ class DynarmicUserCallbacks;
|
|||||||
|
|
||||||
class ARM_Dynarmic final : public ARM_Interface {
|
class ARM_Dynarmic final : public ARM_Interface {
|
||||||
public:
|
public:
|
||||||
ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory, u32 id,
|
explicit ARM_Dynarmic(Core::System* system_, Memory::MemorySystem& memory_, u32 core_id_,
|
||||||
std::shared_ptr<Core::Timing::Timer> timer);
|
std::shared_ptr<Core::Timing::Timer> timer,
|
||||||
|
Core::ExclusiveMonitor& exclusive_monitor_);
|
||||||
~ARM_Dynarmic() override;
|
~ARM_Dynarmic() override;
|
||||||
|
|
||||||
void Run() override;
|
void Run() override;
|
||||||
@ -52,6 +55,7 @@ public:
|
|||||||
|
|
||||||
void ClearInstructionCache() override;
|
void ClearInstructionCache() override;
|
||||||
void InvalidateCacheRange(u32 start_address, std::size_t length) 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 SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) override;
|
||||||
void PurgeState() override;
|
void PurgeState() override;
|
||||||
|
|
||||||
@ -69,6 +73,7 @@ private:
|
|||||||
|
|
||||||
u32 fpexc = 0;
|
u32 fpexc = 0;
|
||||||
CP15State cp15_state;
|
CP15State cp15_state;
|
||||||
|
Core::DynarmicExclusiveMonitor& exclusive_monitor;
|
||||||
|
|
||||||
Dynarmic::A32::Jit* jit = nullptr;
|
Dynarmic::A32::Jit* jit = nullptr;
|
||||||
std::shared_ptr<Memory::PageTable> current_page_table = nullptr;
|
std::shared_ptr<Memory::PageTable> current_page_table = nullptr;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <dynarmic/A32/coprocessor.h>
|
#include <dynarmic/interface/A32/coprocessor.h>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
struct CP15State {
|
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 ClearInstructionCache() override;
|
||||||
void InvalidateCacheRange(u32 start_address, std::size_t length) override;
|
void InvalidateCacheRange(u32 start_address, std::size_t length) override;
|
||||||
|
void ClearExclusiveState() override {};
|
||||||
|
|
||||||
void SetPC(u32 pc) override;
|
void SetPC(u32 pc) override;
|
||||||
u32 GetPC() const 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/logging/log.h"
|
||||||
#include "common/texture.h"
|
#include "common/texture.h"
|
||||||
#include "core/arm/arm_interface.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"
|
#include "core/arm/dynarmic/arm_dynarmic.h"
|
||||||
#endif
|
#endif
|
||||||
#include "core/arm/dyncom/arm_dyncom.h"
|
#include "core/arm/dyncom/arm_dyncom.h"
|
||||||
@ -46,7 +47,7 @@
|
|||||||
#include "core/rpc/rpc_server.h"
|
#include "core/rpc/rpc_server.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
#include "video_core/renderer_base.h"
|
#include "video_core/common/renderer.h"
|
||||||
#include "video_core/video_core.h"
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
@ -364,11 +365,12 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
|
|||||||
kernel = std::make_unique<Kernel::KernelSystem>(
|
kernel = std::make_unique<Kernel::KernelSystem>(
|
||||||
*memory, *timing, [this] { PrepareReschedule(); }, system_mode, num_cores, n3ds_mode);
|
*memory, *timing, [this] { PrepareReschedule(); }, system_mode, num_cores, n3ds_mode);
|
||||||
|
|
||||||
|
exclusive_monitor = MakeExclusiveMonitor(*memory, num_cores);
|
||||||
if (Settings::values.use_cpu_jit) {
|
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) {
|
for (u32 i = 0; i < num_cores; ++i) {
|
||||||
cpu_cores.push_back(
|
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
|
#else
|
||||||
for (u32 i = 0; i < num_cores; ++i) {
|
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;
|
return ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
RendererBase& System::Renderer() {
|
VideoCore::DisplayRenderer& System::Renderer() {
|
||||||
return *VideoCore::g_renderer;
|
return *VideoCore::g_renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -543,6 +545,7 @@ void System::Shutdown(bool is_deserializing) {
|
|||||||
dsp_core.reset();
|
dsp_core.reset();
|
||||||
kernel.reset();
|
kernel.reset();
|
||||||
cpu_cores.clear();
|
cpu_cores.clear();
|
||||||
|
exclusive_monitor.reset();
|
||||||
timing.reset();
|
timing.reset();
|
||||||
|
|
||||||
if (video_dumper && video_dumper->IsDumping()) {
|
if (video_dumper && video_dumper->IsDumping()) {
|
||||||
|
@ -57,10 +57,13 @@ namespace VideoDumper {
|
|||||||
class Backend;
|
class Backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
class RendererBase;
|
namespace VideoCore {
|
||||||
|
class DisplayRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
|
class ExclusiveMonitor;
|
||||||
class Timing;
|
class Timing;
|
||||||
|
|
||||||
class System {
|
class System {
|
||||||
@ -205,7 +208,7 @@ public:
|
|||||||
return *dsp_core;
|
return *dsp_core;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] RendererBase& Renderer();
|
[[nodiscard]] VideoCore::DisplayRenderer& Renderer();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a reference to the service manager.
|
* Gets a reference to the service manager.
|
||||||
@ -363,6 +366,8 @@ private:
|
|||||||
std::unique_ptr<Kernel::KernelSystem> kernel;
|
std::unique_ptr<Kernel::KernelSystem> kernel;
|
||||||
std::unique_ptr<Timing> timing;
|
std::unique_ptr<Timing> timing;
|
||||||
|
|
||||||
|
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static System s_instance;
|
static System s_instance;
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ struct ArchiveFormatInfo {
|
|||||||
u32_le number_files; ///< The pre-defined number of files in the archive.
|
u32_le number_files; ///< The pre-defined number of files in the archive.
|
||||||
u8 duplicate_data; ///< Whether the archive should duplicate the data.
|
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 {
|
class ArchiveBackend : NonCopyable {
|
||||||
public:
|
public:
|
||||||
|
@ -12,6 +12,15 @@
|
|||||||
|
|
||||||
namespace Frontend {
|
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;
|
struct Frame;
|
||||||
/**
|
/**
|
||||||
* For smooth Vsync rendering, we want to always present the latest frame that the core generates,
|
* 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
|
* Represents a drawing context that supports graphics operations.
|
||||||
* graphics backend doesn't require the context, then the implementation of these methods can be
|
|
||||||
* stubs
|
|
||||||
*/
|
*/
|
||||||
class GraphicsContext {
|
class GraphicsContext {
|
||||||
public:
|
public:
|
||||||
virtual ~GraphicsContext();
|
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
|
/// 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
|
/// 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;
|
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
|
/// Polls window events
|
||||||
virtual void PollEvents() = 0;
|
virtual void PollEvents() = 0;
|
||||||
|
|
||||||
@ -148,6 +203,13 @@ public:
|
|||||||
config = val;
|
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)
|
* Gets the framebuffer layout (width, height, and screen regions)
|
||||||
* @note This method is thread-safe
|
* @note This method is thread-safe
|
||||||
@ -194,6 +256,8 @@ protected:
|
|||||||
framebuffer_layout = layout;
|
framebuffer_layout = layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WindowSystemInfo window_info;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Handler called when the minimal client area was requested to be changed via SetConfig.
|
* Handler called when the minimal client area was requested to be changed via SetConfig.
|
||||||
|
@ -20,8 +20,8 @@
|
|||||||
#include "core/tracer/recorder.h"
|
#include "core/tracer/recorder.h"
|
||||||
#include "video_core/command_processor.h"
|
#include "video_core/command_processor.h"
|
||||||
#include "video_core/debug_utils/debug_utils.h"
|
#include "video_core/debug_utils/debug_utils.h"
|
||||||
#include "video_core/rasterizer_interface.h"
|
#include "video_core/common/rasterizer.h"
|
||||||
#include "video_core/renderer_base.h"
|
#include "video_core/common/renderer.h"
|
||||||
#include "video_core/utils.h"
|
#include "video_core/utils.h"
|
||||||
#include "video_core/video_core.h"
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "audio_core/dsp_interface.h"
|
#include "audio_core/dsp_interface.h"
|
||||||
#include "common/archives.h"
|
#include "common/archives.h"
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/atomic_ops.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
@ -20,7 +21,9 @@
|
|||||||
#include "core/hle/lock.h"
|
#include "core/hle/lock.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "core/settings.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"
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
SERIALIZE_EXPORT_IMPL(Memory::MemorySystem::BackingMemImpl<Memory::Region::FCRAM>)
|
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) {
|
bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
|
||||||
auto& page_table = *process.vm_manager.page_table;
|
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);
|
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,
|
void MemorySystem::WriteBlock(const Kernel::Process& process, const VAddr dest_addr,
|
||||||
const void* src_buffer, const std::size_t size) {
|
const void* src_buffer, const std::size_t size) {
|
||||||
auto& page_table = *process.vm_manager.page_table;
|
auto& page_table = *process.vm_manager.page_table;
|
||||||
|
@ -327,6 +327,23 @@ public:
|
|||||||
void Write32(VAddr addr, u32 data);
|
void Write32(VAddr addr, u32 data);
|
||||||
void Write64(VAddr addr, u64 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,
|
void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer,
|
||||||
std::size_t size);
|
std::size_t size);
|
||||||
void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
|
void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
|
||||||
@ -384,6 +401,9 @@ private:
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
void Write(const VAddr vaddr, const T data);
|
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.
|
* 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.
|
* 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/ir/ir_user.h"
|
||||||
#include "core/hle/service/mic_u.h"
|
#include "core/hle/service/mic_u.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "video_core/renderer_base.h"
|
#include "video_core/common/renderer.h"
|
||||||
#include "video_core/video_core.h"
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
@ -14,6 +14,11 @@
|
|||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
||||||
|
enum class RendererBackend : u32 {
|
||||||
|
OpenGL = 0,
|
||||||
|
Vulkan = 1,
|
||||||
|
};
|
||||||
|
|
||||||
enum class InitClock {
|
enum class InitClock {
|
||||||
SystemTime = 0,
|
SystemTime = 0,
|
||||||
FixedTime = 1,
|
FixedTime = 1,
|
||||||
@ -24,11 +29,9 @@ enum class LayoutOption {
|
|||||||
SingleScreen,
|
SingleScreen,
|
||||||
LargeScreen,
|
LargeScreen,
|
||||||
SideScreen,
|
SideScreen,
|
||||||
|
|
||||||
// Similiar to default, but better for mobile devices in portrait mode. Top screen in clamped to
|
// 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.
|
// the top of the frame, and the bottom screen is enlarged to match the top screen.
|
||||||
MobilePortrait,
|
MobilePortrait,
|
||||||
|
|
||||||
// Similiar to LargeScreen, but better for mobile devices in landscape mode. The screens are
|
// 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.
|
// clamped to the top of the frame, and the bottom screen is a bit bigger.
|
||||||
MobileLandscape,
|
MobileLandscape,
|
||||||
@ -111,7 +114,6 @@ namespace NativeAnalog {
|
|||||||
enum Values {
|
enum Values {
|
||||||
CirclePad,
|
CirclePad,
|
||||||
CStick,
|
CStick,
|
||||||
|
|
||||||
NumAnalogs,
|
NumAnalogs,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -164,6 +166,8 @@ struct Values {
|
|||||||
u64 init_time;
|
u64 init_time;
|
||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
|
RendererBackend renderer_backend = RendererBackend::Vulkan;
|
||||||
|
bool renderer_debug = true;
|
||||||
bool use_gles;
|
bool use_gles;
|
||||||
bool use_hw_renderer;
|
bool use_hw_renderer;
|
||||||
bool use_hw_shader;
|
bool use_hw_shader;
|
||||||
|
@ -13,7 +13,7 @@ if (ENABLE_WEB_SERVICE)
|
|||||||
target_link_libraries(citra-room PRIVATE web_service)
|
target_link_libraries(citra-room PRIVATE web_service)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(citra-room PRIVATE cryptopp glad)
|
target_link_libraries(citra-room PRIVATE cryptopp-static glad::glad)
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
target_link_libraries(citra-room PRIVATE getopt)
|
target_link_libraries(citra-room PRIVATE getopt)
|
||||||
endif()
|
endif()
|
||||||
|
@ -28,7 +28,7 @@ if(SDL2_FOUND)
|
|||||||
sdl/sdl_impl.cpp
|
sdl/sdl_impl.cpp
|
||||||
sdl/sdl_impl.h
|
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)
|
target_compile_definitions(input_common PRIVATE HAVE_SDL2)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include "core/3ds.h"
|
#include "core/3ds.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "input_common/touch_from_button.h"
|
#include "input_common/touch_from_button.h"
|
||||||
|
@ -13,4 +13,4 @@ add_library(network STATIC
|
|||||||
|
|
||||||
create_target_directory_groups(network)
|
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