Compare commits

...

80 Commits

Author SHA1 Message Date
c66df41896 Revert "core: Replace boost::optional with std::optional"
This reverts commit 60f0269569.
2022-08-15 12:52:50 +03:00
2d27a19a45 renderer_vulkan: Apply dynamic state 2022-08-14 09:37:09 +03:00
be90677180 renderer_vulkan: Fix culling related issues
Seems the Vulkan winding order is opposite to that of OpenGL
2022-08-14 01:55:54 +03:00
6089988914 renderer_vulkan: Improve synchronization 2022-08-14 01:31:44 +03:00
91ea6931dd rasterizer: Use separate buffers for vs/fs uniforms
Vulkan validation layers complain about WaR hazards since the VS range overlaps with the FS range when the buffer is invalidated. To solve this, split them into separate buffers
2022-08-14 00:26:28 +03:00
74de70bf21 cmake: Use vcpkg configuration from master
Much better than the current setup
2022-08-13 13:17:41 +03:00
1880a4bdf4 video_core: Minor fixes 2022-08-13 08:51:53 +03:00
371beafc10 renderer_vulkan: Transition swapchain manually 2022-08-12 17:53:50 +03:00
734077642e video_core: Fix destruction sequence
Rejoice! Vulkan no longer leaks memory
2022-08-12 15:36:09 +03:00
a2ca75bff4 video_core: Fix remaining validation errors. Introduce PoolManager 2022-08-12 13:38:36 +03:00
09997b31af video_core: It compiles and kinda works 2022-08-11 20:17:38 +03:00
9200731b56 video_core: Even more fixes, close to building now 2022-08-10 19:47:40 +03:00
dade6e6797 video_core: Cleanups and fixes 2022-08-10 17:38:56 +03:00
c5f08a1408 video_core: Make renderer common
* Also rename to DisplayRenderer
2022-08-10 15:36:21 +03:00
67c20e04b4 shader_disk_cache: Remove precompiled cache
* Serves little purpose at this point and complicates things. Maybe readd later?
2022-08-10 00:04:03 +03:00
609e32e317 rasterizer: Use std::ranges::transform everywhere 2022-08-09 20:34:47 +03:00
2397c82b85 video_core: Commonise rasterizer class
* Also added some comments providing some details about attribute loaders
2022-08-09 18:56:14 +03:00
1ded25f68b video_core: Initial port of shader cache
* Need to add backend specific loading
2022-08-09 01:31:35 +03:00
39ca721cac rasterizer_cache: Return a framebuffer handle from GetFramebufferSurfaces 2022-08-08 14:48:55 +03:00
2d4f762db1 video_core: Commonise rasterizer cache 2022-08-08 14:24:47 +03:00
810df95b81 video_core: Rewrite to backend system
* Still doesn't build this is just a massive code dump from all the recent progress
2022-08-08 00:00:52 +03:00
ff9b0dfe2f global: Fix some warnings 2022-07-21 10:17:34 +03:00
d51c720392 arm_exclusive_monitor: Properly qualify friend class
* Otherwise we get compile errors on compilers that are not MSVC
2022-07-21 00:20:36 +03:00
2d8aded953 CMakeLists: Make SDL2 compilation conditional
* vcpkg fails to compile SDL2 on MinGW, so better fetch the package from the environment first
2022-07-20 23:58:45 +03:00
8feafd2ac5 common: Include algorithm in log.h
* Good job MSVC for giving the worst and most cryptic error message
2022-07-20 21:22:57 +03:00
94696de2b2 vcpkg: Bootstrap before installing packages 2022-07-19 16:23:18 +03:00
371387b44f externals: Remove unused submodules 2022-07-17 11:59:00 +03:00
d8d14491dd cmake: Bump minimum required CMake version 2022-07-17 10:03:42 +03:00
6b890987c4 vcpkg: Rework dependency installation
* Manifest mode is very convient but doesn't provide the flexibility we
  need. The main issue is that there is no way to conditionally install
  libraries. To bypass this we can invoke vcpkg directly using a helper
  function vcpkg_add_package that installs the library when invoked.
2022-07-17 09:41:41 +03:00
5338e2e3a3 vcpkg: Force static linkage on windows 2022-07-16 19:52:40 +03:00
6b8931c899 cmake: Bump Qt to 5.12.12 LTS 2022-07-16 18:59:46 +03:00
5cad914b73 vcpkg: Fine tune required ffmpeg dependecies 2022-07-16 16:35:46 +03:00
d865780291 vcpkg: Dont't build Qt from source
* Currently vcpkg has no mechanism of consistently handling prebuilt
  libraries. This means that large libraries like Qt need special
  treatment
2022-07-16 16:32:51 +03:00
60f0269569 core: Replace boost::optional with std::optional 2022-07-16 15:10:22 +03:00
ceadee0358 renderer_vulkan: Fix swapchain creation on Win32 2022-07-15 21:34:36 +03:00
a9b96789d7 Core: Port Exclusive memory impl from yuzu 2022-07-15 20:14:15 +03:00
79379f21a4 Common: Add CPU feature detection for ARM64 2022-07-15 20:13:27 +03:00
0e98fb3780 dynarmic: Update dynarmic to upstream
* Citra's fork of dynarmic is getting old quite fast and accumulating
  technical debt which gets harder and harder to account for as time
  goes on. So to have the access to the latest and greatest features we
  need to use the upstream version which yuzu also uses. This requires
  some extra patches which are contained in the following commits.
2022-07-15 20:06:51 +03:00
d373d74804 vk_shader_gen: Switch shader compiler to glslang
* shaderc is notoriously hard to link to and often causes link errors.
  glslang seems to work better and is a smaller library overall so
  that's a win for the backend.
2022-07-15 19:02:41 +03:00
a9436e01ca tests: Update test suite for Catch2 3.0.1 2022-07-15 17:17:18 +03:00
e7a6af73c1 renderer_vulkan: Fix type in Win32 surface creation 2022-07-15 16:43:54 +03:00
9850c23a03 cmake: Adjust link libraries to vcpkg produced targets 2022-07-15 16:43:51 +03:00
55e5c4edc9 logging: adapt to changes in fmt 8.1 2022-07-15 16:10:12 +03:00
f990a842da vcpkg: Enable all glad extensions 2022-07-15 08:48:30 +03:00
b5e4ec35e3 Introduce vcpkg for dependency management
* Manually including libraries into the project while a perfectly acceptable solution
  leads to slow updates and large maintainance costs. To address this
  shortcoming we are introducing a package manager namely vcpkg into the
  codebase to handle the download and build of most external dependencies. Conan
  was also considered but vcpkg was chosen due to the centralized nature
  of the project. To achieve the integration the CMake configuration has
  been altered but not by much:

  1. Packages handled by vcpkg have been moved from
     externals/CMakeLists.txt to the root one to make them available to
     all subdirectories.

  2. In addition now find_package is used in accordance to the vcpkg
     recommendations.

  3. All libraries built by vcpkg have been updated to their latest
     available version, except for Qt because our codebase isn't
     compatible with Qt 6.0 yet.

  Currently there are build issues caused by the fmtlib upgrade.
  Another question is how to handle large libraries like Qt, Boost and
  SDL2 which will be addressed in a later commit.
2022-07-14 18:42:33 +03:00
b1b61683f2 renderer_vulkan: Fix surface creation 2022-07-04 11:54:01 +03:00
bbb4f1b040 renderer_vulkan: Fix broken synchronization
* The GPU was always 1 tick ahead, making all wait operations nops.
2022-07-03 23:51:19 +03:00
5f942fb4c9 renderer_vulkan: Drop dependency on Vulkan-SDK
* Dynamically fetch vulkan function pointers and checkout Vulkan-Headers.
This way we are not tied by the installed SDK version
2022-07-03 20:38:46 +03:00
7c72060662 renderer_vulkan: Drop VK prefix
* All the classes are in the Vulkan namespace, thus making it superfluous
2022-07-03 16:47:59 +03:00
5b918cb535 renderer_vulkan: Cleanup unused functions in renderer 2022-07-03 16:44:23 +03:00
61932f9a6c renderer_vulkan: Include Vulkan memory allocator 2022-07-03 16:39:23 +03:00
8a2cc15cd1 Fix some C++ 20 warnings 2022-06-24 10:37:22 +03:00
18cc68c687 renderer_vulkan: Fix mipmap generation 2022-06-19 12:44:44 +03:00
69bde2b13b renderer_vulkan: Fix culling related issues 2022-06-19 00:09:02 +03:00
816a846cfb renderer_vulkan: Fix texture allocation and destruction logic 2022-06-18 15:04:15 +03:00
4dd4f2170d renderer_vulkan: 2D shapes demo fully functional now 2022-06-16 17:48:03 +03:00
0eff9ad215 renderer_vulkan: Surface fills and dual screen rendering working 2022-06-16 11:51:23 +03:00
d4b88ac158 renderer_vulkan: Texture management fixes 2022-06-15 22:34:02 +03:00
ed9000d0ec renderer_vulkan: Fix many validation errors 2022-06-14 14:29:52 +03:00
a657ef33e6 More fixes 2022-06-13 16:34:19 +03:00
87db7a6888 Successful build 2022-06-12 18:06:00 +03:00
ba6795b6cc Refactor Vulkan state and pipeline builders 2022-06-08 00:41:19 +03:00
a6fc19d7d9 renderer_vulkan: Initial rasterizer cache vulkan port 2022-05-30 08:03:49 +03:00
06cecba63f renderer_vulkan: Include pipeline builder class and finish VulanState 2022-05-20 11:02:25 +03:00
0d0712f7d7 renderer_vulkan: Add very basic pipeline and shader cache 2022-05-14 18:31:03 +03:00
72340c5685 renderer_vulkan: Port rasterizer to Vulkan
* This is a massive code dump so I'm not going to even attempt to explain what changed
2022-05-13 19:16:53 +03:00
1f967b4770 renderer_vulkan: Refactor VulkanState class and switch to dynamic rendering
* Dynamic rendering gives us no performance loss on desktop while removing the need
to cache and manager many renderpass and framebuffer objects
2022-05-06 22:26:57 +03:00
5858bd3116 renderer_vulkan: Drop vk_pipeline.h/cpp 2022-05-05 17:00:50 +03:00
ab9b84f721 renderer_vulkan: General cleanups
* Add a staging buffer to each texture. This is suboptimal since it
causes many small allocations, will only be here until I implement
a global staging buffer with memory tracking

* Make the task scheduler accept generic functions which allows for more
powerful resource control
2022-05-05 16:55:33 +03:00
f6988d4a8e vulkan: Add Vulkan memory allocator 2022-05-05 14:56:34 +03:00
bc440ce6a3 renderer_vulkan: Rewrite and rename command buffer manager class
* The old manager class had unnecessary complexity and Dolphin specific stuff
that we didn't need. So this commit completely rewrites the class to make the
implementation simpler and more robust. It does three things:

1. Make use of Vulkan timeline semaphores
2. Remove submission thread
3. Rename VKCommandManager to VKTaskScheduler

* In addition remove Unique handles from textures and buffers and give the
responsibility of their deletion to the scheduler.
2022-05-02 20:27:22 +03:00
b6099d5504 common: Implement Common::Event with Common::Flag
* Ports the following commit from dolphin: dolphin-emu/dolphin@48bd9040
2022-04-30 22:32:47 +03:00
6b3767f1b7 renderer_vulkan: Port Vulkan command buffer manager from Dolphin
* In addition to the new command buffer manager this commit
also ports changes to the synchronization objects.
2022-04-30 22:28:37 +03:00
4151fad10b vk_texture: Implement non-owning texture
* Swapchain images must not be destroyed since their cleanup is handled automatically.
2022-04-30 18:58:16 +03:00
2ec7f37d69 renderer_vulkan: Add vulkan swapchain class
* This commit implements the Vulkan swapchain required for presenting
images to the screen. Currently it's not complete as the API will
be finalized in the next subsequent commits.
2022-04-30 15:50:38 +03:00
47e48617d5 renderer_vulkan: Implement vulkan instance creation and state manager
* This commits continues to improve the backend code and starts work
on replacing the old OpenGLState class with a better one suited for
Vulkan. Instance creation is also finally done. The only thing left
before working with the rasterizer is the command buffer manager.
2022-04-30 13:36:30 +03:00
98332af610 renderer_vulkan: Improve texture interface and add framebuffer support 2022-04-28 19:37:55 +03:00
84f97fc77e renderer_vulkan: Implement basic utility classes
*  These first few commits are mostly code dumps until the renderer interface
is finalized. This commits adds some basic Vulkan objects like textures, buffers,
sampler and translates some simpler OpenGL stuff to Vulkan.

* In addition a simple resource cache is implemented that handles recycling
of samplers, renderpasses and also stores the constant descriptor layout infos.
I've added all the resources I could deduce being used in shaders though
I might be missing something. I'm still divided though on whether the resource
cache should also handle pipelines.
2022-04-28 18:14:13 +03:00
c89434627a CMake: Bump source to C++ 20
* We can use shiny new std::span, wow
2022-04-26 21:25:39 +03:00
32bab7d1ba video_core: Initial Vulkan renderer dump
* This is the basic skeleton of the new Citra Vulkan renderer. It's based on
vulkan-hpp and my own wrapper library which I wrote for my some of my projects.
Currently it doesn't even compile and the code is less than adequate.
2022-04-26 21:20:31 +03:00
206 changed files with 18071 additions and 65882 deletions

56
.gitmodules vendored
View File

@ -1,57 +1,27 @@
[submodule "boost"]
path = externals/boost
url = https://github.com/citra-emu/ext-boost.git
[submodule "nihstro"]
path = externals/nihstro
url = https://github.com/neobrain/nihstro.git
[submodule "soundtouch"]
path = externals/soundtouch
url = https://github.com/citra-emu/ext-soundtouch.git
[submodule "catch"]
path = externals/catch
url = https://github.com/philsquared/Catch.git
[submodule "dynarmic"]
path = externals/dynarmic
url = https://github.com/citra-emu/dynarmic.git
[submodule "xbyak"]
path = externals/xbyak
url = https://github.com/herumi/xbyak.git
[submodule "cryptopp"]
path = externals/cryptopp/cryptopp
url = https://github.com/weidai11/cryptopp.git
[submodule "fmt"]
path = externals/fmt
url = https://github.com/fmtlib/fmt.git
[submodule "enet"]
path = externals/enet
url = https://github.com/lsalzman/enet.git
[submodule "inih"]
path = externals/inih/inih
url = https://github.com/benhoyt/inih.git
[submodule "libressl"]
path = externals/libressl
url = https://github.com/citra-emu/ext-libressl-portable.git
[submodule "libusb"]
path = externals/libusb/libusb
url = https://github.com/libusb/libusb.git
url = https://github.com/merryhime/dynarmic.git
[submodule "cubeb"]
path = externals/cubeb
url = https://github.com/kinetiknz/cubeb.git
[submodule "discord-rpc"]
path = externals/discord-rpc
url = https://github.com/discord/discord-rpc.git
[submodule "cpp-jwt"]
path = externals/cpp-jwt
url = https://github.com/arun11299/cpp-jwt.git
[submodule "teakra"]
path = externals/teakra
url = https://github.com/wwylele/teakra.git
[submodule "lodepng"]
path = externals/lodepng/lodepng
url = https://github.com/lvandeve/lodepng.git
[submodule "zstd"]
path = externals/zstd
url = https://github.com/facebook/zstd.git
[submodule "libyuv"]
path = externals/libyuv
url = https://github.com/lemenkov/libyuv.git
[submodule "externals/vma"]
path = externals/vma
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
[submodule "externals/Vulkan-Headers"]
path = externals/Vulkan-Headers
url = https://github.com/KhronosGroup/Vulkan-Headers
[submodule "externals/vcpkg"]
path = externals/vcpkg
url = https://github.com/microsoft/vcpkg
[submodule "externals/inih/inih"]
path = externals/inih/inih
url = https://github.com/benhoyt/inih

View File

@ -1,9 +1,12 @@
# CMake 3.8 required for 17 to be a valid value for CXX_STANDARD
cmake_minimum_required(VERSION 3.8)
# CMake 3.12 required for 20 to be a valid value for CXX_STANDARD
cmake_minimum_required(VERSION 3.12)
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.15)
# Don't override the warning flags in MSVC:
cmake_policy(SET CMP0092 NEW)
endif ()
# Allow selecting MSVC runtime library using CMAKE_MSVC_RUNTIME_LIBRARY.
cmake_policy(SET CMP0091 NEW)
endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
include(DownloadExternals)
@ -14,7 +17,6 @@ project(citra LANGUAGES C CXX ASM)
# Set bundled sdl2/qt as dependent options.
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
CMAKE_DEPENDENT_OPTION(CITRA_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF)
option(ENABLE_QT "Enable the Qt frontend" ON)
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
@ -31,16 +33,12 @@ if (ENABLE_FFMPEG_AUDIO_DECODER OR ENABLE_FFMPEG_VIDEO_DUMPER)
set(ENABLE_FFMPEG ON)
endif()
CMAKE_DEPENDENT_OPTION(CITRA_USE_BUNDLED_FFMPEG "Download bundled FFmpeg binaries" ON "ENABLE_FFMPEG;MSVC" OFF)
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
CMAKE_DEPENDENT_OPTION(ENABLE_MF "Use Media Foundation decoder (preferred over FFmpeg)" ON "WIN32" OFF)
CMAKE_DEPENDENT_OPTION(COMPILE_WITH_DWARF "Add DWARF debugging information" ON "MINGW" OFF)
option(USE_SYSTEM_BOOST "Use the system Boost libs (instead of the bundled ones)" OFF)
CMAKE_DEPENDENT_OPTION(ENABLE_FDK "Use FDK AAC decoder" OFF "NOT ENABLE_FFMPEG_AUDIO_DECODER;NOT ENABLE_MF" OFF)
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit)
@ -49,6 +47,14 @@ if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit)
DESTINATION ${PROJECT_SOURCE_DIR}/.git/hooks)
endif()
# Use ccache for android if available
# =======================================================================
if (NOT $ENV{NDK_CCACHE} EQUAL "")
set(CCACHE_EXE $ENV{NDK_CCACHE})
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_EXE})
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_EXE})
endif()
# Sanity check : Check that all submodules are present
# =======================================================================
@ -126,47 +132,123 @@ message(STATUS "Target architecture: ${ARCHITECTURE}")
# Configure C++ standard
# ===========================
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# set up output paths for executable binaries
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin/$<CONFIG>)
# System imported libraries
# ======================
# Enable vcpkg features
if (NOT DEFINED VCPKG_MANIFEST_FEATURES)
if (ENABLE_SDL2)
find_package(SDL2 CONFIG)
if (NOT SDL2_FOUND)
message(STATUS "SDL2 not found. Using vcpkg")
list(APPEND VCPKG_MANIFEST_FEATURES "citra-sdl2")
endif()
endif()
if (ENABLE_WEB_SERVICE)
list(APPEND VCPKG_MANIFEST_FEATURES "citra-web-service")
endif()
if (USE_DISCORD_PRESENCE)
list(APPEND VCPKG_MANIFEST_FEATURES "citra-discord")
endif()
if (ENABLE_FFMPEG)
find_package(FFmpeg COMPONENTS avcodec avformat avutil swscale swresample)
if (NOT FFMPEG_FOUND OR "${FFmpeg_avcodec_VERSION}" VERSION_LESS "57.48.101")
message(STATUS "FFmpeg not found. Using vcpkg")
list(APPEND VCPKG_MANIFEST_FEATURES "citra-ffmpeg")
endif()
endif()
if (ENABLE_FDK)
find_library(FDK_AAC fdk-aac DOC "The path to fdk_aac library")
if(FDK_AAC STREQUAL "FDK_AAC-NOTFOUND")
message(STATUS "FDK AAC not found. Using vcpkg")
list(APPEND VCPKG_MANIFEST_FEATURES "citra-fdk-aac")
endif()
endif()
# Cache the selected manifest features.
set(VCPKG_MANIFEST_FEATURES ${VCPKG_MANIFEST_FEATURES} CACHE STRING "")
endif()
# Prefer static linkage on windows and MinGW
if (MINGW)
set(VCPKG_TARGET_TRIPLET "x64-mingw-static")
elseif (WIN32)
# We could also build a dynamic CRT and not require this flag but vcpkg
# developers actively discourage this. See:
# https://github.com/microsoft/vcpkg/issues/15122#issuecomment-745497720
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set(VCPKG_TARGET_TRIPLET "x64-windows-static")
endif()
# Include vcpkg toolchain file
include(${CMAKE_SOURCE_DIR}/externals/vcpkg/scripts/buildsystems/vcpkg.cmake)
# Prefer the -pthread flag on Linux.
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
# Boost
find_package(Boost REQUIRED COMPONENTS serialization)
# DiscordRPC
if (USE_DISCORD_PRESENCE)
find_package(discord-rpc CONFIG REQUIRED)
endif()
if (ENABLE_WEB_SERVICE)
# OpenSSL
find_package(OpenSSL REQUIRED)
# JSON
find_package(nlohmann_json CONFIG REQUIRED)
# httplib
find_path(CPP_HTTPLIB_INCLUDE_DIRS "httplib.h")
add_library(httplib INTERFACE)
target_include_directories(httplib INTERFACE ${CPP_HTTPLIB_INCLUDE_DIRS})
# cpp-jwt
find_package(cpp-jwt CONFIG REQUIRED)
endif()
# (xperia64): Only use libyuv on Android b/c of build issues on Windows and mandatory JPEG
if(ANDROID)
# libyuv
find_package(libyuv CONFIG REQUIRED)
endif()
# Find the rest of our dependecies
set(REQUIRED_PACKAGES
Catch2
cryptopp
fmt
glad
glm
zstd
unofficial-enet
lodepng
glslang
xbyak
)
foreach(PACKAGE ${REQUIRED_PACKAGES})
find_package(${PACKAGE} CONFIG REQUIRED)
endforeach()
if (ENABLE_SDL2)
if (CITRA_USE_BUNDLED_SDL2)
# Detect toolchain and platform
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
set(SDL2_VER "SDL2-2.0.16")
else()
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable CITRA_USE_BUNDLED_SDL2 and provide your own.")
endif()
if (DEFINED SDL2_VER)
download_bundled_external("sdl2/" ${SDL2_VER} SDL2_PREFIX)
endif()
set(SDL2_FOUND YES)
set(SDL2_INCLUDE_DIR "${SDL2_PREFIX}/include" CACHE PATH "Path to SDL2 headers")
set(SDL2_LIBRARY "${SDL2_PREFIX}/lib/x64/SDL2.lib" CACHE PATH "Path to SDL2 library")
set(SDL2_DLL_DIR "${SDL2_PREFIX}/lib/x64/" CACHE PATH "Path to SDL2.dll")
else()
find_package(SDL2 REQUIRED)
endif()
if (SDL2_FOUND)
# TODO(yuriks): Make FindSDL2.cmake export an IMPORTED library instead
add_library(SDL2 INTERFACE)
target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}")
target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")
endif()
find_package(SDL2 CONFIG REQUIRED)
else()
set(SDL2_FOUND NO)
endif()
@ -174,7 +256,7 @@ endif()
if (ENABLE_QT)
if (CITRA_USE_BUNDLED_QT)
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
set(QT_VER qt-5.10.0-msvc2017_64)
set(QT_VER qt-5.12.12-msvc2017_64)
else()
message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable CITRA_USE_BUNDLED_QT and provide your own.")
endif()
@ -203,45 +285,24 @@ if(NOT APPLE)
find_package(LibUSB)
endif()
if (NOT LIBUSB_FOUND)
add_subdirectory(externals/libusb)
set(LIBUSB_INCLUDE_DIR "")
set(LIBUSB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/externals/libusb/libusb/libusb")
set(LIBUSB_LIBRARIES usb)
endif()
if (ENABLE_FFMPEG)
if (CITRA_USE_BUNDLED_FFMPEG)
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
set(FFmpeg_VER "ffmpeg-4.1-win64")
else()
message(FATAL_ERROR "No bundled FFmpeg binaries for your toolchain. Disable CITRA_USE_BUNDLED_FFMPEG and provide your own.")
endif()
if (DEFINED FFmpeg_VER)
download_bundled_external("ffmpeg/" ${FFmpeg_VER} FFmpeg_PREFIX)
set(FFMPEG_DIR "${FFmpeg_PREFIX}")
endif()
endif()
if (ENABLE_FFMPEG_VIDEO_DUMPER)
find_package(FFmpeg REQUIRED COMPONENTS avcodec avformat avutil swscale swresample)
if(ENABLE_FFMPEG_VIDEO_DUMPER)
set(FFmpeg_COMPONENTS "avcodec avformat avutil swscale swresample")
else()
find_package(FFmpeg REQUIRED COMPONENTS avcodec)
set(FFmpeg_COMPONENTS "avcodec")
endif()
if ("${FFmpeg_avcodec_VERSION}" VERSION_LESS "57.48.101")
message(FATAL_ERROR "Found version for libavcodec is too low. The required version is at least 57.48.101 (included in FFmpeg 3.1 and later).")
endif()
endif()
if (ENABLE_FFMPEG_VIDEO_DUMPER)
add_definitions(-DENABLE_FFMPEG_VIDEO_DUMPER)
find_package(FFmpeg REQUIRED COMPONENTS ${FFmpeg_COMPONENTS})
endif()
if (ENABLE_FDK)
find_library(FDK_AAC fdk-aac DOC "The path to fdk_aac library")
if(FDK_AAC STREQUAL "FDK_AAC-NOTFOUND")
message(FATAL_ERROR "fdk_aac library not found.")
endif()
find_package(fdk-aac CONFIG REQUIRED)
endif()
# Platform-specific library requirements
# ======================================
@ -351,21 +412,9 @@ git_describe(GIT_DESC --always --long --dirty)
git_branch_name(GIT_BRANCH)
get_timestamp(BUILD_DATE)
if (NOT USE_SYSTEM_BOOST)
add_definitions( -DBOOST_ALL_NO_LIB )
endif()
enable_testing()
add_subdirectory(externals)
# Boost
if (USE_SYSTEM_BOOST)
find_package(Boost 1.70.0 COMPONENTS serialization REQUIRED)
else()
add_library(Boost::boost ALIAS boost)
add_library(Boost::serialization ALIAS boost_serialization)
endif()
add_subdirectory(src)
add_subdirectory(dist/installer)

View 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()

View File

@ -9,34 +9,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules)
include(DownloadExternals)
include(ExternalProject)
# Boost
set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/boost")
set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost")
set(Boost_NO_SYSTEM_PATHS ON)
add_library(boost INTERFACE)
target_include_directories(boost SYSTEM INTERFACE ${Boost_INCLUDE_DIR})
# Boost::serialization
file(GLOB boost_serialization_SRC "${CMAKE_SOURCE_DIR}/externals/boost/libs/serialization/src/*.cpp")
add_library(boost_serialization STATIC ${boost_serialization_SRC})
target_link_libraries(boost_serialization PUBLIC boost)
# Add additional boost libs here; remember to ALIAS them in the root CMakeLists!
# Catch
add_library(catch-single-include INTERFACE)
target_include_directories(catch-single-include INTERFACE catch/single_include)
# Crypto++
add_subdirectory(cryptopp)
# Xbyak
if (ARCHITECTURE_x86_64)
add_library(xbyak INTERFACE)
target_include_directories(xbyak SYSTEM INTERFACE ./xbyak/xbyak)
target_compile_definitions(xbyak INTERFACE XBYAK_NO_OP_NAMES)
endif()
# Dynarmic
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_ARM64)
set(DYNARMIC_TESTS OFF)
@ -45,18 +17,11 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_ARM64)
add_subdirectory(dynarmic)
endif()
# libfmt
add_subdirectory(fmt)
add_library(fmt::fmt ALIAS fmt)
# getopt
if (MSVC)
add_subdirectory(getopt)
endif()
# Glad
add_subdirectory(glad)
# inih
add_subdirectory(inih)
@ -79,66 +44,13 @@ target_include_directories(SoundTouch INTERFACE ./soundtouch/include)
# Teakra
add_subdirectory(teakra EXCLUDE_FROM_ALL)
# Zstandard
add_subdirectory(zstd/build/cmake EXCLUDE_FROM_ALL)
target_include_directories(libzstd_static INTERFACE $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/externals/zstd/lib>)
# ENet
add_subdirectory(enet)
target_include_directories(enet INTERFACE ./enet/include)
# Cubeb
if (ENABLE_CUBEB)
set(BUILD_TESTS OFF CACHE BOOL "")
add_subdirectory(cubeb EXCLUDE_FROM_ALL)
endif()
# DiscordRPC
if (USE_DISCORD_PRESENCE)
add_subdirectory(discord-rpc EXCLUDE_FROM_ALL)
target_include_directories(discord-rpc INTERFACE ./discord-rpc/include)
if (ENABLE_WEB_SERVICE AND ANDROID)
add_subdirectory(android-ifaddrs)
endif()
if (ENABLE_WEB_SERVICE)
find_package(OpenSSL 1.1)
if (OPENSSL_FOUND)
set(OPENSSL_LIBRARIES OpenSSL::SSL OpenSSL::Crypto)
else()
# LibreSSL
set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
set(OPENSSLDIR "/etc/ssl/")
add_subdirectory(libressl EXCLUDE_FROM_ALL)
target_include_directories(ssl INTERFACE ./libressl/include)
target_compile_definitions(ssl PRIVATE -DHAVE_INET_NTOP)
get_directory_property(OPENSSL_LIBRARIES
DIRECTORY libressl
DEFINITION OPENSSL_LIBS)
endif()
# JSON
add_library(json-headers INTERFACE)
target_include_directories(json-headers INTERFACE ./json)
if(ANDROID)
add_subdirectory(android-ifaddrs)
endif()
# httplib
add_library(httplib INTERFACE)
target_include_directories(httplib INTERFACE ./httplib)
target_compile_options(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT)
target_link_libraries(httplib INTERFACE ${OPENSSL_LIBRARIES})
# cpp-jwt
add_library(cpp-jwt INTERFACE)
target_include_directories(cpp-jwt INTERFACE ./cpp-jwt/include)
endif()
# lodepng
add_subdirectory(lodepng)
# (xperia64): Only use libyuv on Android b/c of build issues on Windows and mandatory JPEG
if(ANDROID)
# libyuv
add_subdirectory(libyuv)
target_include_directories(yuv INTERFACE ./libyuv/include)
endif()

1
externals/Vulkan-Headers vendored Submodule

1
externals/boost vendored

Submodule externals/boost deleted from 36603a1e66

1
externals/catch vendored

Submodule externals/catch deleted from c4e3767e26

1
externals/cpp-jwt vendored

Submodule externals/cpp-jwt deleted from 6e27aa4c86

View File

@ -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()

Submodule externals/discord-rpc deleted from 963aa9f3e5

1
externals/enet vendored

Submodule externals/enet deleted from 498b9e3571

1
externals/fmt vendored

Submodule externals/fmt deleted from cc09f1a679

View File

@ -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()

View File

@ -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
```

View File

@ -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_ */

File diff suppressed because one or more lines are too long

11469
externals/glad/src/glad.c vendored

File diff suppressed because one or more lines are too long

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -6,4 +6,4 @@ add_library(inih
)
create_target_directory_groups(inih)
target_include_directories(inih INTERFACE .)
target_include_directories(inih INTERFACE .)

View File

@ -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

File diff suppressed because it is too large Load Diff

1
externals/libressl vendored

Submodule externals/libressl deleted from 039d945419

View File

@ -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)

View File

@ -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

Submodule externals/libusb/libusb deleted from e782eeb251

1
externals/libyuv vendored

Submodule externals/libyuv deleted from 19d71f6b35

View File

@ -1,7 +0,0 @@
add_library(lodepng
lodepng/lodepng.cpp
lodepng/lodepng.h
)
create_target_directory_groups(lodepng)
target_include_directories(lodepng INTERFACE lodepng)

View File

@ -832,7 +832,7 @@ struct MicroProfile
#define MP_LOG_LEAVE 0x0
inline int MicroProfileLogType(MicroProfileLogEntry Index)
inline uint64_t MicroProfileLogType(MicroProfileLogEntry Index)
{
return ((MP_LOG_BEGIN_MASK & Index)>>62) & 0x3;
}
@ -845,7 +845,7 @@ inline uint64_t MicroProfileLogTimerIndex(MicroProfileLogEntry Index)
inline MicroProfileLogEntry MicroProfileMakeLogIndex(uint64_t nBegin, MicroProfileToken nToken, int64_t nTick)
{
MicroProfileLogEntry Entry = (nBegin<<62) | ((0x3fff&nToken)<<48) | (MP_LOG_TICK_MASK&nTick);
int t = MicroProfileLogType(Entry);
uint64_t t = MicroProfileLogType(Entry);
uint64_t nTimerIndex = MicroProfileLogTimerIndex(Entry);
MP_ASSERT(t == nBegin);
MP_ASSERT(nTimerIndex == (nToken&0x3fff));

1
externals/vcpkg vendored Submodule

Submodule externals/vcpkg added at d293ac220d

1
externals/vma vendored Submodule

Submodule externals/vma added at 5ab8c1752a

1
externals/xbyak vendored

Submodule externals/xbyak deleted from c306b8e578

1
externals/zstd vendored

Submodule externals/zstd deleted from 97a3da1df0

View File

@ -67,7 +67,7 @@ elseif(ENABLE_FDK)
hle/fdk_decoder.cpp
hle/fdk_decoder.h
)
target_link_libraries(audio_core PRIVATE ${FDK_AAC})
target_link_libraries(audio_core PRIVATE FDK-AAC::fdk-aac)
target_compile_definitions(audio_core PUBLIC HAVE_FDK)
endif()
@ -80,7 +80,7 @@ if(ANDROID)
endif()
if(SDL2_FOUND)
target_link_libraries(audio_core PRIVATE SDL2)
target_link_libraries(audio_core PRIVATE SDL2::SDL2)
target_compile_definitions(audio_core PRIVATE HAVE_SDL2)
endif()

View File

@ -450,7 +450,7 @@ void DspLle::SetServiceToInterrupt(std::weak_ptr<Service::DSP::DSP_DSP> dsp) {
return;
if (pipe == 0) {
// pipe 0 is for debug. 3DS automatically drains this pipe and discards the data
impl->ReadPipe(pipe, impl->GetPipeReadableSize(pipe));
impl->ReadPipe(static_cast<u8>(pipe), impl->GetPipeReadableSize(pipe));
} else {
std::lock_guard lock(HLE::g_hle_lock);
if (auto locked = dsp.lock()) {

View File

@ -16,11 +16,11 @@ add_executable(citra
create_target_directory_groups(citra)
target_link_libraries(citra PRIVATE common core input_common network)
target_link_libraries(citra PRIVATE inih glad lodepng)
target_link_libraries(citra PRIVATE inih nihstro-headers glad::glad lodepng)
if (MSVC)
target_link_libraries(citra PRIVATE getopt)
endif()
target_link_libraries(citra PRIVATE ${PLATFORM_LIBRARIES} SDL2 Threads::Threads)
target_link_libraries(citra PRIVATE ${PLATFORM_LIBRARIES} SDL2::SDL2 Threads::Threads)
if(UNIX AND NOT APPLE)
install(TARGETS citra RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")

View File

@ -43,7 +43,9 @@
#include "core/movie.h"
#include "core/settings.h"
#include "network/network.h"
#include "video_core/renderer_base.h"
#include "video_core/common/renderer.h"
#include "video_core/common/rasterizer.h"
#include "video_core/video_core.h"
#undef _UNICODE
#include <getopt.h>

View File

@ -20,7 +20,7 @@
#include "input_common/motion_emu.h"
#include "input_common/sdl/sdl.h"
#include "network/network.h"
#include "video_core/renderer_base.h"
#include "video_core/common/renderer.h"
#include "video_core/video_core.h"
SharedContext_SDL2::SharedContext_SDL2() {

View File

@ -259,8 +259,11 @@ endif()
create_target_directory_groups(citra-qt)
target_link_libraries(citra-qt PRIVATE audio_core common core input_common network video_core)
target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt5::Widgets Qt5::Multimedia)
target_link_libraries(citra-qt PRIVATE Boost::boost glad::glad nihstro-headers Qt5::Widgets Qt5::Multimedia)
target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
target_include_directories(citra-qt PRIVATE ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
endif()
target_compile_definitions(citra-qt PRIVATE
# Use QStringBuilder for string concatenation to reduce

View File

@ -7,9 +7,9 @@
#include <QHBoxLayout>
#include <QKeyEvent>
#include <QOffscreenSurface>
#include <glad/glad.h>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QOpenGLFunctions_3_3_Core>
#include <QMessageBox>
#include <fmt/format.h>
#include "citra_qt/bootmanager.h"
#include "citra_qt/main.h"
@ -24,9 +24,15 @@
#include "input_common/main.h"
#include "input_common/motion_emu.h"
#include "network/network.h"
#include "video_core/renderer_base.h"
#include "video_core/common/rasterizer.h"
#include "video_core/common/pipeline_cache.h"
#include "video_core/common/renderer.h"
#include "video_core/video_core.h"
#if !defined(WIN32)
#include <qpa/qplatformnativeinterface.h>
#endif
EmuThread::EmuThread(Frontend::GraphicsContext& core_context) : core_context(core_context) {}
EmuThread::~EmuThread() = default;
@ -52,6 +58,7 @@ void EmuThread::run() {
});
emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
emit HideLoadingScreen();
if (Core::System::GetInstance().frame_limiter.IsFrameAdvancing()) {
// Usually the loading screen is hidden after the first frame is drawn. In this case
@ -89,7 +96,12 @@ void EmuThread::run() {
emit DebugModeLeft();
exec_step = false;
Core::System::GetInstance().SingleStep();
const auto result = Core::System::GetInstance().SingleStep();
if (result != Core::System::ResultStatus::Success) {
this->SetRunning(false);
emit ErrorThrown(result, Core::System::GetInstance().GetStatusDetails());
}
emit DebugModeEntered();
yieldCurrentThread();
@ -108,87 +120,163 @@ void EmuThread::run() {
#endif
}
OpenGLWindow::OpenGLWindow(QWindow* parent, QWidget* event_handler, QOpenGLContext* shared_context)
: QWindow(parent), context(std::make_unique<QOpenGLContext>(shared_context->parent())),
event_handler(event_handler) {
class DummyContext : public Frontend::GraphicsContext {};
// disable vsync for any shared contexts
auto format = shared_context->format();
format.setSwapInterval(Settings::values.use_vsync_new ? 1 : 0);
this->setFormat(format);
class OpenGLSharedContext : public Frontend::GraphicsContext {
public:
/// Create the original context that should be shared from
explicit OpenGLSharedContext(QSurface* surface) : surface(surface) {
QSurfaceFormat format;
format.setVersion(4, 6);
format.setProfile(QSurfaceFormat::CompatibilityProfile);
format.setOption(QSurfaceFormat::FormatOption::DeprecatedFunctions);
format.setOption(QSurfaceFormat::FormatOption::DebugContext);
context->setShareContext(shared_context);
context->setScreen(this->screen());
context->setFormat(format);
context->create();
// TODO: expose a setting for buffer value (ie default/single/double/triple)
format.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior);
format.setSwapInterval(0);
setSurfaceType(QWindow::OpenGLSurface);
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
// WA_DontShowOnScreen, WA_DeleteOnClose
}
OpenGLWindow::~OpenGLWindow() {
context->doneCurrent();
}
void OpenGLWindow::Present() {
if (!isExposed())
return;
context->makeCurrent(this);
if (VideoCore::g_renderer) {
VideoCore::g_renderer->TryPresent(100);
context = std::make_unique<QOpenGLContext>();
context->setFormat(format);
if (!context->create()) {
LOG_ERROR(Frontend, "Unable to create main openGL context");
}
}
context->swapBuffers(this);
auto f = context->versionFunctions<QOpenGLFunctions_3_3_Core>();
f->glFinish();
QWindow::requestUpdate();
}
bool OpenGLWindow::event(QEvent* event) {
switch (event->type()) {
case QEvent::UpdateRequest:
Present();
return true;
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::MouseMove:
case QEvent::KeyPress:
case QEvent::KeyRelease:
case QEvent::FocusIn:
case QEvent::FocusOut:
case QEvent::FocusAboutToChange:
case QEvent::Enter:
case QEvent::Leave:
case QEvent::Wheel:
case QEvent::TabletMove:
case QEvent::TabletPress:
case QEvent::TabletRelease:
case QEvent::TabletEnterProximity:
case QEvent::TabletLeaveProximity:
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
case QEvent::InputMethodQuery:
case QEvent::TouchCancel:
return QCoreApplication::sendEvent(event_handler, event);
case QEvent::Drop:
GetMainWindow()->DropAction(static_cast<QDropEvent*>(event));
return true;
case QEvent::DragEnter:
case QEvent::DragMove:
GetMainWindow()->AcceptDropEvent(static_cast<QDropEvent*>(event));
return true;
default:
return QWindow::event(event);
/// Create the shared contexts for rendering and presentation
explicit OpenGLSharedContext(QOpenGLContext* share_context, QSurface* main_surface = nullptr) {
// disable vsync for any shared contexts
auto format = share_context->format();
format.setSwapInterval(0);
context = std::make_unique<QOpenGLContext>();
context->setShareContext(share_context);
context->setFormat(format);
if (!context->create()) {
LOG_ERROR(Frontend, "Unable to create shared openGL context");
}
if (!main_surface) {
offscreen_surface = std::make_unique<QOffscreenSurface>(nullptr);
offscreen_surface->setFormat(format);
offscreen_surface->create();
surface = offscreen_surface.get();
} else {
surface = main_surface;
}
}
~OpenGLSharedContext() {
DoneCurrent();
}
void SwapBuffers() override {
context->swapBuffers(surface);
}
void MakeCurrent() override {
// We can't track the current state of the underlying context in this wrapper class because
// Qt may make the underlying context not current for one reason or another. In particular,
// the WebBrowser uses GL, so it seems to conflict if we aren't careful.
// Instead of always just making the context current (which does not have any caching to
// check if the underlying context is already current) we can check for the current context
// in the thread local data by calling `currentContext()` and checking if its ours.
if (QOpenGLContext::currentContext() != context.get()) {
context->makeCurrent(surface);
}
}
void DoneCurrent() override {
context->doneCurrent();
}
QOpenGLContext* GetShareContext() {
return context.get();
}
const QOpenGLContext* GetShareContext() const {
return context.get();
}
private:
// Avoid using Qt parent system here since we might move the QObjects to new threads
// As a note, this means we should avoid using slots/signals with the objects too
std::unique_ptr<QOpenGLContext> context;
std::unique_ptr<QOffscreenSurface> offscreen_surface{};
QSurface* surface;
};
class RenderWidget : public QWidget {
public:
explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) {
setAttribute(Qt::WA_NativeWindow);
setAttribute(Qt::WA_PaintOnScreen);
}
virtual ~RenderWidget() = default;
QPaintEngine* paintEngine() const override {
return nullptr;
}
private:
GRenderWindow* render_window;
};
class OpenGLRenderWidget : public RenderWidget {
public:
explicit OpenGLRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {
windowHandle()->setSurfaceType(QWindow::OpenGLSurface);
}
void SetContext(std::unique_ptr<Frontend::GraphicsContext>&& context_) {
context = std::move(context_);
}
private:
std::unique_ptr<Frontend::GraphicsContext> context;
};
class VulkanRenderWidget : public RenderWidget {
public:
explicit VulkanRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {
windowHandle()->setSurfaceType(QWindow::VulkanSurface);
}
};
static Frontend::WindowSystemType GetWindowSystemType() {
// Determine WSI type based on Qt platform.
QString platform_name = QGuiApplication::platformName();
if (platform_name == QStringLiteral("windows"))
return Frontend::WindowSystemType::Windows;
else if (platform_name == QStringLiteral("xcb"))
return Frontend::WindowSystemType::X11;
else if (platform_name == QStringLiteral("wayland"))
return Frontend::WindowSystemType::Wayland;
LOG_CRITICAL(Frontend, "Unknown Qt platform!");
return Frontend::WindowSystemType::Windows;
}
void OpenGLWindow::exposeEvent(QExposeEvent* event) {
QWindow::requestUpdate();
QWindow::exposeEvent(event);
static Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) {
Frontend::EmuWindow::WindowSystemInfo wsi;
wsi.type = GetWindowSystemType();
// Our Win32 Qt external doesn't have the private API.
#if defined(WIN32) || defined(__APPLE__)
wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
#else
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
wsi.display_connection = pni->nativeResourceForWindow("display", window);
if (wsi.type == Frontend::WindowSystemType::Wayland)
wsi.render_surface = window ? pni->nativeResourceForWindow("surface", window) : nullptr;
else
wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
#endif
wsi.render_surface_scale = window ? static_cast<float>(window->devicePixelRatio()) : 1.0f;
return wsi;
}
GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread)
@ -215,11 +303,11 @@ GRenderWindow::~GRenderWindow() {
}
void GRenderWindow::MakeCurrent() {
core_context->MakeCurrent();
main_context->MakeCurrent();
}
void GRenderWindow::DoneCurrent() {
core_context->DoneCurrent();
main_context->DoneCurrent();
}
void GRenderWindow::PollEvents() {
@ -384,25 +472,51 @@ void GRenderWindow::resizeEvent(QResizeEvent* event) {
OnFramebufferSizeChanged();
}
void GRenderWindow::InitRenderTarget() {
bool GRenderWindow::InitRenderTarget() {
ReleaseRenderTarget();
{
// Create a dummy render widget so that Qt
// places the render window at the correct position.
const RenderWidget dummy_widget{this};
}
first_frame = false;
GMainWindow* parent = GetMainWindow();
QWindow* parent_win_handle = parent ? parent->windowHandle() : nullptr;
child_window = new OpenGLWindow(parent_win_handle, this, QOpenGLContext::globalShareContext());
child_window->create();
child_widget = createWindowContainer(child_window, this);
switch (Settings::values.renderer_backend) {
case Settings::RendererBackend::OpenGL:
if (!InitializeOpenGL()) {
return false;
}
break;
case Settings::RendererBackend::Vulkan:
if (!InitializeVulkan()) {
return false;
}
break;
}
child_widget->resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight);
layout()->addWidget(child_widget);
// Reset minimum required size to avoid resizing issues on the main window after restarting.
setMinimumSize(1, 1);
core_context = CreateSharedContext();
resize(Core::kScreenTopWidth, Core::kScreenTopHeight + Core::kScreenBottomHeight);
// Update the Window System information with the new render target
window_info = GetWindowSystemInfo(child_widget->windowHandle());
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
OnFramebufferSizeChanged();
BackupGeometry();
if (Settings::values.renderer_backend == Settings::RendererBackend::OpenGL) {
if (!LoadOpenGL()) {
return false;
}
}
return true;
}
void GRenderWindow::ReleaseRenderTarget() {
@ -413,6 +527,54 @@ void GRenderWindow::ReleaseRenderTarget() {
}
}
bool GRenderWindow::InitializeOpenGL() {
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
// WA_DontShowOnScreen, WA_DeleteOnClose
auto child = new OpenGLRenderWidget(this);
child_widget = child;
child_widget->windowHandle()->create();
auto context = std::make_shared<OpenGLSharedContext>(child->windowHandle());
main_context = context;
child->SetContext(
std::make_unique<OpenGLSharedContext>(context->GetShareContext(), child->windowHandle()));
return true;
}
bool GRenderWindow::InitializeVulkan() {
auto child = new VulkanRenderWidget(this);
child_widget = child;
child_widget->windowHandle()->create();
main_context = std::make_unique<DummyContext>();
return true;
}
bool GRenderWindow::LoadOpenGL() {
auto context = CreateSharedContext();
auto scope = context->Acquire();
if (!gladLoadGL()) {
QMessageBox::warning(
this, tr("Error while initializing OpenGL!"),
tr("Your GPU may not support OpenGL, or you do not have the latest graphics driver."));
return false;
}
const QString renderer =
QString::fromUtf8(reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
if (!GLAD_GL_ES_VERSION_3_2) {
LOG_ERROR(Frontend, "GPU does not support OpenGL ES 3.2: {}", renderer.toStdString());
QMessageBox::warning(this, tr("Error while initializing OpenGL ES 3.2!"),
tr("Your GPU may not support OpenGL ES 3.2, or you do not have the "
"latest graphics driver.<br><br>GL Renderer:<br>%1")
.arg(renderer));
return false;
}
return true;
}
void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) {
if (res_scale == 0)
res_scale = VideoCore::GetResolutionScaleFactor();
@ -448,29 +610,13 @@ void GRenderWindow::showEvent(QShowEvent* event) {
}
std::unique_ptr<Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
return std::make_unique<GLContext>(QOpenGLContext::globalShareContext());
}
GLContext::GLContext(QOpenGLContext* shared_context)
: context(std::make_unique<QOpenGLContext>(shared_context->parent())),
surface(std::make_unique<QOffscreenSurface>(nullptr)) {
// disable vsync for any shared contexts
auto format = shared_context->format();
format.setSwapInterval(0);
context->setShareContext(shared_context);
context->setFormat(format);
context->create();
surface->setParent(shared_context->parent());
surface->setFormat(format);
surface->create();
}
void GLContext::MakeCurrent() {
context->makeCurrent(surface.get());
}
void GLContext::DoneCurrent() {
context->doneCurrent();
if (Settings::values.renderer_backend == Settings::RendererBackend::OpenGL) {
auto c = static_cast<OpenGLSharedContext*>(main_context.get());
// Bind the shared contexts to the main surface in case the backend wants to take over
// presentation
return std::make_unique<OpenGLSharedContext>(c->GetShareContext(),
child_widget->windowHandle());
}
return std::make_unique<DummyContext>();
}

View File

@ -24,22 +24,9 @@ class GMainWindow;
class GRenderWindow;
namespace VideoCore {
enum class LoadCallbackStage;
enum class LoadCallbackStage : u8;
}
class GLContext : public Frontend::GraphicsContext {
public:
explicit GLContext(QOpenGLContext* shared_context);
void MakeCurrent() override;
void DoneCurrent() override;
private:
std::unique_ptr<QOpenGLContext> context;
std::unique_ptr<QOffscreenSurface> surface;
};
class EmuThread final : public QThread {
Q_OBJECT
@ -126,24 +113,6 @@ signals:
void HideLoadingScreen();
};
class OpenGLWindow : public QWindow {
Q_OBJECT
public:
explicit OpenGLWindow(QWindow* parent, QWidget* event_handler, QOpenGLContext* shared_context);
~OpenGLWindow();
void Present();
protected:
bool event(QEvent* event) override;
void exposeEvent(QExposeEvent* event) override;
private:
std::unique_ptr<QOpenGLContext> context;
QWidget* event_handler;
};
class GRenderWindow : public QWidget, public Frontend::EmuWindow {
Q_OBJECT
@ -179,7 +148,7 @@ public:
void focusOutEvent(QFocusEvent* event) override;
void InitRenderTarget();
bool InitRenderTarget();
/// Destroy the previous run's child_widget which should also destroy the child_window
void ReleaseRenderTarget();
@ -212,13 +181,13 @@ private:
void OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal_size) override;
std::unique_ptr<GraphicsContext> core_context;
bool LoadOpenGL();
bool InitializeOpenGL();
bool InitializeVulkan();
std::shared_ptr<Frontend::GraphicsContext> main_context;
QByteArray geometry;
/// Native window handle that backs this presentation widget
QWindow* child_window = nullptr;
/// In order to embed the window into GRenderWindow, you need to use createWindowContainer to
/// put the child_window into a widget then add it to the layout. This child_widget can be
/// parented to GRenderWindow and use Qt's lifetime system

View File

@ -49,9 +49,10 @@ CheatDialog::~CheatDialog() = default;
void CheatDialog::LoadCheats() {
cheats = Core::System::GetInstance().CheatEngine().GetCheats();
ui->tableCheats->setRowCount(cheats.size());
int cheat_count = static_cast<int>(cheats.size());
ui->tableCheats->setRowCount(cheat_count);
for (size_t i = 0; i < cheats.size(); i++) {
for (int i = 0; i < cheat_count; i++) {
QCheckBox* enabled = new QCheckBox();
enabled->setChecked(cheats[i]->IsEnabled());
enabled->setStyleSheet(QStringLiteral("margin-left:7px;"));

View File

@ -944,14 +944,14 @@ void Config::SaveMultiplayerValues() {
// Write ban list
qt_config->beginWriteArray(QStringLiteral("username_ban_list"));
for (std::size_t i = 0; i < UISettings::values.ban_list.first.size(); ++i) {
qt_config->setArrayIndex(i);
qt_config->setArrayIndex(static_cast<int>(i));
WriteSetting(QStringLiteral("username"),
QString::fromStdString(UISettings::values.ban_list.first[i]));
}
qt_config->endArray();
qt_config->beginWriteArray(QStringLiteral("ip_ban_list"));
for (std::size_t i = 0; i < UISettings::values.ban_list.second.size(); ++i) {
qt_config->setArrayIndex(i);
qt_config->setArrayIndex(static_cast<int>(i));
WriteSetting(QStringLiteral("ip"),
QString::fromStdString(UISettings::values.ban_list.second[i]));
}

View File

@ -256,7 +256,7 @@ void ConfigureCamera::SetConfiguration() {
int index = GetSelectedCameraIndex();
for (std::size_t i = 0; i < Implementations.size(); i++) {
if (Implementations[i] == camera_name[index]) {
ui->image_source->setCurrentIndex(i);
ui->image_source->setCurrentIndex(static_cast<int>(i));
}
}
if (camera_name[index] == "image") {

View File

@ -14,8 +14,8 @@ ConfigureEnhancements::ConfigureEnhancements(QWidget* parent)
: QWidget(parent), ui(std::make_unique<Ui::ConfigureEnhancements>()) {
ui->setupUi(this);
for (const auto& filter : OpenGL::TextureFilterer::GetFilterNames())
ui->texture_filter_combobox->addItem(QString::fromStdString(filter.data()));
//for (const auto& filter : OpenGL::TextureFilterer::GetFilterNames())
// ui->texture_filter_combobox->addItem(QString::fromStdString(filter.data()));
SetConfiguration();
@ -89,12 +89,12 @@ void ConfigureEnhancements::updateShaders(Settings::StereoRenderOption stereo_op
ui->shader_combobox->setCurrentIndex(0);
for (const auto& shader : OpenGL::GetPostProcessingShaderList(
/*for (const auto& shader : OpenGL::GetPostProcessingShaderList(
stereo_option == Settings::StereoRenderOption::Anaglyph)) {
ui->shader_combobox->addItem(QString::fromStdString(shader));
if (Settings::values.pp_shader_name == shader)
ui->shader_combobox->setCurrentIndex(ui->shader_combobox->count() - 1);
}
}*/
}
void ConfigureEnhancements::RetranslateUI() {

View File

@ -76,7 +76,7 @@ void IPCRecorderWidget::OnEntryUpdated(IPCDebugger::RequestRecord record) {
QTreeWidgetItem entry{
{QString::number(record.id), GetStatusStr(record), service, GetFunctionName(record)}};
const int row_id = record.id - id_offset;
const std::size_t row_id = record.id - id_offset;
if (ui->main->invisibleRootItem()->childCount() > row_id) {
records[row_id] = record;
(*ui->main->invisibleRootItem()->child(row_id)) = entry;

View File

@ -45,7 +45,7 @@ private:
// The offset between record id and row id, assuming record ids are assigned
// continuously and only the 'Clear' action can be performed, this is enough.
// The initial value is 1, which means record 1 = row 0.
int id_offset = 1;
std::size_t id_offset = 1;
std::vector<IPCDebugger::RequestRecord> records;
};

View File

@ -579,8 +579,8 @@ void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) {
void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
const int game_dir_index = selected.data(GameListDir::GameDirRole).toInt();
QAction* move_up = context_menu.addAction(tr(u8"\U000025b2 Move Up"));
QAction* move_down = context_menu.addAction(tr(u8"\U000025bc Move Down "));
QAction* move_up = context_menu.addAction(tr("Move Up"));
QAction* move_down = context_menu.addAction(tr("Move Down"));
QAction* open_directory_location = context_menu.addAction(tr("Open Directory Location"));
const int row = selected.row();

View File

@ -18,7 +18,7 @@
#include "core/loader/loader.h"
#include "core/loader/smdh.h"
#include "ui_loading_screen.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/common/pipeline_cache.h"
constexpr char PROGRESSBAR_STYLE_PREPARE[] = R"(
QProgressBar {}

View File

@ -17,7 +17,7 @@ class LoadingScreen;
}
namespace VideoCore {
enum class LoadCallbackStage;
enum class LoadCallbackStage : unsigned char;
}
class QGraphicsOpacityEffect;

View File

@ -11,7 +11,6 @@
#include <QFutureWatcher>
#include <QLabel>
#include <QMessageBox>
#include <QOpenGLFunctions_3_3_Core>
#include <QSysInfo>
#include <QtConcurrent/QtConcurrentRun>
#include <QtGui>
@ -764,7 +763,7 @@ void GMainWindow::ConnectMenuEvents() {
connect(ui->action_Close_Movie, &QAction::triggered, this, &GMainWindow::OnCloseMovie);
connect(ui->action_Save_Movie, &QAction::triggered, this, &GMainWindow::OnSaveMovie);
connect(ui->action_Movie_Read_Only_Mode, &QAction::toggled, this,
[this](bool checked) { Core::Movie::GetInstance().SetReadOnly(checked); });
[](bool checked) { Core::Movie::GetInstance().SetReadOnly(checked); });
connect(ui->action_Enable_Frame_Advancing, &QAction::triggered, this, [this] {
if (emulation_running) {
Core::System::GetInstance().frame_limiter.SetFrameAdvancing(
@ -911,19 +910,12 @@ bool GMainWindow::LoadROM(const QString& filename) {
if (emu_thread != nullptr)
ShutdownGame();
render_window->InitRenderTarget();
Frontend::ScopeAcquireContext scope(*render_window);
const QString below_gl33_title = tr("OpenGL 3.3 Unsupported");
const QString below_gl33_message = tr("Your GPU may not support OpenGL 3.3, or you do not "
"have the latest graphics driver.");
if (!QOpenGLContext::globalShareContext()->versionFunctions<QOpenGLFunctions_3_3_Core>()) {
QMessageBox::critical(this, below_gl33_title, below_gl33_message);
if (!render_window->InitRenderTarget()) {
return false;
}
Frontend::ScopeAcquireContext scope(*render_window);
Core::System& system{Core::System::GetInstance()};
const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};
@ -990,10 +982,6 @@ bool GMainWindow::LoadROM(const QString& filename) {
"proper drivers for your graphics card from the manufacturer's website."));
break;
case Core::System::ResultStatus::ErrorVideoCore_ErrorBelowGL33:
QMessageBox::critical(this, below_gl33_title, below_gl33_message);
break;
default:
QMessageBox::critical(
this, tr("Error while loading ROM!"),
@ -1511,7 +1499,7 @@ void GMainWindow::InstallCIA(QStringList filepaths) {
const auto cia_progress = [&](std::size_t written, std::size_t total) {
emit UpdateProgress(written, total);
};
for (const auto current_path : filepaths) {
for (const auto& current_path : filepaths) {
status = Service::AM::InstallCIA(current_path.toStdString(), cia_progress);
emit CIAInstallReport(status, current_path);
}
@ -1963,7 +1951,8 @@ void GMainWindow::OnCaptureScreenshot() {
png_dialog.setAcceptMode(QFileDialog::AcceptSave);
png_dialog.setDefaultSuffix(QStringLiteral("png"));
if (png_dialog.exec()) {
const QString path = png_dialog.selectedFiles().first();
const QList selected = png_dialog.selectedFiles();
const QString path = selected.first();
if (!path.isEmpty()) {
UISettings::values.screenshot_path = QFileInfo(path).path();
render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, path);
@ -2446,8 +2435,6 @@ int main(int argc, char* argv[]) {
std::string bin_path = FileUtil::GetBundleDirectory() + DIR_SEP + "..";
chdir(bin_path.c_str());
#endif
QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
QApplication app(argc, argv);
// Qt changes the locale and causes issues in float conversion using std::to_string() when

View File

@ -56,9 +56,11 @@ add_library(common STATIC
announce_multiplayer_room.h
archives.h
assert.h
atomic_ops.h
detached_tasks.cpp
detached_tasks.h
bit_field.h
bit_field_array.h
bit_set.h
cityhash.cpp
cityhash.h
@ -69,7 +71,9 @@ add_library(common STATIC
construct.h
file_util.cpp
file_util.h
flag.h
hash.h
intrusive_ptr.h
linear_disk_cache.h
logging/backend.cpp
logging/backend.h
@ -85,6 +89,8 @@ add_library(common STATIC
microprofile.h
microprofileui.h
misc.cpp
object_pool.cpp
object_pool.h
param_package.cpp
param_package.h
quaternion.h
@ -92,6 +98,7 @@ add_library(common STATIC
scm_rev.cpp
scm_rev.h
scope_exit.h
semaphore.h
serialization/atomic.h
serialization/boost_discrete_interval.hpp
serialization/boost_flat_set.h
@ -125,12 +132,18 @@ if(ARCHITECTURE_x86_64)
x64/xbyak_abi.h
x64/xbyak_util.h
)
elseif(ARCHITECTURE_arm64)
target_sources(common
PRIVATE
aarch64/cpu_detect.cpp
aarch64/cpu_detect.h
)
endif()
create_target_directory_groups(common)
target_link_libraries(common PUBLIC fmt microprofile Boost::boost Boost::serialization)
target_link_libraries(common PRIVATE libzstd_static)
target_link_libraries(common PUBLIC fmt::fmt microprofile Boost::boost Boost::serialization)
target_link_libraries(common PRIVATE zstd::libzstd_shared)
if (ARCHITECTURE_x86_64)
target_link_libraries(common PRIVATE xbyak)
target_link_libraries(common PRIVATE xbyak::xbyak)
endif()

View 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

View 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

View File

@ -10,7 +10,7 @@ namespace Common {
template <typename T>
[[nodiscard]] constexpr T AlignUp(T value, std::size_t size) {
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
auto mod{value % size};
auto mod = static_cast<T>(value % size);
value -= mod;
return static_cast<T>(mod == T{0} ? value : value + size);
}

166
src/common/atomic_ops.h Normal file
View 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

View File

@ -36,6 +36,18 @@
#include "common/common_funcs.h"
#include "common/swap.h"
// User defined types to need to specialize this
template <typename T>
struct MakeUnsigned {
using type = std::make_unsigned_t<T>;
};
// Ensure that user defined types are sane
template <class T>
concept ValidType = requires(T t) {
static_cast<typename MakeUnsigned<T>::type>(t);
};
/*
* Abstract bitfield class
*
@ -110,6 +122,7 @@
*/
#pragma pack(1)
template <std::size_t Position, std::size_t Bits, typename T, typename EndianTag = LETag>
requires ValidType<T>
struct BitField {
private:
// UnderlyingType is T for non-enum types and the underlying type of T if
@ -120,7 +133,7 @@ private:
std::enable_if<true, T>>::type;
// We store the value as the unsigned type to avoid undefined behaviour on value shifting
using StorageType = std::make_unsigned_t<UnderlyingType>;
using StorageType = typename MakeUnsigned<UnderlyingType>::type;
using StorageTypeWithEndian = typename AddEndian<StorageType, EndianTag>::type;
@ -199,3 +212,38 @@ private:
template <std::size_t Position, std::size_t Bits, typename T>
using BitFieldBE = BitField<Position, Bits, T, BETag>;
/**
* Abstract bit flag class. This is basically a specialization of BitField for single-bit fields.
* Instead of being cast to the underlying type, it acts like a boolean.
*/
#pragma pack(1)
template <std::size_t Position, typename T, typename EndianTag = LETag>
struct BitFlag : protected BitField<Position, 1, T, EndianTag> {
private:
BitFlag(T val) = delete;
using ParentType = BitField<Position, 1, T>;
public:
BitFlag() = default;
BitFlag& operator=(const BitFlag&) = delete;
constexpr BitFlag& operator=(bool val) {
Assign(val);
return *this;
}
constexpr void Assign(bool value) {
ParentType::Assign(value);
}
[[nodiscard]] constexpr operator bool() const {
return Value();
}
[[nodiscard]] constexpr bool Value() const {
return ParentType::Value() != 0;
}
};
#pragma pack()

View 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;
};

View File

@ -21,6 +21,13 @@
#define INSERT_PADDING_BYTES(num_bytes) u8 CONCAT2(pad, __LINE__)[(num_bytes)]
#define INSERT_PADDING_WORDS(num_words) u32 CONCAT2(pad, __LINE__)[(num_words)]
/// These are similar to the INSERT_PADDING_* macros but do not zero-initialize the contents.
/// This keeps the structure trivial to construct.
#define INSERT_PADDING_BYTES_NOINIT(num_bytes) \
[[maybe_unused]] std::array<u8, num_bytes> CONCAT2(pad, __LINE__)
#define INSERT_PADDING_WORDS_NOINIT(num_words) \
[[maybe_unused]] std::array<u32, num_words> CONCAT2(pad, __LINE__)
// Inlining
#ifdef _WIN32
#define FORCE_INLINE __forceinline

View File

@ -24,6 +24,7 @@
#pragma once
#include <array>
#include <cstdint>
#ifdef _MSC_VER
@ -50,6 +51,9 @@ typedef double f64; ///< 64-bit floating point
typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space.
typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space.
using u128 = std::array<std::uint64_t, 2>;
static_assert(sizeof(u128) == 16, "u128 must be 128 bits wide");
// An inheritable class to disallow the copy constructor and operator= functions
class NonCopyable {
protected:

45
src/common/flag.h Normal file
View 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

View File

@ -11,6 +11,15 @@
namespace Common {
/**
* Disables rehashing for std::unordered_map
*/
struct IdentityHash {
u64 operator()(const u64 hash) const {
return hash;
}
};
/**
* Computes a 64-bit hash over the specified block of data
* @param data Block of data to compute hash over
@ -33,6 +42,14 @@ static inline u64 ComputeStructHash64(const T& data) noexcept {
return ComputeHash64(&data, sizeof(data));
}
/**
* Combines hash lhs with hash rhs providing a unique result.
*/
static inline std::size_t HashCombine(std::size_t lhs, std::size_t rhs) noexcept {
lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2);
return lhs;
}
/// A helper template that ensures the padding in a struct is initialized by memsetting to 0.
template <typename T>
struct HashableStruct {

261
src/common/intrusive_ptr.h Normal file
View 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>;

View File

@ -9,7 +9,7 @@
#include "common/common_types.h"
// defined in Version.cpp
extern const char* scm_rev_git_str;
const char* scm_rev_git_str = "DUMMY";
// On disk format:
// header{

View File

@ -235,6 +235,7 @@ void DebuggerBackend::Write(const Entry& entry) {
CLS(Render) \
SUB(Render, Software) \
SUB(Render, OpenGL) \
SUB(Render, Vulkan) \
CLS(Audio) \
SUB(Audio, DSP) \
SUB(Audio, Sink) \

View File

@ -4,10 +4,24 @@
#pragma once
#include <algorithm>
#include <array>
#include <type_traits>
#include <fmt/format.h>
#include "common/common_types.h"
// adapted from https://github.com/fmtlib/fmt/issues/2704
// a generic formatter for enum classes (<= 32 bits)
#if FMT_VERSION >= 80100
template <typename T>
struct fmt::formatter<T, std::enable_if_t<std::is_enum_v<T>, char>> : formatter<u32> {
template <typename FormatContext>
auto format(const T& value, FormatContext& ctx) -> decltype(ctx.out()) {
return fmt::formatter<u32>::format(static_cast<u32>(value), ctx);
}
};
#endif
namespace Log {
// trims up to and including the last of ../, ..\, src/, src\ in a string
@ -102,6 +116,7 @@ enum class Class : ClassType {
Render, ///< Emulator video output and hardware acceleration
Render_Software, ///< Software renderer backend
Render_OpenGL, ///< OpenGL backend
Render_Vulkan, ///< Vulkan backend
Audio, ///< Audio emulation
Audio_DSP, ///< The HLE and LLE implementations of the DSP
Audio_Sink, ///< Emulator audio output backend

View File

@ -39,6 +39,11 @@ struct Rectangle {
return Rectangle{left, top, static_cast<T>(left + GetWidth() * s),
static_cast<T>(top + GetHeight() * s)};
}
[[nodiscard]] Rectangle<T> operator *(const T num) const {
return Rectangle{left * num, top * num, right * num, bottom * num};
}
auto operator <=> (const Rectangle<T>& other) const = default;
};
template <typename T>

View 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
View 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
View 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

View File

@ -12,8 +12,8 @@ void FlipRGBA8Texture(std::vector<u8>& tex, u64 width, u64 height) {
ASSERT(tex.size() == width * height * 4);
const u64 line_size = width * 4;
for (u64 line = 0; line < height / 2; line++) {
const u32 offset_1 = line * line_size;
const u32 offset_2 = (height - line - 1) * line_size;
const u64 offset_1 = line * line_size;
const u64 offset_2 = (height - line - 1) * line_size;
// Swap lines
std::swap_ranges(tex.begin() + offset_1, tex.begin() + offset_1 + line_size,
tex.begin() + offset_2);

View File

@ -72,6 +72,9 @@ public:
return Vec2{f, f};
}
// Default comparison operators
[[nodiscard]] auto operator<=>(const Vec2& other) const = default;
[[nodiscard]] constexpr Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
return {x + other.x, y + other.y};
}
@ -184,6 +187,8 @@ template <typename T, typename V>
}
using Vec2f = Vec2<float>;
using Vec2u = Vec2<unsigned>;
using Vec2i = Vec2<int>;
template <>
inline float Vec2<float>::Length() const {
@ -228,6 +233,9 @@ public:
return Vec3(f, f, f);
}
// Default comparison operators
[[nodiscard]] auto operator<=>(const Vec3& other) const = default;
[[nodiscard]] constexpr Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
return {x + other.x, y + other.y, z + other.z};
}
@ -412,6 +420,8 @@ inline float Vec3<float>::Normalize() {
}
using Vec3f = Vec3<float>;
using Vec3u = Vec3<unsigned>;
using Vec3i = Vec3<int>;
template <typename T>
class Vec4 {
@ -448,6 +458,9 @@ public:
return Vec4(f, f, f, f);
}
// Default comparison operators
[[nodiscard]] auto operator<=>(const Vec4& other) const = default;
[[nodiscard]] constexpr Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
return {x + other.x, y + other.y, z + other.z, w + other.w};
}
@ -623,6 +636,8 @@ template <typename T, typename V>
}
using Vec4f = Vec4<float>;
using Vec4u = Vec4<unsigned>;
using Vec4i = Vec4<int>;
template <typename T>
constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b) {

View File

@ -158,10 +158,10 @@ struct ABIFrameInfo {
inline ABIFrameInfo ABI_CalculateFrameSize(std::bitset<32> regs, std::size_t rsp_alignment,
std::size_t needed_frame_size) {
int count = (regs & ABI_ALL_GPRS).count();
std::size_t count = (regs & ABI_ALL_GPRS).count();
rsp_alignment -= count * 8;
std::size_t subtraction = 0;
int xmm_count = (regs & ABI_ALL_XMMS).count();
std::size_t xmm_count = (regs & ABI_ALL_XMMS).count();
if (xmm_count) {
// If we have any XMMs to save, we must align the stack here.
subtraction = rsp_alignment & 0xF;

View File

@ -14,6 +14,8 @@ add_library(core STATIC
arm/dyncom/arm_dyncom_thumb.h
arm/dyncom/arm_dyncom_trans.cpp
arm/dyncom/arm_dyncom_trans.h
arm/exclusive_monitor.cpp
arm/exclusive_monitor.h
arm/skyeye_common/arm_regformat.h
arm/skyeye_common/armstate.cpp
arm/skyeye_common/armstate.h
@ -473,7 +475,7 @@ endif()
create_target_directory_groups(core)
target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core)
target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp fmt open_source_archives Boost::serialization)
target_link_libraries(core PUBLIC Boost::boost PRIVATE nihstro-headers cryptopp-static fmt::fmt open_source_archives Boost::serialization)
if (ENABLE_WEB_SERVICE)
target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE -DCPPHTTPLIB_OPENSSL_SUPPORT)
@ -483,12 +485,14 @@ if (ENABLE_WEB_SERVICE)
endif()
endif()
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_ARM64)
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
target_sources(core PRIVATE
arm/dynarmic/arm_dynarmic.cpp
arm/dynarmic/arm_dynarmic.h
arm/dynarmic/arm_dynarmic_cp15.cpp
arm/dynarmic/arm_dynarmic_cp15.h
arm/dynarmic/arm_exclusive_monitor.cpp
arm/dynarmic/arm_exclusive_monitor.h
)
target_link_libraries(core PRIVATE dynarmic)
endif()

View File

@ -122,6 +122,9 @@ public:
*/
virtual void InvalidateCacheRange(u32 start_address, std::size_t length) = 0;
/// Clears the exclusive monitor's state.
virtual void ClearExclusiveState() = 0;
/// Notify CPU emulation that page tables have changed
virtual void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) = 0;

View File

@ -3,12 +3,14 @@
// Refer to the license.txt file included.
#include <cstring>
#include <dynarmic/A32/a32.h>
#include <dynarmic/A32/context.h>
#include <dynarmic/interface/A32/a32.h>
#include <dynarmic/interface/A32/context.h>
#include <dynarmic/interface/optimization_flags.h>
#include "common/assert.h"
#include "common/microprofile.h"
#include "core/arm/dynarmic/arm_dynarmic.h"
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/gdbstub/gdbstub.h"
@ -100,10 +102,23 @@ public:
memory.Write64(vaddr, value);
}
bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override {
return memory.WriteExclusive8(vaddr, value, expected);
}
bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override {
return memory.WriteExclusive16(vaddr, value, expected);
}
bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override {
return memory.WriteExclusive32(vaddr, value, expected);
}
bool MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expected) override {
return memory.WriteExclusive64(vaddr, value, expected);
}
void InterpreterFallback(VAddr pc, std::size_t num_instructions) override {
// Should never happen.
UNREACHABLE_MSG("InterpeterFallback reached with pc = 0x{:08x}, code = 0x{:08x}, num = {}",
pc, MemoryReadCode(pc), num_instructions);
pc, MemoryReadCode(pc).value(), num_instructions);
}
void CallSVC(std::uint32_t swi) override {
@ -133,7 +148,7 @@ public:
return;
}
ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", exception,
pc, MemoryReadCode(pc));
pc, MemoryReadCode(pc).value());
}
void AddTicks(std::uint64_t ticks) override {
@ -149,10 +164,12 @@ public:
Memory::MemorySystem& memory;
};
ARM_Dynarmic::ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory, u32 id,
std::shared_ptr<Core::Timing::Timer> timer)
: ARM_Interface(id, timer), system(*system), memory(memory),
cb(std::make_unique<DynarmicUserCallbacks>(*this)) {
ARM_Dynarmic::ARM_Dynarmic(Core::System* system_, Memory::MemorySystem& memory_, u32 core_id_,
std::shared_ptr<Core::Timing::Timer> timer_,
Core::ExclusiveMonitor& exclusive_monitor_)
: ARM_Interface(core_id_, timer_), system(*system_), memory(memory_),
cb(std::make_unique<DynarmicUserCallbacks>(*this)),
exclusive_monitor{dynamic_cast<Core::DynarmicExclusiveMonitor&>(exclusive_monitor_)} {
SetPageTable(memory.GetCurrentPageTable());
}
@ -291,6 +308,10 @@ void ARM_Dynarmic::InvalidateCacheRange(u32 start_address, std::size_t length) {
jit->InvalidateCacheRange(start_address, length);
}
void ARM_Dynarmic::ClearExclusiveState() {
jit->ClearExclusiveState();
}
std::shared_ptr<Memory::PageTable> ARM_Dynarmic::GetPageTable() const {
return current_page_table;
}
@ -328,6 +349,11 @@ std::unique_ptr<Dynarmic::A32::Jit> ARM_Dynarmic::MakeJit() {
config.page_table = &current_page_table->GetPointerArray();
config.coprocessors[15] = std::make_shared<DynarmicCP15>(cp15_state);
config.define_unpredictable_behaviour = true;
// Multi-process state
config.processor_id = GetID();
config.global_monitor = &exclusive_monitor.monitor;
return std::make_unique<Dynarmic::A32::Jit>(config);
}

View File

@ -6,7 +6,7 @@
#include <map>
#include <memory>
#include <dynarmic/A32/a32.h>
#include <dynarmic/interface/A32/a32.h>
#include "common/common_types.h"
#include "core/arm/arm_interface.h"
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
@ -17,6 +17,8 @@ class MemorySystem;
} // namespace Memory
namespace Core {
class DynarmicExclusiveMonitor;
class ExclusiveMonitor;
class System;
}
@ -24,8 +26,9 @@ class DynarmicUserCallbacks;
class ARM_Dynarmic final : public ARM_Interface {
public:
ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory, u32 id,
std::shared_ptr<Core::Timing::Timer> timer);
explicit ARM_Dynarmic(Core::System* system_, Memory::MemorySystem& memory_, u32 core_id_,
std::shared_ptr<Core::Timing::Timer> timer,
Core::ExclusiveMonitor& exclusive_monitor_);
~ARM_Dynarmic() override;
void Run() override;
@ -52,6 +55,7 @@ public:
void ClearInstructionCache() override;
void InvalidateCacheRange(u32 start_address, std::size_t length) override;
void ClearExclusiveState() override;
void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) override;
void PurgeState() override;
@ -69,6 +73,7 @@ private:
u32 fpexc = 0;
CP15State cp15_state;
Core::DynarmicExclusiveMonitor& exclusive_monitor;
Dynarmic::A32::Jit* jit = nullptr;
std::shared_ptr<Memory::PageTable> current_page_table = nullptr;

View File

@ -5,7 +5,7 @@
#pragma once
#include <memory>
#include <dynarmic/A32/coprocessor.h>
#include <dynarmic/interface/A32/coprocessor.h>
#include "common/common_types.h"
struct CP15State {

View 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

View 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

View File

@ -30,6 +30,7 @@ public:
void ClearInstructionCache() override;
void InvalidateCacheRange(u32 start_address, std::size_t length) override;
void ClearExclusiveState() override {};
void SetPC(u32 pc) override;
u32 GetPC() const override;

View 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

View 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

View File

@ -13,7 +13,8 @@
#include "common/logging/log.h"
#include "common/texture.h"
#include "core/arm/arm_interface.h"
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_ARM64)
#include "core/arm/exclusive_monitor.h"
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
#include "core/arm/dynarmic/arm_dynarmic.h"
#endif
#include "core/arm/dyncom/arm_dyncom.h"
@ -46,7 +47,7 @@
#include "core/rpc/rpc_server.h"
#include "core/settings.h"
#include "network/network.h"
#include "video_core/renderer_base.h"
#include "video_core/common/renderer.h"
#include "video_core/video_core.h"
namespace Core {
@ -364,11 +365,12 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
kernel = std::make_unique<Kernel::KernelSystem>(
*memory, *timing, [this] { PrepareReschedule(); }, system_mode, num_cores, n3ds_mode);
exclusive_monitor = MakeExclusiveMonitor(*memory, num_cores);
if (Settings::values.use_cpu_jit) {
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_ARM64)
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
for (u32 i = 0; i < num_cores; ++i) {
cpu_cores.push_back(
std::make_shared<ARM_Dynarmic>(this, *memory, i, timing->GetTimer(i)));
std::make_shared<ARM_Dynarmic>(this, *memory, i, timing->GetTimer(i), *exclusive_monitor));
}
#else
for (u32 i = 0; i < num_cores; ++i) {
@ -436,7 +438,7 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
return ResultStatus::Success;
}
RendererBase& System::Renderer() {
VideoCore::DisplayRenderer& System::Renderer() {
return *VideoCore::g_renderer;
}
@ -543,6 +545,7 @@ void System::Shutdown(bool is_deserializing) {
dsp_core.reset();
kernel.reset();
cpu_cores.clear();
exclusive_monitor.reset();
timing.reset();
if (video_dumper && video_dumper->IsDumping()) {

View File

@ -57,10 +57,13 @@ namespace VideoDumper {
class Backend;
}
class RendererBase;
namespace VideoCore {
class DisplayRenderer;
}
namespace Core {
class ExclusiveMonitor;
class Timing;
class System {
@ -205,7 +208,7 @@ public:
return *dsp_core;
}
[[nodiscard]] RendererBase& Renderer();
[[nodiscard]] VideoCore::DisplayRenderer& Renderer();
/**
* Gets a reference to the service manager.
@ -363,6 +366,8 @@ private:
std::unique_ptr<Kernel::KernelSystem> kernel;
std::unique_ptr<Timing> timing;
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
private:
static System s_instance;

View File

@ -101,7 +101,7 @@ struct ArchiveFormatInfo {
u32_le number_files; ///< The pre-defined number of files in the archive.
u8 duplicate_data; ///< Whether the archive should duplicate the data.
};
static_assert(std::is_pod<ArchiveFormatInfo>::value, "ArchiveFormatInfo is not POD");
static_assert(std::is_trivial_v<ArchiveFormatInfo>, "ArchiveFormatInfo is not POD");
class ArchiveBackend : NonCopyable {
public:

View File

@ -12,6 +12,15 @@
namespace Frontend {
/// Information for the Graphics Backends signifying what type of screen pointer is in
/// WindowInformation
enum class WindowSystemType {
Headless,
Windows,
X11,
Wayland,
};
struct Frame;
/**
* For smooth Vsync rendering, we want to always present the latest frame that the core generates,
@ -52,19 +61,48 @@ public:
};
/**
* Represents a graphics context that can be used for background computation or drawing. If the
* graphics backend doesn't require the context, then the implementation of these methods can be
* stubs
* Represents a drawing context that supports graphics operations.
*/
class GraphicsContext {
public:
virtual ~GraphicsContext();
/// Inform the driver to swap the front/back buffers and present the current image
virtual void SwapBuffers() {}
/// Makes the graphics context current for the caller thread
virtual void MakeCurrent() = 0;
virtual void MakeCurrent() {}
/// Releases (dunno if this is the "right" word) the context from the caller thread
virtual void DoneCurrent() = 0;
virtual void DoneCurrent() {}
class Scoped {
public:
[[nodiscard]] explicit Scoped(GraphicsContext& context_) : context(context_) {
context.MakeCurrent();
}
~Scoped() {
if (active) {
context.DoneCurrent();
}
}
/// In the event that context was destroyed before the Scoped is destroyed, this provides a
/// mechanism to prevent calling a destroyed object's method during the deconstructor
void Cancel() {
active = false;
}
private:
GraphicsContext& context;
bool active{true};
};
/// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value
/// ends
[[nodiscard]] Scoped Acquire() {
return Scoped{*this};
}
};
/**
@ -95,6 +133,23 @@ public:
std::pair<unsigned, unsigned> min_client_area_size;
};
/// Data describing host window system information
struct WindowSystemInfo {
// Window system type. Determines which GL context or Vulkan WSI is used.
WindowSystemType type = WindowSystemType::Headless;
// Connection to a display server. This is used on X11 and Wayland platforms.
void* display_connection = nullptr;
// Render surface. This is a pointer to the native window handle, which depends
// on the platform. e.g. HWND for Windows, Window for X11. If the surface is
// set to nullptr, the video backend will run in headless mode.
void* render_surface = nullptr;
// Scale of the render surface. For hidpi systems, this will be >1.
float render_surface_scale = 1.0f;
};
/// Polls window events
virtual void PollEvents() = 0;
@ -148,6 +203,13 @@ public:
config = val;
}
/**
* Returns system information about the drawing area.
*/
const WindowSystemInfo& GetWindowInfo() const {
return window_info;
}
/**
* Gets the framebuffer layout (width, height, and screen regions)
* @note This method is thread-safe
@ -194,6 +256,8 @@ protected:
framebuffer_layout = layout;
}
WindowSystemInfo window_info;
private:
/**
* Handler called when the minimal client area was requested to be changed via SetConfig.

View File

@ -20,8 +20,8 @@
#include "core/tracer/recorder.h"
#include "video_core/command_processor.h"
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_base.h"
#include "video_core/common/rasterizer.h"
#include "video_core/common/renderer.h"
#include "video_core/utils.h"
#include "video_core/video_core.h"

View File

@ -9,6 +9,7 @@
#include "audio_core/dsp_interface.h"
#include "common/archives.h"
#include "common/assert.h"
#include "common/atomic_ops.h"
#include "common/common_types.h"
#include "common/logging/log.h"
#include "common/swap.h"
@ -20,7 +21,9 @@
#include "core/hle/lock.h"
#include "core/memory.h"
#include "core/settings.h"
#include "video_core/renderer_base.h"
//#include "video_core/renderer_base.h"
#include "video_core/common/renderer.h"
#include "video_core/common/rasterizer.h"
#include "video_core/video_core.h"
SERIALIZE_EXPORT_IMPL(Memory::MemorySystem::BackingMemImpl<Memory::Region::FCRAM>)
@ -373,6 +376,38 @@ void MemorySystem::Write(const VAddr vaddr, const T data) {
}
}
template <typename T>
bool MemorySystem::WriteExclusive(const VAddr vaddr, const T data, const T expected) {
u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS];
if (page_pointer) {
const auto volatile_pointer = reinterpret_cast<volatile T*>(&page_pointer[vaddr & PAGE_MASK]);
return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
}
PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS];
switch (type) {
case PageType::Unmapped:
LOG_ERROR(HW_Memory, "unmapped Write{} 0x{:08X} @ 0x{:08X} at PC 0x{:08X}",
sizeof(data) * 8, (u32)data, vaddr, Core::GetRunningCore().GetPC());
return true;
case PageType::Memory:
ASSERT_MSG(false, "Mapped memory page without a pointer @ {:08X}", vaddr);
return true;
case PageType::RasterizerCachedMemory: {
RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Invalidate);
const auto volatile_pointer = reinterpret_cast<volatile T*>(GetPointerForRasterizerCache(vaddr).GetPtr());
return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
}
case PageType::Special:
WriteMMIO<T>(GetMMIOHandler(*impl->current_page_table, vaddr), vaddr, data);
return false;
default:
UNREACHABLE();
}
return true;
}
bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
auto& page_table = *process.vm_manager.page_table;
@ -732,6 +767,22 @@ void MemorySystem::Write64(const VAddr addr, const u64 data) {
Write<u64_le>(addr, data);
}
bool MemorySystem::WriteExclusive8(const VAddr addr, const u8 data, const u8 expected) {
return WriteExclusive<u8>(addr, data, expected);
}
bool MemorySystem::WriteExclusive16(const VAddr addr, const u16 data, const u16 expected) {
return WriteExclusive<u16_le>(addr, data, expected);
}
bool MemorySystem::WriteExclusive32(const VAddr addr, const u32 data, const u32 expected) {
return WriteExclusive<u32_le>(addr, data, expected);
}
bool MemorySystem::WriteExclusive64(const VAddr addr, const u64 data, const u64 expected) {
return WriteExclusive<u64_le>(addr, data, expected);
}
void MemorySystem::WriteBlock(const Kernel::Process& process, const VAddr dest_addr,
const void* src_buffer, const std::size_t size) {
auto& page_table = *process.vm_manager.page_table;

View File

@ -327,6 +327,23 @@ public:
void Write32(VAddr addr, u32 data);
void Write64(VAddr addr, u64 data);
/**
* Writes a {8, 16, 32, 64}-bit unsigned integer to the given virtual address in
* the current process' address space if and only if the address contains
* the expected value. This operation is atomic.
*
* @param addr The virtual address to write the X-bit unsigned integer to.
* @param data The X-bit unsigned integer to write to the given virtual address.
* @param expected The X-bit unsigned integer to check against the given virtual address.
* @returns true if the operation failed
*
* @post The memory range [addr, sizeof(data)) contains the given data value.
*/
bool WriteExclusive8(const VAddr addr, const u8 data, const u8 expected);
bool WriteExclusive16(const VAddr addr, const u16 data, const u16 expected);
bool WriteExclusive32(const VAddr addr, const u32 data, const u32 expected);
bool WriteExclusive64(const VAddr addr, const u64 data, const u64 expected);
void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer,
std::size_t size);
void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
@ -384,6 +401,9 @@ private:
template <typename T>
void Write(const VAddr vaddr, const T data);
template <typename T>
bool WriteExclusive(const VAddr vaddr, const T data, const T expected);
/**
* Gets the pointer for virtual memory where the page is marked as RasterizerCachedMemory.
* This is used to access the memory where the page pointer is nullptr due to rasterizer cache.

View File

@ -14,7 +14,7 @@
#include "core/hle/service/ir/ir_user.h"
#include "core/hle/service/mic_u.h"
#include "core/settings.h"
#include "video_core/renderer_base.h"
#include "video_core/common/renderer.h"
#include "video_core/video_core.h"
namespace Settings {

View File

@ -14,6 +14,11 @@
namespace Settings {
enum class RendererBackend : u32 {
OpenGL = 0,
Vulkan = 1,
};
enum class InitClock {
SystemTime = 0,
FixedTime = 1,
@ -24,11 +29,9 @@ enum class LayoutOption {
SingleScreen,
LargeScreen,
SideScreen,
// Similiar to default, but better for mobile devices in portrait mode. Top screen in clamped to
// the top of the frame, and the bottom screen is enlarged to match the top screen.
MobilePortrait,
// Similiar to LargeScreen, but better for mobile devices in landscape mode. The screens are
// clamped to the top of the frame, and the bottom screen is a bit bigger.
MobileLandscape,
@ -111,7 +114,6 @@ namespace NativeAnalog {
enum Values {
CirclePad,
CStick,
NumAnalogs,
};
@ -164,6 +166,8 @@ struct Values {
u64 init_time;
// Renderer
RendererBackend renderer_backend = RendererBackend::Vulkan;
bool renderer_debug = true;
bool use_gles;
bool use_hw_renderer;
bool use_hw_shader;

View File

@ -13,7 +13,7 @@ if (ENABLE_WEB_SERVICE)
target_link_libraries(citra-room PRIVATE web_service)
endif()
target_link_libraries(citra-room PRIVATE cryptopp glad)
target_link_libraries(citra-room PRIVATE cryptopp-static glad::glad)
if (MSVC)
target_link_libraries(citra-room PRIVATE getopt)
endif()

View File

@ -28,7 +28,7 @@ if(SDL2_FOUND)
sdl/sdl_impl.cpp
sdl/sdl_impl.h
)
target_link_libraries(input_common PRIVATE SDL2)
target_link_libraries(input_common PRIVATE SDL2::SDL2)
target_compile_definitions(input_common PRIVATE HAVE_SDL2)
endif()

View File

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include "core/3ds.h"
#include "core/settings.h"
#include "input_common/touch_from_button.h"

View File

@ -13,4 +13,4 @@ add_library(network STATIC
create_target_directory_groups(network)
target_link_libraries(network PRIVATE common enet Boost::serialization)
target_link_libraries(network PRIVATE common unofficial::enet::enet Boost::serialization)

Some files were not shown because too many files have changed in this diff Show More