mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-15 13:16:43 +00:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b02db21e45 | |||
| 7dde5a4b3e | |||
| 5de66b2a53 | |||
| 86b31fcad9 | |||
| ecc28bd9c3 | |||
| a4e1c4b20e | |||
| 71aedd5f74 | |||
| 943b42209e | |||
| e786bc8a51 | |||
| 8513d3da7c | |||
| 0330b90f1a | |||
| f2dfdf6970 | |||
| d73bc5ba9e | |||
| 7fd81bb9f4 | |||
| 3f24787575 | |||
| a8911d61ce | |||
| 2373027b79 | |||
| e7d8c3da71 | |||
| 36fcd1e350 | |||
| 38bcfe6781 | |||
| edefb4367f | |||
| 4a0ca0d022 | |||
| 7bd6f4cd77 | |||
| 6ce07fb0da | |||
| 7266d683aa | |||
| 2576cbc6d7 | |||
| 1e315dc34b | |||
| 118e2f441d | |||
| 4e012d9d56 | |||
| 018039eb3b | |||
| e7a931d06b | |||
| 8648c27cbb | |||
| def76946f0 | |||
| 13d39f39aa | |||
| 7731b5bc86 | |||
| c4ab2f6b9e | |||
| dd12266c26 | |||
| a3d32a18b8 | |||
| c0ffc900cd |
@@ -1,9 +1,9 @@
|
||||
name: tx-pull
|
||||
|
||||
on:
|
||||
# tuesday, saturday at 2pm
|
||||
# monday at 4pm
|
||||
schedule:
|
||||
- cron: '0 14 * * 2,6'
|
||||
- cron: '0 16 * * 1'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -3,7 +3,7 @@ description: File a bug report
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Tech support does not belong here. You should only file an issue here if you think you have experienced an actual bug with yuzu.
|
||||
value: Tech support does not belong here. You should only file an issue here if you think you have experienced an actual bug with Eden.
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
@@ -43,7 +43,7 @@ body:
|
||||
id: log
|
||||
attributes:
|
||||
label: Log File
|
||||
description: A log file will help our developers to better diagnose and fix the issue. Instructions can be found [here](https://yuzu-emu.org/help/reference/log-files).
|
||||
description: A log file will help our developers to better diagnose and fix the issue. Instructions can be found [here](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/HowToAccessLogs.md).
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
@@ -4,7 +4,7 @@ labels: "request"
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Tech support does not belong here. You should only file an issue here if you are requesting a feature you believe would make yuzu better.
|
||||
value: Tech support does not belong here. You should only file an issue here if you are requesting a feature you believe would make Eden better.
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
@@ -23,6 +23,6 @@ body:
|
||||
id: why-feature
|
||||
attributes:
|
||||
label: Why would this feature be useful?
|
||||
description: A brief description of why this feature would make yuzu better.
|
||||
description: A brief description of why this feature would make Eden better.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
+29
-15
@@ -28,23 +28,23 @@ if (NOT DEFINED ARCHITECTURE)
|
||||
endif()
|
||||
|
||||
# Needed for FFmpeg w/ VAAPI and DRM
|
||||
if (PLATFORM_OPENBSD)
|
||||
if (OPENBSD)
|
||||
# OpenBSD 7.8 broke libcxx when upgrading, so we must define the PSTL backend manually
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R6/include -D_LIBCPP_PSTL_BACKEND_SERIAL=1")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R6/include -D_LIBCPP_PSTL_BACKEND_SERIAL=1")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_SYSROOT}/usr/X11R6/lib")
|
||||
elseif (PLATFORM_NETBSD)
|
||||
elseif (NETBSD)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R7/include -I${CMAKE_SYSROOT}/usr/pkg/include/c++/v1")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R7/include -I${CMAKE_SYSROOT}/usr/pkg/include/c++/v1")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_SYSROOT}/usr/X11R7/lib")
|
||||
endif()
|
||||
|
||||
# NetBSD: Fun for the whole family!
|
||||
if (PLATFORM_NETBSD)
|
||||
if (NETBSD)
|
||||
set(ENV{PKG_CONFIG_PATH} "${PKG_CONFIG_PATH}:${CMAKE_SYSROOT}/usr/pkg/lib/ffmpeg7/pkgconfig")
|
||||
endif()
|
||||
|
||||
cmake_dependent_option(YUZU_STATIC_ROOM "Build a static room executable only (CI only)" OFF "PLATFORM_LINUX" OFF)
|
||||
cmake_dependent_option(YUZU_STATIC_ROOM "Build a static room executable only (CI only)" OFF "LINUX" OFF)
|
||||
if (YUZU_STATIC_ROOM)
|
||||
set(YUZU_ROOM ON)
|
||||
set(YUZU_ROOM_STANDALONE ON)
|
||||
@@ -79,6 +79,7 @@ set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundl
|
||||
cmake_dependent_option(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF)
|
||||
|
||||
option(ENABLE_DEBUG_TOOLS "Enable debugging tools (maxwell disassembler, SPIRV translator, etc)" OFF)
|
||||
option(ENABLE_WERROR "Enable -Werror diagnostics" ON)
|
||||
|
||||
# non-linux bundled qt are static
|
||||
if (YUZU_USE_BUNDLED_QT AND (APPLE OR NOT UNIX))
|
||||
@@ -157,6 +158,19 @@ if (CXX_CLANG_CL)
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-reserved-identifier>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-deprecated-declarations>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-cast-function-type-mismatch>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c99-extensions>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c++17-compat>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c++11-compat-reserved-user-defined-literal>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c++11-compat-deprecated-writable-strings>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c++11-compat-pedantic>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c++11-compat>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c++0x-compat>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c++98-c++11-compat-binary-literal>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c++98-compat-pedantic>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c++98-compat>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c99-compat>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c98-compat>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-c99-extensions>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:/EHsc>)
|
||||
# REQUIRED CPU features IN Windows-amd64
|
||||
if (ARCHITECTURE_x86_64)
|
||||
@@ -210,7 +224,7 @@ endif()
|
||||
|
||||
# ffmpeg
|
||||
option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT})
|
||||
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from external source" "${PLATFORM_SUN}" "NOT WIN32 AND NOT ANDROID" OFF)
|
||||
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from external source" "${SOLARIS}" "NOT WIN32 AND NOT ANDROID" OFF)
|
||||
|
||||
# sirit
|
||||
set(BUNDLED_SIRIT_DEFAULT OFF)
|
||||
@@ -221,7 +235,7 @@ endif()
|
||||
option(YUZU_USE_BUNDLED_SIRIT "Download bundled sirit" ${BUNDLED_SIRIT_DEFAULT})
|
||||
|
||||
# FreeBSD 15+ has libusb, versions below should disable it
|
||||
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR PLATFORM_LINUX OR PLATFORM_FREEBSD OR APPLE" OFF)
|
||||
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR LINUX OR FREEBSD OR APPLE" OFF)
|
||||
|
||||
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT (WIN32 AND ARCHITECTURE_arm64) AND NOT APPLE" OFF)
|
||||
mark_as_advanced(FORCE ENABLE_OPENGL)
|
||||
@@ -235,7 +249,7 @@ option(YUZU_TESTS "Compile tests" "${BUILD_TESTING}")
|
||||
|
||||
# Install udev rules on Linux (mainly for gyros)
|
||||
# Only acts on joysticks and nothing else.
|
||||
cmake_dependent_option(YUZU_INSTALL_UDEV_RULES "Install udev rules for gyro access" OFF "PLATFORM_LINUX" OFF)
|
||||
cmake_dependent_option(YUZU_INSTALL_UDEV_RULES "Install udev rules for gyro access" OFF "LINUX" OFF)
|
||||
|
||||
option(YUZU_DOWNLOAD_ANDROID_VVL "Download validation layer binary for android" ON)
|
||||
|
||||
@@ -248,7 +262,7 @@ cmake_dependent_option(YUZU_ROOM_STANDALONE "Enable standalone room executable"
|
||||
|
||||
cmake_dependent_option(YUZU_CMD "Compile the eden-cli executable" ON "NOT ANDROID" OFF)
|
||||
|
||||
cmake_dependent_option(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR PLATFORM_LINUX" OFF)
|
||||
cmake_dependent_option(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF)
|
||||
|
||||
option(YUZU_DOWNLOAD_TIME_ZONE_DATA "Always download time zone binaries" ON)
|
||||
set(YUZU_TZDB_PATH "" CACHE STRING "Path to a pre-downloaded timezone database")
|
||||
@@ -258,7 +272,7 @@ cmake_dependent_option(YUZU_USE_BUNDLED_MOLTENVK "Download bundled MoltenVK lib"
|
||||
option(YUZU_DISABLE_LLVM "Disable LLVM (useful for CI)" OFF)
|
||||
|
||||
set(DEFAULT_YUZU_USE_BUNDLED_OPENSSL OFF)
|
||||
if (EXT_DEFAULT OR PLATFORM_SUN OR PLATFORM_OPENBSD)
|
||||
if (EXT_DEFAULT OR SOLARIS OR OPENBSD)
|
||||
set(DEFAULT_YUZU_USE_BUNDLED_OPENSSL ON)
|
||||
endif()
|
||||
|
||||
@@ -281,7 +295,7 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/hooks/pre-commit AND NOT EXISTS ${PROJECT_SOURCE
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_arm64 AND (ANDROID OR PLATFORM_LINUX))
|
||||
if (ARCHITECTURE_arm64 AND (ANDROID OR LINUX))
|
||||
set(HAS_NCE 1)
|
||||
add_compile_definitions(HAS_NCE=1)
|
||||
endif()
|
||||
@@ -290,7 +304,7 @@ if (YUZU_ROOM)
|
||||
add_compile_definitions(YUZU_ROOM)
|
||||
endif()
|
||||
|
||||
if (UNIX AND NOT (PLATFORM_LINUX OR WIN32))
|
||||
if (UNIX AND NOT (LINUX OR WIN32))
|
||||
if(CXX_APPLE OR CXX_CLANG)
|
||||
# libc++ has stop_token and jthread as experimental
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexperimental-library")
|
||||
@@ -404,7 +418,7 @@ if (Boost_ADDED)
|
||||
|
||||
if (NOT MSVC OR CXX_CLANG)
|
||||
# boost sucks
|
||||
if (PLATFORM_SUN)
|
||||
if (SOLARIS)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-pthreads>)
|
||||
endif()
|
||||
|
||||
@@ -508,9 +522,9 @@ elseif (WIN32)
|
||||
# PSAPI is the Process Status API
|
||||
set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version crypt32 rpcrt4 gdi32 wldap32 mswsock)
|
||||
endif()
|
||||
elseif (PLATFORM_MANAGARM)
|
||||
elseif (MANAGARM)
|
||||
set(PLATFORM_LIBRARIES iconv intl)
|
||||
elseif (PLATFORM_HAIKU)
|
||||
elseif (HAIKUOS)
|
||||
# Haiku is so special :)
|
||||
set(PLATFORM_LIBRARIES bsd /boot/system/lib/libnetwork.so)
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$")
|
||||
@@ -604,7 +618,7 @@ if (ENABLE_QT)
|
||||
|
||||
# Best practice is to ask for all components at once, so they are from the same version
|
||||
set(YUZU_QT_COMPONENTS Core Widgets Charts Concurrent Gui)
|
||||
if (PLATFORM_LINUX OR PLATFORM_FREEBSD)
|
||||
if (LINUX OR FREEBSD)
|
||||
list(APPEND YUZU_QT_COMPONENTS DBus)
|
||||
# yes Qt, we get it
|
||||
set(QT_NO_PRIVATE_MODULE_WARNING ON)
|
||||
|
||||
@@ -13,7 +13,7 @@ find_package_handle_standard_args(Opus
|
||||
VERSION_VAR OPUS_VERSION
|
||||
)
|
||||
|
||||
if (PLATFORM_MSYS)
|
||||
if (MSYS2)
|
||||
FixMsysPath(PkgConfig::OPUS)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ find_package_handle_standard_args(enet
|
||||
VERSION_VAR ENET_VERSION
|
||||
)
|
||||
|
||||
if (PLATFORM_MSYS)
|
||||
if (MSYS2)
|
||||
FixMsysPath(PkgConfig::ENET)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ find_package_handle_standard_args(libusb
|
||||
VERSION_VAR LIBUSB_VERSION
|
||||
)
|
||||
|
||||
if (PLATFORM_MSYS)
|
||||
if (MSYS2)
|
||||
FixMsysPath(PkgConfig::LIBUSB)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ else()
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(LZ4 QUIET IMPORTED_TARGET liblz4)
|
||||
|
||||
if (PLATFORM_MSYS)
|
||||
if (MSYS2)
|
||||
FixMsysPath(PkgConfig::LZ4)
|
||||
endif()
|
||||
|
||||
|
||||
+5
-1
@@ -22,9 +22,13 @@ Eden is free, open-source, copyleft software, licensed under the terms of the [G
|
||||
|
||||
- No LLM or AI usage, *period*, for patches, pull requests, issues, comments, debugging, brainstorming, etc.
|
||||
- For details on why, see the [detailed AI policy](docs/policies/AI.md).
|
||||
- Usage of any form of profanity or otherwise unsavory language is generally discouraged.
|
||||
- This is primarily because it rarely helps to actually understand what's going on.
|
||||
- Remember that your comments should be focused and actually address what's happening. With very few exceptions, expletives are actively detrimental at best.
|
||||
- New code must follow the same general style as the surrounding codebase. Exceptions may be granted in certain cases.
|
||||
- Maintainers reserve the right to change your patches and pull requests at will. We will try to avoid this.
|
||||
- You should respect all decisions made by the [code owners](docs/CODEOWNERS) in your particular subsystem. If you feel they are overstepping or are incorrect, don't be afraid to stand your ground!
|
||||
- You should generally respect all decisions made by the [code owners](docs/CODEOWNERS) in your particular subsystem.
|
||||
- However, if you feel they are overstepping or are incorrect, don't be afraid to stand your ground! Maintainers are not always correct.
|
||||
- While we do *not* adhere to the terms of a formal code of conduct, you will generally be expected to respect other developers, contributors, and community members.
|
||||
- You **must** have basic knowledge of [Git](https://git-scm.com/learn). Knowing how to manage your branches and follow proper fork policies is a necessity.
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ These options control dependencies.
|
||||
- `YUZU_INSTALL_UDEV_RULES` (OFF) Install udev rules to enable hidraw access
|
||||
- Needed for gyroscopes
|
||||
- Only available on Linux
|
||||
- `ENABLE_DEBUG_TOOLS` (OFF) Enables debugging and development tools, see [tools](../tools/README.md).
|
||||
- `ENABLE_WERROR` (ON) Enables warnings as errors (-Werror).
|
||||
|
||||
### Flavors
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ Everyone has their own way of viewing good/bad C++ practices, my general outline
|
||||
- The reason is because the project has `-fno-rtti` disabled by default, due to the costs of dynamic polymorphism.
|
||||
- Always copy-on-value for objects with `sizeof(void *) >= sizeof(T) * 2`, i.e objects sized as 2 pointers or less, for bigger objects you can use ref/pointer as usual.
|
||||
- Try using move semantics instead of references, whenever possible.
|
||||
- Remember function parameters are extremelly cheap as fuck, don't be afraid to place upto 8 parameters on a given function.
|
||||
- Function parameters are cheap. Don't be afraid to use as many as needed (API usability permitting).
|
||||
- Don't save a reference in structures of a parent object, i.e:
|
||||
|
||||
```c++
|
||||
|
||||
Vendored
+1
-1
@@ -164,7 +164,7 @@ if (NOT ANDROID)
|
||||
AddJsonPackage(sdl3)
|
||||
else()
|
||||
message(STATUS "Using bundled SDL3")
|
||||
if (PLATFORM_FREEBSD)
|
||||
if (FREEBSD)
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
endif()
|
||||
AddJsonPackage(sdl3-ci)
|
||||
|
||||
+23
-80
@@ -1,45 +1,46 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2025 crueter
|
||||
# SPDX-FileCopyrightText: Copyright 2026 crueter
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
## DetectPlatform ##
|
||||
|
||||
# This is a small helper that sets PLATFORM_<platform> variables for various
|
||||
# This is a small helper that sets platform variables for various
|
||||
# operating systems and distributions. Note that Apple, Windows, Android, etc.
|
||||
# are not covered, as CMake already does that for us.
|
||||
|
||||
# It also sets CXX_<compiler> for the C++ compiler.
|
||||
|
||||
# Furthermore, some platforms have really silly requirements/quirks, so this
|
||||
# also does a few of those.
|
||||
|
||||
# This module contains contributions from the Eden Emulator Project,
|
||||
# notably from crueter and Lizzie.
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "SunOS")
|
||||
set(PLATFORM_SUN ON)
|
||||
set(SOLARIS ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "OpenOrbis")
|
||||
set(PLATFORM_PS4 ON)
|
||||
set(OPENORBIS ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "managarm")
|
||||
set(PLATFORM_MANAGARM ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
|
||||
set(PLATFORM_FREEBSD ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
|
||||
set(PLATFORM_OPENBSD ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "NetBSD")
|
||||
set(PLATFORM_NETBSD ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "DragonFly")
|
||||
set(PLATFORM_DRAGONFLYBSD ON)
|
||||
set(MANAGARM ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Haiku")
|
||||
set(PLATFORM_HAIKU ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(PLATFORM_LINUX ON)
|
||||
set(HAIKUOS ON)
|
||||
endif()
|
||||
|
||||
# BSD
|
||||
if (DEFINED BSD)
|
||||
if ("${BSD}" STREQUAL "DragonFlyBSD")
|
||||
set(DRAGONFLYBSD ON)
|
||||
elseif ("${BSD}" STREQUAL "FreeBSD")
|
||||
set(FREEBSD ON)
|
||||
elseif ("${BSD}" STREQUAL "OpenBSD")
|
||||
set(OPENBSD ON)
|
||||
elseif ("${BSD}" STREQUAL "NetBSD")
|
||||
set(NETBSD ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# dumb heuristic to detect msys2
|
||||
if (CMAKE_COMMAND MATCHES "msys64")
|
||||
set(PLATFORM_MSYS ON)
|
||||
set(MSYS2 ON)
|
||||
endif()
|
||||
|
||||
# compiler checks
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(CXX_CLANG ON)
|
||||
if (MSVC)
|
||||
@@ -47,8 +48,6 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
endif()
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(CXX_GCC ON)
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
set(CXX_CL ON)
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM")
|
||||
set(CXX_ICC ON)
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
@@ -61,37 +60,13 @@ if(MINGW AND CXX_CLANG)
|
||||
set(CMAKE_SYSTEM_VERSION 10.0.0)
|
||||
endif()
|
||||
|
||||
# NB: this does not account for SPARC
|
||||
if (PLATFORM_SUN)
|
||||
# Terrific OpenIndiana pkg shenanigans
|
||||
list(APPEND CMAKE_PREFIX_PATH
|
||||
"${CMAKE_SYSROOT}/usr/lib/qt/6.6/lib/amd64/cmake")
|
||||
list(APPEND CMAKE_MODULE_PATH
|
||||
"${CMAKE_SYSROOT}/usr/lib/qt/6.6/lib/amd64/cmake")
|
||||
|
||||
# Amazing - absolutely incredible
|
||||
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_SYSROOT}/usr/lib/amd64/cmake")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SYSROOT}/usr/lib/amd64/cmake")
|
||||
|
||||
# For some mighty reason, doing a normal release build sometimes
|
||||
# may not trigger the proper -O3 switch to materialize
|
||||
if (CMAKE_BUILD_TYPE MATCHES "Release")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
|
||||
endif()
|
||||
if (CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# MSYS2 utilities
|
||||
|
||||
# Sometimes, PkgConfig modules will incorrectly reference / when CMake
|
||||
# wants you to reference it as C:/msys64/. This function corrects that.
|
||||
# Example in a Find module:
|
||||
#[[
|
||||
if (PLATFORM_MSYS)
|
||||
if (MSYS2)
|
||||
FixMsysPath(PkgConfig::OPUS)
|
||||
endif()
|
||||
]]
|
||||
@@ -116,41 +91,9 @@ function(FixMsysPath target)
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${include_dir})
|
||||
endfunction()
|
||||
|
||||
# MSYSTEM handling + program_path
|
||||
if (PLATFORM_MSYS)
|
||||
# really, really dumb heuristic to detect what environment we are in
|
||||
macro(system var)
|
||||
if (CMAKE_COMMAND MATCHES ${var})
|
||||
set(MSYSTEM ${var})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
system(mingw64)
|
||||
system(clang64)
|
||||
system(clangarm64)
|
||||
system(ucrt64)
|
||||
|
||||
if (NOT DEFINED MSYSTEM)
|
||||
set(MSYSTEM msys2)
|
||||
endif()
|
||||
|
||||
# We generally want to prioritize environment-specific binaries if possible
|
||||
# some, like autoconf, are not present on environments besides msys2 though
|
||||
set(CMAKE_PROGRAM_PATH C:/msys64/${MSYSTEM}/bin C:/msys64/usr/bin)
|
||||
set(ENV{PKG_CONFIG_PATH} C:/msys64/${MSYSTEM}/lib/pkgconfig)
|
||||
endif()
|
||||
|
||||
# This saves a truly ridiculous amount of time during linking
|
||||
# In my tests, without this, Eden takes 2 mins, with this, it takes 3-5 seconds
|
||||
# or on GitHub Actions, 10 minutes -> 3 seconds
|
||||
# Saves linking time
|
||||
if (MINGW)
|
||||
set(MINGW_FLAGS "-Wl,--strip-all -Wl,--gc-sections")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE
|
||||
"${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${MINGW_FLAGS}")
|
||||
endif()
|
||||
|
||||
# awesome
|
||||
if (PLATFORM_FREEBSD OR PLATFORM_DRAGONFLYBSD)
|
||||
set(CMAKE_EXE_LINKER_FLAGS
|
||||
"${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_SYSROOT}/usr/local/lib")
|
||||
endif()
|
||||
|
||||
Vendored
+5
-5
@@ -56,7 +56,7 @@ if (NOT YUZU_USE_BUNDLED_FFMPEG)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (PLATFORM_PS4 OR PLATFORM_MANAGARM)
|
||||
if (OPENORBIS OR MANAGARM)
|
||||
# Doesn't support VA-API, don't go thru the embarrassment of trying to enable it
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi)
|
||||
elseif (ANDROID)
|
||||
@@ -75,7 +75,7 @@ elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING AND NOT ANDROID)
|
||||
if(X11_FOUND)
|
||||
if (NOT APPLE)
|
||||
# In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so
|
||||
if(PLATFORM_SUN)
|
||||
if(SOLARIS)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES
|
||||
X11
|
||||
"${CMAKE_SYSROOT}/usr/lib/xorg/amd64/libdrm.so")
|
||||
@@ -158,7 +158,7 @@ elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING AND NOT ANDROID)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (PLATFORM_PS4)
|
||||
if (OPENORBIS)
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_LIBS
|
||||
-lkernel
|
||||
-lSceUserService
|
||||
@@ -172,7 +172,7 @@ if (PLATFORM_PS4)
|
||||
--extra-cxxflags=${CMAKE_SYSROOT}/usr/include
|
||||
--extra-libs="${FFmpeg_CROSS_COMPILE_LIBS}"
|
||||
)
|
||||
elseif (PLATFORM_MANAGARM)
|
||||
elseif (MANAGARM)
|
||||
# Required for proper stuff
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
|
||||
--disable-pthreads
|
||||
@@ -299,7 +299,7 @@ else()
|
||||
set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES})
|
||||
|
||||
# BSD make or Solaris make don't support ffmpeg make-j8
|
||||
if (PLATFORM_LINUX OR ANDROID OR APPLE OR WIN32 OR PLATFORM_FREEBSD)
|
||||
if (LINUX OR ANDROID OR APPLE OR WIN32 OR FREEBSD)
|
||||
set(FFmpeg_MAKE_ARGS -j${SYSTEM_THREADS})
|
||||
else()
|
||||
set(FFmpeg_MAKE_ARGS "")
|
||||
|
||||
Vendored
+1
-1
@@ -11,7 +11,7 @@ if (NOT libusb_ADDED)
|
||||
endif()
|
||||
|
||||
# TODO: *BSD fails to compile--may need different configs/symbols
|
||||
if (MINGW OR PLATFORM_LINUX OR APPLE)
|
||||
if (MINGW OR LINUX OR APPLE)
|
||||
set(LIBUSB_FOUND ON CACHE BOOL "libusb is present" FORCE)
|
||||
set(LIBUSB_VERSION "1.0.24" CACHE STRING "libusb version string" FORCE)
|
||||
|
||||
|
||||
Vendored
+2
-2
@@ -1177,7 +1177,7 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re
|
||||
#endif
|
||||
|
||||
#ifndef STBI_NO_TGA
|
||||
// test tga last because it's a crappy test!
|
||||
// test tga last because it's a bad test!
|
||||
if (stbi__tga_test(s))
|
||||
return stbi__tga_load(s,x,y,comp,req_comp, ri);
|
||||
#endif
|
||||
@@ -7662,7 +7662,7 @@ static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)
|
||||
if (stbi__hdr_info(s, x, y, comp)) return 1;
|
||||
#endif
|
||||
|
||||
// test tga last because it's a crappy test!
|
||||
// test tga last because it's a bad test!
|
||||
#ifndef STBI_NO_TGA
|
||||
if (stbi__tga_info(s, x, y, comp))
|
||||
return 1;
|
||||
|
||||
+21
-9
@@ -155,12 +155,24 @@ else()
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WERROR)
|
||||
add_compile_options(
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=all>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=extra>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=missing-declarations>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=shadow>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=unused>)
|
||||
else()
|
||||
add_compile_options(
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wall>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wextra>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wmissing-declarations>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wshadow>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wunused>
|
||||
# Some compilers could particularly misbehave :)
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-error-all>)
|
||||
endif()
|
||||
add_compile_options(
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=all>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=extra>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=missing-declarations>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=shadow>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=unused>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-attributes>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-invalid-offsetof>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-unused-parameter>
|
||||
@@ -169,9 +181,9 @@ else()
|
||||
if (CXX_CLANG OR CXX_ICC OR CXX_APPLE) # Clang, AppleClang, or Intel C++
|
||||
if (NOT MSVC)
|
||||
add_compile_options(
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=shadow-uncaptured-local>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=implicit-fallthrough>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=type-limits>)
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wshadow-uncaptured-local>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wimplicit-fallthrough>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wtype-limits>)
|
||||
endif()
|
||||
add_compile_options(
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-braced-scalar-init>
|
||||
@@ -181,7 +193,7 @@ else()
|
||||
|
||||
if (ARCHITECTURE_x86_64)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-mcx16>)
|
||||
if (PLATFORM_LINUX OR PLATFORM_FREEBSD)
|
||||
if (LINUX OR FREEBSD)
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:C,CXX>:-mtls-dialect=gnu2>)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
-1
@@ -27,7 +27,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
||||
RENDERER_ASYNCHRONOUS_GPU_EMULATION("use_asynchronous_gpu_emulation"),
|
||||
RENDERER_ASYNC_PRESENTATION("async_presentation"),
|
||||
RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders"),
|
||||
RENDERER_UNIFIED_MEMORY("use_unified_memory"),
|
||||
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
|
||||
ENABLE_BUFFER_HISTORY("enable_buffer_history"),
|
||||
USE_OPTIMIZED_VERTEX_BUFFERS("use_optimized_vertex_buffers"),
|
||||
|
||||
-7
@@ -685,13 +685,6 @@ abstract class SettingsItem(
|
||||
descriptionId = R.string.renderer_asynchronous_shaders_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.RENDERER_UNIFIED_MEMORY,
|
||||
titleId = R.string.renderer_unified_memory,
|
||||
descriptionId = R.string.renderer_unified_memory_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.FAST_GPU_TIME,
|
||||
|
||||
-1
@@ -304,7 +304,6 @@ class SettingsFragmentPresenter(
|
||||
add(BooleanSetting.EMULATE_BGR565.key)
|
||||
add(BooleanSetting.RESCALE_HACK.key)
|
||||
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
|
||||
add(BooleanSetting.RENDERER_UNIFIED_MEMORY.key)
|
||||
add(IntSetting.ANDROID_PIPELINE_WORKERS.key)
|
||||
add(BooleanSetting.RENDERER_ASYNCHRONOUS_GPU_EMULATION.key)
|
||||
add(BooleanSetting.RENDERER_ASYNC_PRESENTATION.key)
|
||||
|
||||
@@ -524,8 +524,6 @@
|
||||
<string name="rescale_hack_description">Enables a legacy handling for the rescale configuration pass for games by using a quick rescale path</string>
|
||||
<string name="renderer_asynchronous_shaders">Use asynchronous shaders</string>
|
||||
<string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously. This may reduce stutters but may also introduce glitches.</string>
|
||||
<string name="renderer_unified_memory">Unified memory access</string>
|
||||
<string name="renderer_unified_memory_description">Allows GPU write buffer readbacks directly into guest memory, skipping the CPU staging copy.</string>
|
||||
<string name="gpu_unswizzle_settings">GPU Unswizzle Settings</string>
|
||||
<string name="gpu_unswizzle_settings_description">Configure GPU-based texture unswizzling parameters or disable it entirely. Adjust these settings to balance performance and texture loading quality.</string>
|
||||
<string name="gpu_unswizzle_enable">Enable GPU Unswizzle</string>
|
||||
|
||||
@@ -222,7 +222,7 @@ if (MSVC)
|
||||
)
|
||||
else()
|
||||
target_compile_options(audio_core PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=conversion>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wconversion>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-sign-conversion>)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -108,7 +108,6 @@ add_library(
|
||||
settings_input.h
|
||||
settings_setting.h
|
||||
slot_vector.h
|
||||
socket_types.h
|
||||
spin_lock.h
|
||||
stb.cpp
|
||||
stb.h
|
||||
@@ -220,7 +219,7 @@ endif()
|
||||
if(CXX_CLANG)
|
||||
target_compile_options(common PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-fsized-deallocation>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=unreachable-code-aggressive>)
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wunreachable-code-aggressive>)
|
||||
target_compile_definitions(
|
||||
common
|
||||
PRIVATE
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "web_service/web_result.h"
|
||||
|
||||
namespace AnnounceMultiplayerRoom {
|
||||
|
||||
@@ -31,9 +31,7 @@ s64 GetMaxPermissibleResidentMapCount() {
|
||||
} // namespace
|
||||
|
||||
HeapTracker::HeapTracker(Common::HostMemory& buffer)
|
||||
: m_buffer(buffer),
|
||||
m_has_hardware_buffer_backing(!buffer.BackingHardwareBuffers().empty()),
|
||||
m_max_resident_map_count(GetMaxPermissibleResidentMapCount()) {}
|
||||
: m_buffer(buffer), m_max_resident_map_count(GetMaxPermissibleResidentMapCount()) {}
|
||||
HeapTracker::~HeapTracker() = default;
|
||||
|
||||
void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||
@@ -87,8 +85,7 @@ void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_hea
|
||||
|
||||
// If resident, erase from resident map.
|
||||
if (item->is_resident) {
|
||||
m_resident_map_count -= this->HostMapCount(item->paddr, item->size);
|
||||
ASSERT(m_resident_map_count >= 0);
|
||||
ASSERT(--m_resident_map_count >= 0);
|
||||
m_resident_mappings.erase(m_resident_mappings.iterator_to(*item));
|
||||
}
|
||||
|
||||
@@ -194,7 +191,7 @@ bool HeapTracker::DeferredMapSeparateHeap(size_t virtual_offset) {
|
||||
|
||||
// This map is now resident.
|
||||
it->is_resident = true;
|
||||
m_resident_map_count += this->HostMapCount(it->paddr, it->size);
|
||||
m_resident_map_count++;
|
||||
m_resident_mappings.insert(*it);
|
||||
}
|
||||
|
||||
@@ -216,17 +213,17 @@ void HeapTracker::RebuildSeparateHeapAddressSpace() {
|
||||
// Despite being worse in theory, this has proven to be better in practice than more
|
||||
// regularly dumping a smaller amount, because it significantly reduces average case
|
||||
// lock contention.
|
||||
s64 const desired_count = (std::min)(m_resident_map_count, m_max_resident_map_count) / 2;
|
||||
std::size_t const desired_count = (std::min)(m_resident_map_count, m_max_resident_map_count) / 2;
|
||||
std::size_t const evict_count = m_resident_map_count - desired_count;
|
||||
auto it = m_resident_mappings.begin();
|
||||
|
||||
while (m_resident_map_count > desired_count && it != m_resident_mappings.end()) {
|
||||
for (size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) {
|
||||
// Unmark and unmap.
|
||||
it->is_resident = false;
|
||||
m_buffer.Unmap(it->vaddr, it->size, false);
|
||||
|
||||
// Advance.
|
||||
m_resident_map_count -= this->HostMapCount(it->paddr, it->size);
|
||||
ASSERT(m_resident_map_count >= 0);
|
||||
ASSERT(--m_resident_map_count >= 0);
|
||||
it = m_resident_mappings.erase(it);
|
||||
}
|
||||
}
|
||||
@@ -248,7 +245,6 @@ void HeapTracker::SplitHeapMapLocked(VAddr offset) {
|
||||
// Cache the original values.
|
||||
auto* const left = std::addressof(*it);
|
||||
const size_t orig_size = left->size;
|
||||
const s64 orig_host_map_count = this->HostMapCount(left->paddr, orig_size);
|
||||
|
||||
// Adjust the left map.
|
||||
const size_t left_size = offset - left->vaddr;
|
||||
@@ -270,20 +266,11 @@ void HeapTracker::SplitHeapMapLocked(VAddr offset) {
|
||||
|
||||
// If resident, also insert into resident map.
|
||||
if (right->is_resident) {
|
||||
m_resident_map_count += this->HostMapCount(left->paddr, left->size) +
|
||||
this->HostMapCount(right->paddr, right->size) -
|
||||
orig_host_map_count;
|
||||
m_resident_map_count++;
|
||||
m_resident_mappings.insert(*right);
|
||||
}
|
||||
}
|
||||
|
||||
s64 HeapTracker::HostMapCount(PAddr paddr, size_t size) const {
|
||||
if (!m_has_hardware_buffer_backing) {
|
||||
return size != 0 ? 1 : 0;
|
||||
}
|
||||
return static_cast<s64>(m_buffer.BackingMapCount(paddr, size));
|
||||
}
|
||||
|
||||
HeapTracker::AddrTree::iterator HeapTracker::GetNearestHeapMapLocked(VAddr offset) {
|
||||
const SeparateHeapMap key{
|
||||
.vaddr = offset,
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -85,13 +82,10 @@ private:
|
||||
|
||||
AddrTree::iterator GetNearestHeapMapLocked(VAddr offset);
|
||||
|
||||
s64 HostMapCount(PAddr paddr, size_t size) const;
|
||||
|
||||
void RebuildSeparateHeapAddressSpace();
|
||||
|
||||
private:
|
||||
Common::HostMemory& m_buffer;
|
||||
const bool m_has_hardware_buffer_backing;
|
||||
const s64 m_max_resident_map_count;
|
||||
|
||||
std::shared_mutex m_rebuild_lock{};
|
||||
|
||||
+6
-368
@@ -51,45 +51,14 @@
|
||||
|
||||
#endif // ^^^ POSIX ^^^
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/free_region_manager.h"
|
||||
#include "common/host_memory.h"
|
||||
#include "common/logging.h"
|
||||
#include "common/memory_detect.h"
|
||||
#include "common/settings.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <dlfcn.h>
|
||||
#include <android/hardware_buffer.h>
|
||||
|
||||
namespace {
|
||||
|
||||
struct NativeHandle {
|
||||
int version;
|
||||
int numFds;
|
||||
int numInts;
|
||||
int data[1];
|
||||
};
|
||||
|
||||
using PFN_AHardwareBuffer_getNativeHandle = const NativeHandle* (*)(const AHardwareBuffer*);
|
||||
|
||||
PFN_AHardwareBuffer_getNativeHandle ResolveGetNativeHandle() {
|
||||
void* const lib = dlopen("libnativewindow.so", RTLD_NOW);
|
||||
if (lib == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<PFN_AHardwareBuffer_getNativeHandle>(
|
||||
dlsym(lib, "AHardwareBuffer_getNativeHandle"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__) && __ANDROID_API__ < 30
|
||||
#include <sys/syscall.h>
|
||||
@@ -106,12 +75,6 @@ namespace Common {
|
||||
[[maybe_unused]] constexpr size_t PageAlignment = 0x1000;
|
||||
[[maybe_unused]] constexpr size_t HugePageSize = 0x200000;
|
||||
|
||||
static std::atomic<u64> committed_backing_size{};
|
||||
|
||||
u64 GetCommittedBackingSize() noexcept {
|
||||
return committed_backing_size.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// Manually imported for MinGW compatibility
|
||||
@@ -160,7 +123,7 @@ static void GetFuncAddress(Common::DynamicLibrary& dll, const char* name, T& pfn
|
||||
|
||||
class HostMemory::Impl {
|
||||
public:
|
||||
explicit Impl(size_t backing_size_, size_t virtual_size_, size_t)
|
||||
explicit Impl(size_t backing_size_, size_t virtual_size_)
|
||||
: backing_size{backing_size_}
|
||||
, virtual_size{virtual_size_}
|
||||
, process{GetCurrentProcess()}
|
||||
@@ -266,10 +229,6 @@ public:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
bool IsBackingShared() const noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
const size_t backing_size; ///< Size of the backing memory in bytes
|
||||
const size_t virtual_size; ///< Size of the virtual address placeholder in bytes
|
||||
|
||||
@@ -542,10 +501,9 @@ static int shm_open_anon(int flags, mode_t mode) {
|
||||
|
||||
class HostMemory::Impl {
|
||||
public:
|
||||
explicit Impl(size_t backing_size_, size_t virtual_size_, size_t preferred_offset_)
|
||||
explicit Impl(size_t backing_size_, size_t virtual_size_)
|
||||
: backing_size{backing_size_}
|
||||
, virtual_size{virtual_size_}
|
||||
, preferred_offset{preferred_offset_}
|
||||
{}
|
||||
|
||||
bool Init() {
|
||||
@@ -585,15 +543,10 @@ public:
|
||||
LOG_WARNING(Common_Memory, "Using private mappings instead of shared ones");
|
||||
backing_base = static_cast<u8*>(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
|
||||
if (fd > 0) {
|
||||
fd = -1;
|
||||
close(fd);
|
||||
}
|
||||
fd = -1;
|
||||
} else {
|
||||
#ifdef __ANDROID__
|
||||
if (InitAhbBacking()) {
|
||||
return InitVirtual();
|
||||
}
|
||||
#endif
|
||||
backing_base = static_cast<u8*>(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
|
||||
}
|
||||
if (backing_base == MAP_FAILED) {
|
||||
@@ -601,10 +554,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
return InitVirtual();
|
||||
}
|
||||
|
||||
bool InitVirtual() {
|
||||
// Virtual memory initialization
|
||||
virtual_base = virtual_map_base = static_cast<u8*>(ChooseVirtualBase(virtual_size));
|
||||
if (virtual_base == MAP_FAILED) {
|
||||
LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno));
|
||||
@@ -617,242 +567,6 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
static AHardwareBuffer_Desc MakeBlobDesc(size_t len) {
|
||||
return AHardwareBuffer_Desc{
|
||||
.width = static_cast<u32>(len),
|
||||
.height = 1,
|
||||
.layers = 1,
|
||||
.format = AHARDWAREBUFFER_FORMAT_BLOB,
|
||||
.usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
|
||||
AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
|
||||
AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER,
|
||||
.stride = 0,
|
||||
.rfu0 = 0,
|
||||
.rfu1 = 0,
|
||||
};
|
||||
}
|
||||
|
||||
static bool ProbeAhbBacking(PFN_AHardwareBuffer_getNativeHandle get_native_handle) {
|
||||
const AHardwareBuffer_Desc desc = MakeBlobDesc(PageAlignment * 2);
|
||||
AHardwareBuffer* buffer{};
|
||||
if (AHardwareBuffer_allocate(&desc, &buffer) != 0 || buffer == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const NativeHandle* const handle = get_native_handle(buffer);
|
||||
if (handle == nullptr || handle->numFds < 1) {
|
||||
AHardwareBuffer_release(buffer);
|
||||
return false;
|
||||
}
|
||||
const int probe_fd = handle->data[0];
|
||||
bool ok = true;
|
||||
const auto try_map = [&](int prot, off_t offset, const char* what) {
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
void* const ptr = mmap(nullptr, PageAlignment, prot, MAP_SHARED, probe_fd, offset);
|
||||
if (ptr == MAP_FAILED) {
|
||||
ok = false;
|
||||
return;
|
||||
}
|
||||
munmap(ptr, PageAlignment);
|
||||
};
|
||||
try_map(PROT_READ | PROT_WRITE, 0, "shared mappings");
|
||||
try_map(PROT_READ | PROT_WRITE, static_cast<off_t>(PageAlignment), "mappings at an offset");
|
||||
#ifdef ARCHITECTURE_arm64
|
||||
try_map(PROT_READ | PROT_EXEC, 0, "executable mappings");
|
||||
#endif
|
||||
AHardwareBuffer_release(buffer);
|
||||
return ok;
|
||||
}
|
||||
|
||||
size_t ComputeAhbBudget(size_t window_size) const {
|
||||
const u64 total_physical = Common::GetMemInfo().TotalPhysicalMemory;
|
||||
constexpr u64 BaselineFootprint = 6ULL << 30;
|
||||
if (total_physical <= BaselineFootprint) {
|
||||
return 0;
|
||||
}
|
||||
const u64 max_map_count = Common::GetMaxMapCount();
|
||||
constexpr u64 ReservedMaps = 24576;
|
||||
if (max_map_count == 0 || max_map_count <= ReservedMaps) {
|
||||
return 0;
|
||||
}
|
||||
u64 budget = (total_physical - BaselineFootprint) / 2;
|
||||
constexpr u64 MapSlotsPerWindow = 4096;
|
||||
const u64 affordable_windows = (max_map_count - ReservedMaps) / MapSlotsPerWindow;
|
||||
budget = (std::min)(budget, affordable_windows * window_size);
|
||||
const u64 available = Common::GetAvailablePhysicalMemory();
|
||||
if (available != 0) {
|
||||
budget = (std::min)(budget, available / 2);
|
||||
}
|
||||
budget = (std::min)(budget, static_cast<u64>(backing_size));
|
||||
budget = Common::AlignDown(budget, window_size);
|
||||
constexpr u64 MinimumBudget = 256ULL << 20;
|
||||
if (budget < MinimumBudget) {
|
||||
return 0;
|
||||
}
|
||||
return static_cast<size_t>(budget);
|
||||
}
|
||||
|
||||
bool InitAhbBacking() {
|
||||
if (!Settings::values.use_unified_memory.GetValue()) {
|
||||
return false;
|
||||
}
|
||||
static const PFN_AHardwareBuffer_getNativeHandle get_native_handle =
|
||||
ResolveGetNativeHandle();
|
||||
if (get_native_handle == nullptr) {
|
||||
return false;
|
||||
}
|
||||
constexpr size_t window_size = 256ULL << 20;
|
||||
const size_t budget = ComputeAhbBudget(window_size);
|
||||
if (budget == 0) {
|
||||
return false;
|
||||
}
|
||||
if (!ProbeAhbBacking(get_native_handle)) {
|
||||
return false;
|
||||
}
|
||||
const size_t aligned_backing = Common::AlignDown(backing_size, window_size);
|
||||
const size_t max_windows = (std::min)(budget, aligned_backing) / window_size;
|
||||
|
||||
std::vector<AHardwareBuffer*> buffers;
|
||||
std::vector<int> buffer_fds;
|
||||
const auto cleanup = [&] {
|
||||
for (AHardwareBuffer* buffer : buffers) {
|
||||
AHardwareBuffer_release(buffer);
|
||||
}
|
||||
buffers.clear();
|
||||
buffer_fds.clear();
|
||||
};
|
||||
for (size_t i = 0; i < max_windows; ++i) {
|
||||
const AHardwareBuffer_Desc desc = MakeBlobDesc(window_size);
|
||||
AHardwareBuffer* buffer{};
|
||||
if (AHardwareBuffer_allocate(&desc, &buffer) != 0 || buffer == nullptr) {
|
||||
break;
|
||||
}
|
||||
const NativeHandle* const handle = get_native_handle(buffer);
|
||||
if (handle == nullptr || handle->numFds < 1) {
|
||||
AHardwareBuffer_release(buffer);
|
||||
break;
|
||||
}
|
||||
const int buffer_fd = handle->data[0];
|
||||
const off_t buffer_len = lseek(buffer_fd, 0, SEEK_END);
|
||||
if (buffer_len < static_cast<off_t>(window_size)) {
|
||||
AHardwareBuffer_release(buffer);
|
||||
break;
|
||||
}
|
||||
buffers.push_back(buffer);
|
||||
buffer_fds.push_back(buffer_fd);
|
||||
}
|
||||
const size_t num_windows = buffers.size();
|
||||
if (num_windows == 0) {
|
||||
return false;
|
||||
}
|
||||
const size_t region_size = num_windows * window_size;
|
||||
const size_t region_base = Common::AlignDown(
|
||||
(std::min)(preferred_offset, aligned_backing - region_size), window_size);
|
||||
u8* const base = static_cast<u8*>(mmap(nullptr, backing_size, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0));
|
||||
if (base == MAP_FAILED) {
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
const auto map_over_reservation = [&](size_t offset, size_t len, int map_fd,
|
||||
off_t map_offset) {
|
||||
if (len == 0) {
|
||||
return true;
|
||||
}
|
||||
if (mmap(base + offset, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, map_fd,
|
||||
map_offset) == MAP_FAILED) {
|
||||
munmap(base, backing_size);
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
if (!map_over_reservation(0, region_base, fd, 0)) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < num_windows; ++i) {
|
||||
if (!map_over_reservation(region_base + i * window_size, window_size, buffer_fds[i],
|
||||
0)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const size_t tail_offset = region_base + region_size;
|
||||
if (!map_over_reservation(tail_offset, backing_size - tail_offset, fd,
|
||||
static_cast<off_t>(tail_offset))) {
|
||||
return false;
|
||||
}
|
||||
backing_base = base;
|
||||
ahb_windows = std::move(buffers);
|
||||
ahb_fds = std::move(buffer_fds);
|
||||
ahb_window_size = window_size;
|
||||
ahb_base = region_base;
|
||||
ahb_bytes = region_size;
|
||||
committed_backing_size.store(region_size, std::memory_order_relaxed);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MapBackingRange(size_t virtual_offset, size_t host_offset, size_t length, int prot_flags) {
|
||||
while (length > 0) {
|
||||
int map_fd = fd;
|
||||
off_t map_offset = static_cast<off_t>(host_offset);
|
||||
size_t chunk = length;
|
||||
if (host_offset < ahb_base) {
|
||||
chunk = (std::min)(chunk, ahb_base - host_offset);
|
||||
} else if (host_offset < ahb_base + ahb_bytes) {
|
||||
const size_t relative = host_offset - ahb_base;
|
||||
const size_t window = relative / ahb_window_size;
|
||||
const size_t local = relative % ahb_window_size;
|
||||
map_fd = ahb_fds[window];
|
||||
map_offset = static_cast<off_t>(local);
|
||||
chunk = (std::min)(chunk, ahb_window_size - local);
|
||||
}
|
||||
void* const ret = mmap(virtual_base + virtual_offset, chunk, prot_flags,
|
||||
MAP_SHARED | MAP_FIXED, map_fd, map_offset);
|
||||
ASSERT_MSG(ret != MAP_FAILED, "mmap: {}", strerror(errno));
|
||||
virtual_offset += chunk;
|
||||
host_offset += chunk;
|
||||
length -= chunk;
|
||||
}
|
||||
}
|
||||
|
||||
size_t BackingMapCount(size_t host_offset, size_t length) const noexcept {
|
||||
if (length == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (ahb_bytes == 0) {
|
||||
return 1;
|
||||
}
|
||||
size_t count = 0;
|
||||
while (length > 0) {
|
||||
size_t chunk = length;
|
||||
if (host_offset < ahb_base) {
|
||||
chunk = (std::min)(chunk, ahb_base - host_offset);
|
||||
} else if (host_offset < ahb_base + ahb_bytes) {
|
||||
const size_t local = (host_offset - ahb_base) % ahb_window_size;
|
||||
chunk = (std::min)(chunk, ahb_window_size - local);
|
||||
}
|
||||
host_offset += chunk;
|
||||
length -= chunk;
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
std::span<AHardwareBuffer* const> AhbWindows() const noexcept {
|
||||
return ahb_windows;
|
||||
}
|
||||
|
||||
size_t AhbWindowSize() const noexcept {
|
||||
return ahb_bytes != 0 ? ahb_window_size : 0;
|
||||
}
|
||||
|
||||
size_t AhbBase() const noexcept {
|
||||
return ahb_base;
|
||||
}
|
||||
#endif
|
||||
|
||||
~Impl() {
|
||||
Release();
|
||||
}
|
||||
@@ -873,12 +587,6 @@ public:
|
||||
#ifdef ARCHITECTURE_arm64
|
||||
if (True(perms & MemoryPermission::Execute))
|
||||
prot_flags |= PROT_EXEC;
|
||||
#endif
|
||||
#ifdef __ANDROID__
|
||||
if (ahb_bytes != 0) {
|
||||
MapBackingRange(virtual_offset, host_offset, length, prot_flags);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
int flags = (fd >= 0 ? MAP_SHARED : MAP_PRIVATE) | MAP_FIXED;
|
||||
void* ret = mmap(virtual_base + virtual_offset, length, prot_flags, flags, fd, host_offset);
|
||||
@@ -924,18 +632,8 @@ public:
|
||||
virtual_base = nullptr;
|
||||
}
|
||||
|
||||
bool IsBackingShared() const noexcept {
|
||||
#ifdef __ANDROID__
|
||||
if (ahb_bytes != 0) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return fd >= 0;
|
||||
}
|
||||
|
||||
const size_t backing_size; ///< Size of the backing memory in bytes
|
||||
const size_t virtual_size; ///< Size of the virtual address placeholder in bytes
|
||||
const size_t preferred_offset;
|
||||
|
||||
u8* backing_base{reinterpret_cast<u8*>(MAP_FAILED)};
|
||||
u8* virtual_base{reinterpret_cast<u8*>(MAP_FAILED)};
|
||||
@@ -958,18 +656,6 @@ private:
|
||||
int ret = close(fd);
|
||||
ASSERT_MSG(ret == 0, "close failed: {}", strerror(errno));
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
for (AHardwareBuffer* buffer : ahb_windows) {
|
||||
AHardwareBuffer_release(buffer);
|
||||
}
|
||||
ahb_windows.clear();
|
||||
ahb_fds.clear();
|
||||
if (ahb_bytes != 0) {
|
||||
committed_backing_size.store(0, std::memory_order_relaxed);
|
||||
ahb_bytes = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void AdjustMap(size_t* virtual_offset, size_t* length) {
|
||||
@@ -995,19 +681,11 @@ private:
|
||||
|
||||
int fd{-1}; // memfd file descriptor, -1 is the error value of memfd_create
|
||||
FreeRegionManager free_manager{};
|
||||
|
||||
#ifdef __ANDROID__
|
||||
std::vector<AHardwareBuffer*> ahb_windows;
|
||||
std::vector<int> ahb_fds;
|
||||
size_t ahb_window_size{};
|
||||
size_t ahb_base{};
|
||||
size_t ahb_bytes{};
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // ^^^ POSIX ^^^
|
||||
|
||||
HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_, size_t preferred_offset_)
|
||||
HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_)
|
||||
: backing_size(backing_size_)
|
||||
, virtual_size(virtual_size_)
|
||||
{
|
||||
@@ -1019,7 +697,7 @@ HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_, size_t prefer
|
||||
#else
|
||||
// Try to allocate a fastmem arena.
|
||||
// The implementation will fail with std::bad_alloc on errors.
|
||||
impl = std::make_unique<HostMemory::Impl>(AlignUp(backing_size, PageAlignment), AlignUp(virtual_size, PageAlignment) + HugePageSize, preferred_offset_);
|
||||
impl = std::make_unique<HostMemory::Impl>(AlignUp(backing_size, PageAlignment), AlignUp(virtual_size, PageAlignment) + HugePageSize);
|
||||
if (impl->Init()) {
|
||||
backing_base = impl->backing_base;
|
||||
virtual_base = impl->virtual_base;
|
||||
@@ -1089,46 +767,6 @@ void HostMemory::ClearBackingRegion(size_t physical_offset, size_t length, u32 f
|
||||
std::memset(backing_base + physical_offset, fill_value, length);
|
||||
}
|
||||
|
||||
std::span<AHardwareBuffer* const> HostMemory::BackingHardwareBuffers() const noexcept {
|
||||
#ifdef __ANDROID__
|
||||
return impl ? impl->AhbWindows() : std::span<AHardwareBuffer* const>{};
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t HostMemory::BackingMapCount(size_t host_offset, size_t length) const noexcept {
|
||||
#ifdef __ANDROID__
|
||||
return impl ? impl->BackingMapCount(host_offset, length) : (length != 0 ? 1 : 0);
|
||||
#else
|
||||
return length != 0 ? 1 : 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t HostMemory::BackingHardwareBufferWindowSize() const noexcept {
|
||||
#ifdef __ANDROID__
|
||||
return impl ? impl->AhbWindowSize() : 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool HostMemory::IsBackingShared() const noexcept {
|
||||
#if defined(__OPENORBIS__) || defined(__managarm__)
|
||||
return false;
|
||||
#else
|
||||
return impl && impl->IsBackingShared();
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t HostMemory::BackingHardwareBufferBase() const noexcept {
|
||||
#ifdef __ANDROID__
|
||||
return impl ? impl->AhbBase() : 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void HostMemory::EnableDirectMappedAddress() {
|
||||
#if !(defined(__OPENORBIS__) || defined(__managarm__))
|
||||
if (impl) {
|
||||
|
||||
@@ -8,17 +8,12 @@
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/virtual_buffer.h"
|
||||
|
||||
struct AHardwareBuffer;
|
||||
|
||||
namespace Common {
|
||||
|
||||
[[nodiscard]] u64 GetCommittedBackingSize() noexcept;
|
||||
|
||||
enum class MemoryPermission : u32 {
|
||||
Read = 1 << 0,
|
||||
Write = 1 << 1,
|
||||
@@ -33,7 +28,7 @@ DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission)
|
||||
*/
|
||||
class HostMemory {
|
||||
public:
|
||||
explicit HostMemory(size_t backing_size_, size_t virtual_size_, size_t preferred_offset_ = 0);
|
||||
explicit HostMemory(size_t backing_size_, size_t virtual_size_);
|
||||
~HostMemory();
|
||||
|
||||
/**
|
||||
@@ -67,20 +62,6 @@ public:
|
||||
return backing_base;
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t BackingSize() const noexcept {
|
||||
return backing_size;
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t BackingMapCount(size_t host_offset, size_t length) const noexcept;
|
||||
|
||||
[[nodiscard]] std::span<AHardwareBuffer* const> BackingHardwareBuffers() const noexcept;
|
||||
|
||||
[[nodiscard]] size_t BackingHardwareBufferWindowSize() const noexcept;
|
||||
|
||||
[[nodiscard]] size_t BackingHardwareBufferBase() const noexcept;
|
||||
|
||||
[[nodiscard]] bool IsBackingShared() const noexcept;
|
||||
|
||||
[[nodiscard]] u8* VirtualBasePointer() noexcept {
|
||||
return virtual_base;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -20,10 +17,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "common/memory_detect.h"
|
||||
|
||||
namespace Common {
|
||||
@@ -76,55 +69,4 @@ const MemoryInfo& GetMemInfo() {
|
||||
return mem_info;
|
||||
}
|
||||
|
||||
u64 GetAvailablePhysicalMemory() {
|
||||
#ifdef _WIN32
|
||||
MEMORYSTATUSEX memorystatus;
|
||||
memorystatus.dwLength = sizeof(memorystatus);
|
||||
if (GlobalMemoryStatusEx(&memorystatus)) {
|
||||
return memorystatus.ullAvailPhys;
|
||||
}
|
||||
return 0;
|
||||
#elif defined(__linux__)
|
||||
if (std::FILE* const file = std::fopen("/proc/meminfo", "re")) {
|
||||
char line[256];
|
||||
u64 available = 0;
|
||||
while (std::fgets(line, sizeof(line), file) != nullptr) {
|
||||
if (std::strncmp(line, "MemAvailable:", 13) == 0) {
|
||||
available = std::strtoull(line + 13, nullptr, 10) * 1024ULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::fclose(file);
|
||||
if (available != 0) {
|
||||
return available;
|
||||
}
|
||||
}
|
||||
struct sysinfo info;
|
||||
if (sysinfo(&info) == 0) {
|
||||
const u64 unit = info.mem_unit != 0 ? info.mem_unit : 1ULL;
|
||||
return (static_cast<u64>(info.freeram) + static_cast<u64>(info.bufferram)) * unit;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
u64 GetMaxMapCount() {
|
||||
#ifdef __linux__
|
||||
if (std::FILE* const file = std::fopen("/proc/sys/vm/max_map_count", "re")) {
|
||||
char line[32];
|
||||
u64 count = 0;
|
||||
if (std::fgets(line, sizeof(line), file) != nullptr) {
|
||||
count = std::strtoull(line, nullptr, 10);
|
||||
}
|
||||
std::fclose(file);
|
||||
return count;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -21,8 +18,4 @@ struct MemoryInfo {
|
||||
*/
|
||||
[[nodiscard]] const MemoryInfo& GetMemInfo();
|
||||
|
||||
[[nodiscard]] u64 GetAvailablePhysicalMemory();
|
||||
|
||||
[[nodiscard]] u64 GetMaxMapCount();
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -587,9 +587,6 @@ struct Values {
|
||||
SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
|
||||
Category::RendererHacks};
|
||||
|
||||
SwitchableSetting<bool> use_unified_memory{linkage, false, "use_unified_memory",
|
||||
Category::RendererHacks};
|
||||
|
||||
SwitchableSetting<GpuUnswizzleSize> gpu_unswizzle_texture_size{linkage,
|
||||
GpuUnswizzleSize::Large,
|
||||
"gpu_unswizzle_texture_size",
|
||||
@@ -705,7 +702,15 @@ struct Values {
|
||||
|
||||
// Controls
|
||||
InputSetting<std::array<PlayerInput, 10>> players;
|
||||
|
||||
Setting<bool> disable_wgi_xinput{
|
||||
linkage, false, "disable_wgi_xinput", Category::Controls, Specialization::Default,
|
||||
// Only read/write disable_wgi_xinput on Windows platforms
|
||||
#ifdef _WIN32
|
||||
true
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
};
|
||||
Setting<bool> enable_raw_input{
|
||||
linkage, false, "enable_raw_input", Category::Controls, Specialization::Default,
|
||||
// Only read/write enable_raw_input on Windows platforms
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Network {
|
||||
|
||||
/// Address families
|
||||
enum class Domain : u8 {
|
||||
Unspecified, ///< Represents 0, used in getaddrinfo hints
|
||||
INET, ///< Address family for IPv4
|
||||
};
|
||||
|
||||
/// Socket types
|
||||
enum class Type {
|
||||
Unspecified, ///< Represents 0, used in getaddrinfo hints
|
||||
STREAM,
|
||||
DGRAM,
|
||||
RAW,
|
||||
SEQPACKET,
|
||||
};
|
||||
|
||||
/// Protocol values for sockets
|
||||
enum class Protocol : u8 {
|
||||
Unspecified, ///< Represents 0, usable in various places
|
||||
IP,
|
||||
ICMP,
|
||||
TCP,
|
||||
UDP,
|
||||
IPV6,
|
||||
RAW,
|
||||
IGMP,
|
||||
GGP,
|
||||
IPV4,
|
||||
ST,
|
||||
EGP,
|
||||
PIGP,
|
||||
RCCMON,
|
||||
NVPII,
|
||||
PUP,
|
||||
ARGUS,
|
||||
EMCON,
|
||||
XNET,
|
||||
CHAOS,
|
||||
MUX,
|
||||
MEAS,
|
||||
HMP,
|
||||
PRM,
|
||||
IDP,
|
||||
TRUNK1,
|
||||
TRUNK2,
|
||||
LEAF1,
|
||||
LEAF2,
|
||||
RDP,
|
||||
IRTP,
|
||||
TP,
|
||||
BLT,
|
||||
NSP,
|
||||
INP,
|
||||
DCCP,
|
||||
//TODO: 3PC,
|
||||
IDPR,
|
||||
XTP,
|
||||
DDP,
|
||||
CMTP,
|
||||
TPXX,
|
||||
IL,
|
||||
SDRP,
|
||||
ROUTING,
|
||||
FRAGMENT,
|
||||
IDRP,
|
||||
RSVP,
|
||||
GRE,
|
||||
MHRP,
|
||||
BHA,
|
||||
ESP,
|
||||
AH,
|
||||
INLSP,
|
||||
SWIPE,
|
||||
NHRP,
|
||||
MOBILE,
|
||||
TLSP,
|
||||
SKIP,
|
||||
ICMPV6,
|
||||
NONE,
|
||||
DSTOPTS,
|
||||
AHIP,
|
||||
CFTP,
|
||||
HELLO,
|
||||
SATEXPAK,
|
||||
KRYPTOLAN,
|
||||
RVD,
|
||||
IPPC,
|
||||
ADFS,
|
||||
SATMON,
|
||||
VISA,
|
||||
IPCV,
|
||||
CPNX,
|
||||
CPHB,
|
||||
WSN,
|
||||
PVP,
|
||||
BRSATMON,
|
||||
ND,
|
||||
WBMON,
|
||||
WBEXPAK,
|
||||
EON,
|
||||
VMTP,
|
||||
SVMTP,
|
||||
VINES,
|
||||
TTP,
|
||||
IGP,
|
||||
DGP,
|
||||
TCF,
|
||||
IGRP,
|
||||
OSPFIGP,
|
||||
SRPC,
|
||||
LARP,
|
||||
MTP,
|
||||
AX25,
|
||||
IPEIP,
|
||||
MICP,
|
||||
SCCSP,
|
||||
ETHERIP,
|
||||
ENCAP,
|
||||
APES,
|
||||
GMTP,
|
||||
IPCOMP,
|
||||
SCTP,
|
||||
MH,
|
||||
UDPLITE,
|
||||
HIP,
|
||||
SHIM6,
|
||||
PIM,
|
||||
CARP,
|
||||
PGM,
|
||||
MPLS,
|
||||
PFSYNC
|
||||
};
|
||||
|
||||
/// Shutdown mode
|
||||
enum class ShutdownHow {
|
||||
RD,
|
||||
WR,
|
||||
RDWR,
|
||||
};
|
||||
|
||||
/// Array of IPv4 address
|
||||
using IPv4Address = std::array<u8, 4>;
|
||||
|
||||
/// Cross-platform sockaddr structure
|
||||
struct SockAddrIn {
|
||||
Domain family;
|
||||
IPv4Address ip;
|
||||
u16 portno;
|
||||
};
|
||||
|
||||
constexpr u32 FLAG_MSG_PEEK = 0x2;
|
||||
constexpr u32 FLAG_MSG_DONTWAIT = 0x80;
|
||||
constexpr u32 FLAG_O_NONBLOCK = 0x800;
|
||||
|
||||
/// Cross-platform addrinfo structure
|
||||
struct AddrInfo {
|
||||
Domain family;
|
||||
Type socket_type;
|
||||
Protocol protocol;
|
||||
SockAddrIn addr;
|
||||
std::optional<std::string> canon_name;
|
||||
};
|
||||
|
||||
} // namespace Network
|
||||
@@ -1133,6 +1133,9 @@ add_library(core STATIC
|
||||
internal_network/network_interface.h
|
||||
internal_network/socket_proxy.cpp
|
||||
internal_network/socket_proxy.h
|
||||
internal_network/socket_icmp.cpp
|
||||
internal_network/socket_icmp.h
|
||||
internal_network/socket_types.h
|
||||
internal_network/sockets.h
|
||||
internal_network/wifi_scanner.h
|
||||
launch_timestamp_cache.cpp
|
||||
@@ -1173,7 +1176,7 @@ add_library(core STATIC
|
||||
|
||||
if (ENABLE_WIFI_SCAN)
|
||||
target_sources(core PRIVATE internal_network/wifi_scanner.cpp)
|
||||
if (PLATFORM_LINUX)
|
||||
if (LINUX)
|
||||
target_link_libraries(core PRIVATE iw)
|
||||
endif()
|
||||
else()
|
||||
@@ -1199,7 +1202,7 @@ if (MSVC)
|
||||
)
|
||||
else()
|
||||
target_compile_options(core PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=conversion>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wconversion>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-sign-conversion>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-cast-function-type>
|
||||
$<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>)
|
||||
|
||||
+1
-5
@@ -119,7 +119,6 @@ struct System::Impl {
|
||||
|
||||
is_multicore = Settings::values.use_multi_core.GetValue();
|
||||
extended_memory_layout = Settings::values.memory_layout_mode.GetValue() != Settings::MemoryLayout::Memory_4Gb;
|
||||
unified_memory = Settings::values.use_unified_memory.GetValue();
|
||||
|
||||
core_timing.SetMulticore(is_multicore);
|
||||
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
|
||||
@@ -147,8 +146,7 @@ struct System::Impl {
|
||||
!device_memory.has_value() ||
|
||||
is_multicore != Settings::values.use_multi_core.GetValue() ||
|
||||
extended_memory_layout != (Settings::values.memory_layout_mode.GetValue() !=
|
||||
Settings::MemoryLayout::Memory_4Gb) ||
|
||||
unified_memory != Settings::values.use_unified_memory.GetValue();
|
||||
Settings::MemoryLayout::Memory_4Gb);
|
||||
|
||||
if (!must_reinitialize) {
|
||||
return;
|
||||
@@ -159,7 +157,6 @@ struct System::Impl {
|
||||
is_multicore = Settings::values.use_multi_core.GetValue();
|
||||
extended_memory_layout =
|
||||
Settings::values.memory_layout_mode.GetValue() != Settings::MemoryLayout::Memory_4Gb;
|
||||
unified_memory = Settings::values.use_unified_memory.GetValue();
|
||||
|
||||
Initialize(system);
|
||||
}
|
||||
@@ -506,7 +503,6 @@ struct System::Impl {
|
||||
std::atomic_bool is_powered_on{};
|
||||
bool is_multicore : 1 = false;
|
||||
bool extended_memory_layout : 1 = false;
|
||||
bool unified_memory : 1 = false;
|
||||
bool exit_locked : 1 = false;
|
||||
bool exit_requested : 1 = false;
|
||||
bool nvdec_active : 1 = false;
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -15,18 +12,9 @@ constexpr size_t VirtualReserveSize = 1ULL << 38;
|
||||
constexpr size_t VirtualReserveSize = 1ULL << 39;
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
size_t ApplicationPoolOffset() {
|
||||
using Init = Kernel::Board::Nintendo::Nx::KSystemControl::Init;
|
||||
const size_t dram_size = Init::GetIntendedMemorySize();
|
||||
const size_t application_pool_size = Init::GetApplicationPoolSize();
|
||||
return dram_size > application_pool_size ? dram_size - application_pool_size : 0;
|
||||
}
|
||||
}
|
||||
|
||||
DeviceMemory::DeviceMemory()
|
||||
: buffer{Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize(),
|
||||
VirtualReserveSize, ApplicationPoolOffset()} {}
|
||||
VirtualReserveSize} {}
|
||||
|
||||
DeviceMemory::~DeviceMemory() = default;
|
||||
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
#include "common/scratch_buffer.h"
|
||||
#include "common/virtual_buffer.h"
|
||||
|
||||
struct AHardwareBuffer;
|
||||
|
||||
namespace Core {
|
||||
|
||||
constexpr size_t DEVICE_PAGEBITS = 12ULL;
|
||||
@@ -97,34 +95,6 @@ public:
|
||||
ApplyOpOnPAddr(address, buffer, operation);
|
||||
}
|
||||
|
||||
u8* GetPhysicalBase() noexcept {
|
||||
return reinterpret_cast<u8*>(physical_base);
|
||||
}
|
||||
|
||||
const u8* GetPhysicalBase() const noexcept {
|
||||
return reinterpret_cast<const u8*>(physical_base);
|
||||
}
|
||||
|
||||
size_t GetPhysicalSize() const noexcept {
|
||||
return physical_size;
|
||||
}
|
||||
|
||||
std::span<AHardwareBuffer* const> GetBackingHardwareBuffers() const noexcept {
|
||||
return ahb_windows;
|
||||
}
|
||||
|
||||
size_t GetBackingHardwareBufferWindowSize() const noexcept {
|
||||
return ahb_window_size;
|
||||
}
|
||||
|
||||
size_t GetBackingHardwareBufferBase() const noexcept {
|
||||
return ahb_base;
|
||||
}
|
||||
|
||||
bool IsBackingShared() const noexcept {
|
||||
return backing_is_shared;
|
||||
}
|
||||
|
||||
PAddr GetPhysicalRawAddressFromDAddr(DAddr address) const {
|
||||
PAddr subbits = PAddr(address & page_mask);
|
||||
auto paddr = tracked_entries[(address >> page_bits)].compressed_physical_ptr;
|
||||
@@ -201,11 +171,6 @@ private:
|
||||
std::unique_ptr<DeviceMemoryManagerAllocator<Traits>> impl;
|
||||
|
||||
const uintptr_t physical_base;
|
||||
const size_t physical_size;
|
||||
const std::span<AHardwareBuffer* const> ahb_windows;
|
||||
const size_t ahb_window_size;
|
||||
const size_t ahb_base;
|
||||
const bool backing_is_shared;
|
||||
DeviceInterface* device_inter;
|
||||
|
||||
struct TrackedEntry {
|
||||
|
||||
@@ -171,11 +171,6 @@ struct DeviceMemoryManagerAllocator {
|
||||
template <typename Traits>
|
||||
DeviceMemoryManager<Traits>::DeviceMemoryManager(const DeviceMemory& device_memory_)
|
||||
: physical_base{uintptr_t(device_memory_.buffer.BackingBasePointer())}
|
||||
, physical_size{device_memory_.buffer.BackingSize()}
|
||||
, ahb_windows{device_memory_.buffer.BackingHardwareBuffers()}
|
||||
, ahb_window_size{device_memory_.buffer.BackingHardwareBufferWindowSize()}
|
||||
, ahb_base{device_memory_.buffer.BackingHardwareBufferBase()}
|
||||
, backing_is_shared{device_memory_.buffer.IsBackingShared()}
|
||||
, device_inter{nullptr}
|
||||
, compressed_device_addr(1ULL << ((Settings::values.memory_layout_mode.GetValue() == Settings::MemoryLayout::Memory_4Gb ? physical_min_bits : physical_max_bits) - Memory::YUZU_PAGEBITS))
|
||||
, tracked_entries(device_as_size >> Memory::YUZU_PAGEBITS)
|
||||
|
||||
@@ -28,7 +28,7 @@ Result CloseHandle(Core::System& system, Handle handle) {
|
||||
|
||||
/// Clears the signaled state of an event or process.
|
||||
Result ResetSignal(Core::System& system, Handle handle) {
|
||||
LOG_DEBUG(Kernel_SVC, "called handle {:#08x}", handle);
|
||||
LOG_TRACE(Kernel_SVC, "called handle {:#08x}", handle);
|
||||
|
||||
// Get the current handle table.
|
||||
const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <ankerl/unordered_dense.h>
|
||||
|
||||
#include "common/logging.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/ldn/ldn_results.h"
|
||||
#include "core/hle/service/ldn/ldn_types.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator
|
||||
@@ -84,7 +84,7 @@ private:
|
||||
RestrictionSettings restriction_settings{};
|
||||
std::array<char, 8> pin_code{};
|
||||
Capability capability{};
|
||||
// TODO: this is RAW as fuck
|
||||
// TODO: this is raw
|
||||
PlayTimerSettings raw_play_timer_settings{};
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
||||
@@ -129,6 +129,13 @@ ServerManager::~ServerManager() {
|
||||
}
|
||||
}
|
||||
|
||||
void ServerManager::StartAdditionalHostThreads(const char* name, size_t num_threads) {
|
||||
for (size_t i = 0; i < num_threads; i++) {
|
||||
auto thread_name = fmt::format("{}:{}", name, i + 1);
|
||||
m_threads.emplace_back(m_system.Kernel().RunOnHostCoreThread(std::move(thread_name), [&] { this->LoopProcessImpl(); }));
|
||||
}
|
||||
}
|
||||
|
||||
void ServerManager::RunServer(std::unique_ptr<ServerManager>&& server_manager) {
|
||||
server_manager->m_system.RunServer(std::move(server_manager));
|
||||
}
|
||||
@@ -245,14 +252,6 @@ Result ServerManager::ManageDeferral(Kernel::KEvent** out_event) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void ServerManager::StartAdditionalHostThreads(const char* name, size_t num_threads) {
|
||||
for (size_t i = 0; i < num_threads; i++) {
|
||||
auto thread_name = fmt::format("{}:{}", name, i + 1);
|
||||
m_threads.emplace_back(m_system.Kernel().RunOnHostCoreThread(
|
||||
std::move(thread_name), [&] { this->LoopProcessImpl(); }));
|
||||
}
|
||||
}
|
||||
|
||||
Result ServerManager::LoopProcess() {
|
||||
SCOPE_EXIT {
|
||||
m_stopped.Set();
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -48,8 +51,8 @@ public:
|
||||
Result ManageDeferral(Kernel::KEvent** out_event);
|
||||
|
||||
Result LoopProcess();
|
||||
void StartAdditionalHostThreads(const char* name, size_t num_threads);
|
||||
|
||||
void StartAdditionalHostThreads(const char* name, size_t num_threads);
|
||||
static void RunServer(std::unique_ptr<ServerManager>&& server);
|
||||
|
||||
private:
|
||||
|
||||
@@ -1020,7 +1020,7 @@ Result ISystemSettingsServer::GetBatteryLot(Out<BatteryLot> out_battery_lot) {
|
||||
c.lot_number[1] = 'H';
|
||||
c.lot_number[2] = 'A';
|
||||
c.lot_number[3] = 'C';
|
||||
// TODO: I have no fucking idea what the letters mean
|
||||
// TODO: what do the letters mean?
|
||||
c.lot_number[4] = 'H';
|
||||
c.lot_number[5] = 'Z';
|
||||
c.lot_number[6] = 'Z';
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
#include "common/logging.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "core/hle/service/sockets/sockets_translate.h"
|
||||
#include "core/internal_network/network.h"
|
||||
#include "core/internal_network/socket_proxy.h"
|
||||
#include "core/internal_network/socket_icmp.h"
|
||||
#include "core/internal_network/sockets.h"
|
||||
#include "network/network.h"
|
||||
#include <common/settings.h>
|
||||
@@ -28,11 +29,11 @@ namespace Service::Sockets {
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsConnectionBased(Type type) {
|
||||
bool IsConnectionBased(Network::Type type) {
|
||||
switch (type) {
|
||||
case Type::STREAM:
|
||||
case Network::Type::STREAM:
|
||||
return true;
|
||||
case Type::DGRAM:
|
||||
case Network::Type::DGRAM:
|
||||
return false;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented type={}", type);
|
||||
@@ -92,7 +93,7 @@ void BSD::ConnectWork::Execute(BSD* bsd) {
|
||||
void BSD::ConnectWork::Response(HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
|
||||
rb.Push<s32>(bsd_errno == Network::Errno::SUCCESS ? 0 : -1);
|
||||
rb.PushEnum(bsd_errno);
|
||||
}
|
||||
|
||||
@@ -170,12 +171,8 @@ void BSD::Socket(HLERequestContext& ctx) {
|
||||
const u32 domain = rp.Pop<u32>();
|
||||
const u32 type = rp.Pop<u32>();
|
||||
const u32 protocol = rp.Pop<u32>();
|
||||
|
||||
LOG_DEBUG(Service, "called. domain={} type={} protocol={}", domain, type, protocol);
|
||||
|
||||
const auto [fd, bsd_errno] = SocketImpl(static_cast<Domain>(domain), static_cast<Type>(type),
|
||||
static_cast<Protocol>(protocol));
|
||||
|
||||
const auto [fd, bsd_errno] = SocketImpl(Network::Domain(domain), Network::Type(type), Network::Protocol(protocol));
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<s32>(fd);
|
||||
@@ -246,13 +243,13 @@ void BSD::GetPeerName(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service, "called. fd={}", fd);
|
||||
|
||||
std::vector<u8> write_buffer(ctx.GetWriteBufferSize());
|
||||
const Errno bsd_errno = GetPeerNameImpl(fd, write_buffer);
|
||||
const Network::Errno bsd_errno = GetPeerNameImpl(fd, write_buffer);
|
||||
|
||||
ctx.WriteBuffer(write_buffer);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 5};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<s32>(bsd_errno != Errno::SUCCESS ? -1 : 0);
|
||||
rb.Push<s32>(bsd_errno != Network::Errno::SUCCESS ? -1 : 0);
|
||||
rb.PushEnum(bsd_errno);
|
||||
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
||||
}
|
||||
@@ -264,13 +261,13 @@ void BSD::GetSockName(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service, "called. fd={}", fd);
|
||||
|
||||
std::vector<u8> write_buffer(ctx.GetWriteBufferSize());
|
||||
const Errno bsd_errno = GetSockNameImpl(fd, write_buffer);
|
||||
const Network::Errno bsd_errno = GetSockNameImpl(fd, write_buffer);
|
||||
|
||||
ctx.WriteBuffer(write_buffer);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 5};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<s32>(bsd_errno != Errno::SUCCESS ? -1 : 0);
|
||||
rb.Push<s32>(bsd_errno != Network::Errno::SUCCESS ? -1 : 0);
|
||||
rb.PushEnum(bsd_errno);
|
||||
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
|
||||
}
|
||||
@@ -278,21 +275,19 @@ void BSD::GetSockName(HLERequestContext& ctx) {
|
||||
void BSD::GetSockOpt(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const s32 fd = rp.Pop<s32>();
|
||||
const u32 level = rp.Pop<u32>();
|
||||
const auto optname = static_cast<OptName>(rp.Pop<u32>());
|
||||
const auto level = Network::SocketLevel(rp.Pop<u32>());
|
||||
const auto optname = Network::OptName(rp.Pop<u32>());
|
||||
|
||||
std::vector<u8> optval(ctx.GetWriteBufferSize());
|
||||
|
||||
LOG_DEBUG(Service, "called. fd={} level={} optname={:#x} len={:#x}", fd, level, optname,
|
||||
optval.size());
|
||||
|
||||
const Errno err = GetSockOptImpl(fd, level, optname, optval);
|
||||
LOG_DEBUG(Service, "called. fd={} level={} optname={:#x} len={:#x}", fd, level, optname, optval.size());
|
||||
const Network::Errno err = GetSockOptImpl(fd, level, optname, optval);
|
||||
|
||||
ctx.WriteBuffer(optval);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 5};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<s32>(err == Errno::SUCCESS ? 0 : -1);
|
||||
rb.Push<s32>(err == Network::Errno::SUCCESS ? 0 : -1);
|
||||
rb.PushEnum(err);
|
||||
rb.Push<u32>(static_cast<u32>(optval.size()));
|
||||
}
|
||||
@@ -315,7 +310,7 @@ void BSD::Fcntl(HLERequestContext& ctx) {
|
||||
|
||||
LOG_DEBUG(Service, "called. fd={} cmd={} arg={}", fd, cmd, arg);
|
||||
|
||||
const auto [ret, bsd_errno] = FcntlImpl(fd, static_cast<FcntlCmd>(cmd), arg);
|
||||
const auto [ret, bsd_errno] = FcntlImpl(fd, Network::FcntlCmd(cmd), arg);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
@@ -327,13 +322,11 @@ void BSD::SetSockOpt(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const s32 fd = rp.Pop<s32>();
|
||||
const u32 level = rp.Pop<u32>();
|
||||
const OptName optname = static_cast<OptName>(rp.Pop<u32>());
|
||||
const Network::SocketLevel level = Network::SocketLevel(rp.Pop<u32>());
|
||||
const Network::OptName optname = Network::OptName(rp.Pop<u32>());
|
||||
const auto optval = ctx.ReadBuffer();
|
||||
|
||||
LOG_DEBUG(Service, "called. fd={} level={} optname={:#x} optlen={}", fd, level,
|
||||
static_cast<u32>(optname), optval.size());
|
||||
|
||||
LOG_DEBUG(Service, "called. fd={} level={} optname={:#x} optlen={}", fd, level, u32(optname), optval.size());
|
||||
BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optval));
|
||||
}
|
||||
|
||||
@@ -454,7 +447,7 @@ void BSD::DuplicateSocket(HLERequestContext& ctx) {
|
||||
|
||||
struct OutputParameters {
|
||||
s32 ret;
|
||||
Errno bsd_errno;
|
||||
Network::Errno bsd_errno;
|
||||
};
|
||||
static_assert(sizeof(OutputParameters) == 0x8);
|
||||
|
||||
@@ -468,10 +461,10 @@ void BSD::DuplicateSocket(HLERequestContext& ctx) {
|
||||
if (auto* res = std::get_if<s32>(&res_v)) {
|
||||
rb.PushRaw(OutputParameters{
|
||||
.ret = *res,
|
||||
.bsd_errno = Errno::SUCCESS,
|
||||
.bsd_errno = Network::Errno::SUCCESS,
|
||||
});
|
||||
} else {
|
||||
auto* err = std::get_if<Errno>(&res_v);
|
||||
auto* err = std::get_if<Network::Errno>(&res_v);
|
||||
rb.PushRaw(OutputParameters{
|
||||
.ret = 0,
|
||||
.bsd_errno = *err,
|
||||
@@ -486,7 +479,7 @@ void BSD::EventFd(HLERequestContext& ctx) {
|
||||
|
||||
LOG_WARNING(Service, "(STUBBED) called. initval={}, flags={}", initval, flags);
|
||||
|
||||
BuildErrnoResponse(ctx, Errno::SUCCESS);
|
||||
BuildErrnoResponse(ctx, Network::Errno::SUCCESS);
|
||||
}
|
||||
|
||||
template <typename Work>
|
||||
@@ -495,130 +488,130 @@ void BSD::ExecuteWork(HLERequestContext& ctx, Work work) {
|
||||
work.Response(ctx);
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protocol) {
|
||||
|
||||
if (type == Type::SEQPACKET) {
|
||||
std::pair<s32, Network::Errno> BSD::SocketImpl(Network::Domain domain, Network::Type type, Network::Protocol protocol) {
|
||||
LOG_DEBUG(Network, "domain={},type={},protocol={}", u32(domain), u32(type), u32(protocol));
|
||||
if (type == Network::Type::SEQPACKET) {
|
||||
UNIMPLEMENTED_MSG("SOCK_SEQPACKET errno management");
|
||||
} else if (type == Type::RAW && (domain != Domain::INET || protocol != Protocol::ICMP)) {
|
||||
} else if (type == Network::Type::RAW && (domain != Network::Domain::INET || protocol != Network::Protocol::ICMP)) {
|
||||
UNIMPLEMENTED_MSG("SOCK_RAW errno management");
|
||||
}
|
||||
|
||||
[[maybe_unused]] const bool unk_flag = (static_cast<u32>(type) & 0x20000000) != 0;
|
||||
[[maybe_unused]] const bool unk_flag = (u32(type) & 0x20000000) != 0;
|
||||
UNIMPLEMENTED_IF_MSG(unk_flag, "Unknown flag in type");
|
||||
type = static_cast<Type>(static_cast<u32>(type) & ~0x20000000);
|
||||
type = Network::Type(u32(type) & ~0x20000000);
|
||||
|
||||
const s32 fd = FindFreeFileDescriptorHandle();
|
||||
if (fd < 0) {
|
||||
LOG_ERROR(Service, "No more file descriptors available");
|
||||
return {-1, Errno::MFILE};
|
||||
return {-1, Network::Errno::MFILE};
|
||||
}
|
||||
|
||||
if (Settings::values.airplane_mode.GetValue() && IsConnectionBased(type)) {
|
||||
LOG_ERROR(Service, "Airplane mode is enabled, cannot create socket");
|
||||
file_descriptors[fd].reset();
|
||||
return {-1, Network::Errno::NOTCONN};
|
||||
}
|
||||
|
||||
file_descriptors[fd] = FileDescriptor{};
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
|
||||
// ENONMEM might be thrown here
|
||||
LOG_INFO(Service, "New socket fd={},domain={},type={},prot={}", fd, domain, type, protocol);
|
||||
|
||||
LOG_INFO(Service, "New socket fd={}", fd);
|
||||
|
||||
// While room is important -- we need to remember ICMP takes priority over **everything else**
|
||||
// TODO: rework this so proxy sockets can be done transparently? -- like what if i need
|
||||
// to browse the internet while playing LDN or something stupid like that?
|
||||
auto room_member = Network::GetRoomMember().lock();
|
||||
if (room_member && room_member->IsConnected()) {
|
||||
if (protocol == Network::Protocol::ICMP || protocol == Network::Protocol::ICMPV6) {
|
||||
descriptor.socket = std::make_shared<Network::IcmpSocket>();
|
||||
} else if (room_member && room_member->IsConnected()) {
|
||||
descriptor.socket = std::make_shared<Network::ProxySocket>();
|
||||
} else {
|
||||
descriptor.socket = std::make_shared<Network::Socket>();
|
||||
}
|
||||
|
||||
descriptor.socket->Initialize(Translate(domain), Translate(type), Translate(protocol));
|
||||
auto const bsd_errno = descriptor.socket->Initialize(domain, type, protocol);
|
||||
descriptor.is_connection_based = IsConnectionBased(type);
|
||||
|
||||
if (Settings::values.airplane_mode.GetValue() && descriptor.is_connection_based) {
|
||||
LOG_ERROR(Service, "Airplane mode is enabled, cannot create socket");
|
||||
return {-1, Errno::NOTCONN};
|
||||
#ifdef _WIN32
|
||||
if (descriptor.is_connection_based && descriptor.socket->fd == INVALID_SOCKET) {
|
||||
#else
|
||||
if (descriptor.is_connection_based && descriptor.socket->fd == Network::Socket::INVALID_SOCKET) {
|
||||
#endif
|
||||
file_descriptors[fd].reset();
|
||||
return {-1, bsd_errno};
|
||||
}
|
||||
|
||||
return {fd, Errno::SUCCESS};
|
||||
return {fd, Network::Errno::SUCCESS};
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
|
||||
s32 nfds, s32 timeout) {
|
||||
std::pair<s32, Network::Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, s32 nfds, s32 timeout) {
|
||||
LOG_DEBUG(Network, "nfds={},timeout={}", nfds, timeout);
|
||||
if (nfds <= 0) {
|
||||
// When no entries are provided, -1 is returned with errno zero
|
||||
return {-1, Errno::SUCCESS};
|
||||
return {-1, Network::Errno::SUCCESS};
|
||||
}
|
||||
if (read_buffer.size() < nfds * sizeof(PollFD)) {
|
||||
return {-1, Errno::INVAL};
|
||||
if (read_buffer.size() < nfds * sizeof(Network::PollFD)) {
|
||||
return {-1, Network::Errno::INVAL};
|
||||
}
|
||||
if (write_buffer.size() < nfds * sizeof(PollFD)) {
|
||||
return {-1, Errno::INVAL};
|
||||
if (write_buffer.size() < nfds * sizeof(Network::PollFD)) {
|
||||
return {-1, Network::Errno::INVAL};
|
||||
}
|
||||
|
||||
std::vector<PollFD> fds(nfds);
|
||||
std::memcpy(fds.data(), read_buffer.data(), nfds * sizeof(PollFD));
|
||||
std::span<const Network::PollFD> in_fds(reinterpret_cast<const Network::PollFD*>(read_buffer.data()), nfds);
|
||||
std::span<Network::PollFD> out_fds(reinterpret_cast<Network::PollFD*>(write_buffer.data()), nfds);
|
||||
std::copy(in_fds.begin(), in_fds.end(), out_fds.begin());
|
||||
|
||||
if (timeout >= 0) {
|
||||
const s64 seconds = timeout / 1000;
|
||||
const u64 nanoseconds = 1'000'000 * (static_cast<u64>(timeout) % 1000);
|
||||
|
||||
const u64 nanoseconds = 1'000'000 * (u64(timeout) % 1000);
|
||||
if (seconds < 0) {
|
||||
return {-1, Errno::INVAL};
|
||||
return {-1, Network::Errno::INVAL};
|
||||
}
|
||||
if (nanoseconds > 999'999'999) {
|
||||
return {-1, Errno::INVAL};
|
||||
return {-1, Network::Errno::INVAL};
|
||||
}
|
||||
} else if (timeout != -1) {
|
||||
return {-1, Errno::INVAL};
|
||||
return {-1, Network::Errno::INVAL};
|
||||
}
|
||||
|
||||
for (PollFD& pollfd : fds) {
|
||||
ASSERT(False(pollfd.revents));
|
||||
|
||||
if (pollfd.fd > static_cast<s32>(MAX_FD) || pollfd.fd < 0) {
|
||||
LOG_ERROR(Service, "File descriptor handle={} is invalid", pollfd.fd);
|
||||
pollfd.revents = PollEvents{};
|
||||
return {0, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
const std::optional<FileDescriptor>& descriptor = file_descriptors[pollfd.fd];
|
||||
if (!descriptor) {
|
||||
LOG_TRACE(Service, "File descriptor handle={} is not allocated", pollfd.fd);
|
||||
pollfd.revents = PollEvents::Nval;
|
||||
return {0, Errno::SUCCESS};
|
||||
for (size_t i = 0; i < in_fds.size(); ++i) {
|
||||
ASSERT(out_fds[i].fd == in_fds[i].fd && False(in_fds[i].revents));
|
||||
if (!IsFileDescriptorValid(in_fds[i].fd)) {
|
||||
out_fds[i].revents = {};
|
||||
if (!file_descriptors[in_fds[i].fd])
|
||||
out_fds[i].revents = Network::PollEvents::NVAL;
|
||||
return {0, Network::Errno::SUCCESS};
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Network::PollFD> host_pollfds(fds.size());
|
||||
std::transform(fds.begin(), fds.end(), host_pollfds.begin(), [](PollFD pollfd) {
|
||||
Network::PollFD result;
|
||||
result.socket = file_descriptors[pollfd.fd]->socket.get();
|
||||
result.events = Translate(pollfd.events);
|
||||
result.revents = Network::PollEvents{};
|
||||
std::vector<Network::HostPollFD> host_pollfds(in_fds.size());
|
||||
std::transform(in_fds.begin(), in_fds.end(), host_pollfds.begin(), [](auto const e) {
|
||||
Network::HostPollFD result{};
|
||||
result.socket = file_descriptors[e.fd]->socket.get();
|
||||
result.events = e.events;
|
||||
result.revents = {};
|
||||
return result;
|
||||
});
|
||||
|
||||
const auto result = Network::Poll(host_pollfds, timeout);
|
||||
|
||||
const size_t num = host_pollfds.size();
|
||||
for (size_t i = 0; i < num; ++i) {
|
||||
fds[i].revents = Translate(host_pollfds[i].revents);
|
||||
}
|
||||
std::memcpy(write_buffer.data(), fds.data(), nfds * sizeof(PollFD));
|
||||
|
||||
return Translate(result);
|
||||
auto const res = Network::Poll(host_pollfds, timeout);
|
||||
for (size_t i = 0; i < in_fds.size(); ++i)
|
||||
out_fds[i].revents = host_pollfds[i].revents;
|
||||
return res;
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
std::pair<s32, Network::Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return {-1, Errno::BADF};
|
||||
return {-1, Network::Errno::BADF};
|
||||
}
|
||||
|
||||
const s32 new_fd = FindFreeFileDescriptorHandle();
|
||||
if (new_fd < 0) {
|
||||
LOG_ERROR(Service, "No more file descriptors available");
|
||||
return {-1, Errno::MFILE};
|
||||
return {-1, Network::Errno::MFILE};
|
||||
}
|
||||
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
auto [result, bsd_errno] = descriptor.socket->Accept();
|
||||
if (bsd_errno != Network::Errno::SUCCESS) {
|
||||
return {-1, Translate(bsd_errno)};
|
||||
return {-1, bsd_errno};
|
||||
}
|
||||
|
||||
file_descriptors[new_fd] = FileDescriptor{};
|
||||
@@ -626,267 +619,218 @@ std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
new_descriptor.socket = std::move(result.socket);
|
||||
new_descriptor.is_connection_based = descriptor.is_connection_based;
|
||||
|
||||
const SockAddrIn guest_addr_in = Translate(result.sockaddr_in);
|
||||
PutValue(write_buffer, guest_addr_in);
|
||||
|
||||
return {new_fd, Errno::SUCCESS};
|
||||
PutValue(write_buffer, result.sockaddr_in);
|
||||
return {new_fd, Network::Errno::SUCCESS};
|
||||
}
|
||||
|
||||
Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) {
|
||||
Network::Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Errno::BADF;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
ASSERT(addr.size() >= 16);
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Errno::BADF;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
|
||||
auto addr_in = GetValue<SockAddrIn>(addr);
|
||||
|
||||
return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
|
||||
auto addr_in = GetValue<Network::SockAddrIn>(addr);
|
||||
return file_descriptors[fd]->socket->Bind(addr_in);
|
||||
}
|
||||
|
||||
Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
|
||||
Network::Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Errno::BADF;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
|
||||
ASSERT(addr.size() >= 16);
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Errno::BADF;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
|
||||
auto addr_in = GetValue<SockAddrIn>(addr);
|
||||
|
||||
const Errno result = Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in)));
|
||||
|
||||
if (result == Errno::ISCONN) {
|
||||
auto addr_in = GetValue<Network::SockAddrIn>(addr);
|
||||
const Network::Errno result = file_descriptors[fd]->socket->Connect(addr_in);
|
||||
if (result == Network::Errno::ISCONN) {
|
||||
LOG_DEBUG(Service, "returned ISCONN - socket already connected");
|
||||
return Errno::SUCCESS;
|
||||
return Network::Errno::SUCCESS;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
Network::Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Errno::BADF;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Errno::BADF;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
|
||||
const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetPeerName();
|
||||
if (bsd_errno != Network::Errno::SUCCESS) {
|
||||
return Translate(bsd_errno);
|
||||
return bsd_errno;
|
||||
}
|
||||
const SockAddrIn guest_addrin = Translate(addr_in);
|
||||
|
||||
ASSERT(write_buffer.size() >= sizeof(guest_addrin));
|
||||
write_buffer.resize(sizeof(guest_addrin));
|
||||
PutValue(write_buffer, guest_addrin);
|
||||
return Translate(bsd_errno);
|
||||
ASSERT(write_buffer.size() >= addr_in.len);
|
||||
write_buffer.resize(addr_in.len);
|
||||
PutValue(write_buffer, addr_in);
|
||||
return bsd_errno;
|
||||
}
|
||||
|
||||
Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
Network::Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Errno::BADF;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Errno::BADF;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
|
||||
const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetSockName();
|
||||
if (bsd_errno != Network::Errno::SUCCESS) {
|
||||
return Translate(bsd_errno);
|
||||
return bsd_errno;
|
||||
}
|
||||
const SockAddrIn guest_addrin = Translate(addr_in);
|
||||
|
||||
ASSERT(write_buffer.size() >= sizeof(guest_addrin));
|
||||
write_buffer.resize(sizeof(guest_addrin));
|
||||
PutValue(write_buffer, guest_addrin);
|
||||
return Translate(bsd_errno);
|
||||
ASSERT(write_buffer.size() >= addr_in.len);
|
||||
write_buffer.resize(addr_in.len);
|
||||
PutValue(write_buffer, addr_in);
|
||||
return bsd_errno;
|
||||
}
|
||||
|
||||
Errno BSD::ListenImpl(s32 fd, s32 backlog) {
|
||||
Network::Errno BSD::ListenImpl(s32 fd, s32 backlog) {
|
||||
LOG_DEBUG(Network, "fd={},backlog={}", fd, backlog);
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Errno::BADF;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Errno::BADF;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
return Translate(file_descriptors[fd]->socket->Listen(backlog));
|
||||
return file_descriptors[fd]->socket->Listen(backlog);
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
|
||||
std::pair<s32, Network::Errno> BSD::FcntlImpl(s32 fd, Network::FcntlCmd cmd, s32 arg) {
|
||||
LOG_DEBUG(Network, "fd={},cmd={},arg={}", fd, u32(cmd), arg);
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return {-1, Errno::BADF};
|
||||
return {-1, Network::Errno::BADF};
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return {-1, Errno::BADF};
|
||||
return {-1, Network::Errno::BADF};
|
||||
}
|
||||
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
|
||||
switch (cmd) {
|
||||
case FcntlCmd::GETFL:
|
||||
case Network::FcntlCmd::GETFL:
|
||||
ASSERT(arg == 0);
|
||||
return {descriptor.flags, Errno::SUCCESS};
|
||||
case FcntlCmd::SETFL: {
|
||||
const bool enable = (arg & Network::FLAG_O_NONBLOCK) != 0;
|
||||
const Errno bsd_errno = Translate(descriptor.socket->SetNonBlock(enable));
|
||||
if (bsd_errno != Errno::SUCCESS) {
|
||||
return {descriptor.flags, Network::Errno::SUCCESS};
|
||||
case Network::FcntlCmd::SETFL: {
|
||||
const bool enable = (arg & u32(Network::FcntlFlags::NONBLOCK_NX)) != 0;
|
||||
const Network::Errno bsd_errno = descriptor.socket->SetNonBlock(enable);
|
||||
if (bsd_errno != Network::Errno::SUCCESS) {
|
||||
return {-1, bsd_errno};
|
||||
}
|
||||
descriptor.flags = arg;
|
||||
return {0, Errno::SUCCESS};
|
||||
return {0, Network::Errno::SUCCESS};
|
||||
}
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented cmd={}", cmd);
|
||||
return {-1, Errno::SUCCESS};
|
||||
return {-1, Network::Errno::SUCCESS};
|
||||
}
|
||||
}
|
||||
|
||||
Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval) {
|
||||
Network::Errno BSD::GetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::vector<u8>& optval) {
|
||||
LOG_DEBUG(Network, "fd={},level={},optname={}", fd, u32(level), u32(optname));
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Errno::BADF;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Errno::BADF;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
|
||||
if (level != static_cast<u32>(SocketLevel::SOCKET)) {
|
||||
UNIMPLEMENTED_MSG("Unknown getsockopt level");
|
||||
return Errno::SUCCESS;
|
||||
if (level != Network::SocketLevel::SOCKET) {
|
||||
LOG_WARNING(Service, "(stubbed) level fd={}, level={}, optname={}", fd, level, optname);
|
||||
}
|
||||
|
||||
Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
|
||||
|
||||
switch (optname) {
|
||||
case OptName::ERROR_: {
|
||||
case Network::OptName::ERROR_: {
|
||||
auto [pending_err, getsockopt_err] = socket->GetPendingError();
|
||||
if (getsockopt_err == Network::Errno::SUCCESS) {
|
||||
Errno translated_pending_err = Translate(pending_err);
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
optval.size() == sizeof(Errno), { return Errno::INVAL; },
|
||||
optval.size() == sizeof(Network::Errno), { return Network::Errno::INVAL; },
|
||||
"Incorrect getsockopt option size");
|
||||
optval.resize(sizeof(Errno));
|
||||
PutValue(optval, translated_pending_err);
|
||||
optval.resize(sizeof(Network::Errno));
|
||||
PutValue(optval, pending_err);
|
||||
}
|
||||
return Translate(getsockopt_err);
|
||||
return getsockopt_err;
|
||||
}
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented optname={}", optname);
|
||||
return Errno::SUCCESS;
|
||||
return Network::Errno::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval) {
|
||||
Network::Errno BSD::SetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::span<const u8> optval) {
|
||||
LOG_DEBUG(Service, "fd={},level={},optname={}", fd, level, optname);
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Errno::BADF;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Errno::BADF;
|
||||
}
|
||||
|
||||
if (level != static_cast<u32>(SocketLevel::SOCKET)) {
|
||||
LOG_WARNING(Service, "(STUBBED) setsockopt with level={}, optname={}", level, optname);
|
||||
return Errno::SUCCESS;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
|
||||
Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
|
||||
|
||||
if (optname == OptName::LINGER) {
|
||||
ASSERT(optval.size() == sizeof(Linger));
|
||||
auto linger = GetValue<Linger>(optval);
|
||||
ASSERT(linger.onoff == 0 || linger.onoff == 1);
|
||||
|
||||
return Translate(socket->SetLinger(linger.onoff != 0, linger.linger));
|
||||
}
|
||||
|
||||
ASSERT(optval.size() == sizeof(u32));
|
||||
auto value = GetValue<u32>(optval);
|
||||
|
||||
switch (optname) {
|
||||
case OptName::REUSEADDR:
|
||||
ASSERT(value == 0 || value == 1);
|
||||
return Translate(socket->SetReuseAddr(value != 0));
|
||||
case OptName::KEEPALIVE:
|
||||
ASSERT(value == 0 || value == 1);
|
||||
return Translate(socket->SetKeepAlive(value != 0));
|
||||
case OptName::BROADCAST:
|
||||
ASSERT(value == 0 || value == 1);
|
||||
return Translate(socket->SetBroadcast(value != 0));
|
||||
case OptName::SNDBUF:
|
||||
return Translate(socket->SetSndBuf(value));
|
||||
case OptName::RCVBUF:
|
||||
return Translate(socket->SetRcvBuf(value));
|
||||
case OptName::SNDTIMEO:
|
||||
return Translate(socket->SetSndTimeo(value));
|
||||
case OptName::RCVTIMEO:
|
||||
return Translate(socket->SetRcvTimeo(value));
|
||||
case OptName::NOSIGPIPE:
|
||||
LOG_WARNING(Service, "(STUBBED) setting NOSIGPIPE to {}", value);
|
||||
return Errno::SUCCESS;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented optname={}", optname);
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
return socket->SetSockOpt(level, optname, optval);
|
||||
}
|
||||
|
||||
Errno BSD::ShutdownImpl(s32 fd, s32 how) {
|
||||
Network::Errno BSD::ShutdownImpl(s32 fd, s32 how) {
|
||||
LOG_DEBUG(Network, "fd={},how={}", fd, how);
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Errno::BADF;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Errno::BADF;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
const Network::ShutdownHow host_how = Translate(static_cast<ShutdownHow>(how));
|
||||
return Translate(file_descriptors[fd]->socket->Shutdown(host_how));
|
||||
return file_descriptors[fd]->socket->Shutdown(Network::ShutdownHow(how));
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
|
||||
std::pair<s32, Network::Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
|
||||
LOG_DEBUG(Network, "fd={},flags={}", fd, flags);
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return {-1, Errno::BADF};
|
||||
return {-1, Network::Errno::BADF};
|
||||
}
|
||||
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
|
||||
// Apply flags
|
||||
using Network::FLAG_MSG_DONTWAIT;
|
||||
using Network::FLAG_O_NONBLOCK;
|
||||
if ((flags & FLAG_MSG_DONTWAIT) != 0) {
|
||||
flags &= ~FLAG_MSG_DONTWAIT;
|
||||
if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
|
||||
if ((flags & u32(Network::MsgOpt::DONTWAIT)) != 0) {
|
||||
flags &= ~u32(Network::MsgOpt::DONTWAIT);
|
||||
if ((descriptor.flags & u32(Network::FcntlFlags::NONBLOCK_NX)) == 0) {
|
||||
descriptor.socket->SetNonBlock(true);
|
||||
}
|
||||
}
|
||||
|
||||
const auto [ret, bsd_errno] = Translate(descriptor.socket->Recv(flags, message));
|
||||
|
||||
const auto [ret, bsd_errno] = descriptor.socket->Recv(flags, message);
|
||||
// Restore original state
|
||||
if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
|
||||
if ((descriptor.flags & u32(Network::FcntlFlags::NONBLOCK_NX)) == 0)
|
||||
descriptor.socket->SetNonBlock(false);
|
||||
}
|
||||
|
||||
return {ret, bsd_errno};
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
|
||||
std::vector<u8>& addr) {
|
||||
std::pair<s32, Network::Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message, std::vector<u8>& addr) {
|
||||
LOG_DEBUG(Network, "fd={},flags={}", fd, flags);
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return {-1, Errno::BADF};
|
||||
return {-1, Network::Errno::BADF};
|
||||
}
|
||||
|
||||
FileDescriptor& descriptor = *file_descriptors[fd];
|
||||
@@ -901,19 +845,17 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess
|
||||
}
|
||||
|
||||
// Apply flags
|
||||
using Network::FLAG_MSG_DONTWAIT;
|
||||
using Network::FLAG_O_NONBLOCK;
|
||||
if ((flags & FLAG_MSG_DONTWAIT) != 0) {
|
||||
flags &= ~FLAG_MSG_DONTWAIT;
|
||||
if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
|
||||
if ((flags & u32(Network::MsgOpt::DONTWAIT)) != 0) {
|
||||
flags &= ~u32(Network::MsgOpt::DONTWAIT);
|
||||
if ((descriptor.flags & u32(Network::FcntlFlags::NONBLOCK_NX)) == 0) {
|
||||
descriptor.socket->SetNonBlock(true);
|
||||
}
|
||||
}
|
||||
|
||||
const auto [ret, bsd_errno] = Translate(descriptor.socket->RecvFrom(flags, message, p_addr_in));
|
||||
const auto [ret, bsd_errno] = descriptor.socket->RecvFrom(flags, message, p_addr_in);
|
||||
|
||||
// Restore original state
|
||||
if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
|
||||
if ((descriptor.flags & u32(Network::FcntlFlags::NONBLOCK_NX)) == 0) {
|
||||
descriptor.socket->SetNonBlock(false);
|
||||
}
|
||||
|
||||
@@ -922,58 +864,59 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess
|
||||
addr.clear();
|
||||
} else {
|
||||
ASSERT(addr.size() >= 16);
|
||||
const SockAddrIn result = Translate(addr_in);
|
||||
PutValue(addr, result);
|
||||
PutValue(addr, addr_in);
|
||||
}
|
||||
}
|
||||
|
||||
return {ret, bsd_errno};
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, std::span<const u8> message) {
|
||||
std::pair<s32, Network::Errno> BSD::SendImpl(s32 fd, u32 flags, std::span<const u8> message) {
|
||||
LOG_DEBUG(Network, "fd={},flags={}", fd, flags);
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return {-1, Errno::BADF};
|
||||
return {-1, Network::Errno::BADF};
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return {-1, Errno::BADF};
|
||||
return {-1, Network::Errno::BADF};
|
||||
}
|
||||
return Translate(file_descriptors[fd]->socket->Send(message, flags));
|
||||
return file_descriptors[fd]->socket->Send(message, flags);
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
|
||||
std::span<const u8> addr) {
|
||||
std::pair<s32, Network::Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> message, std::span<const u8> addr) {
|
||||
LOG_DEBUG(Network, "fd={},flags={}", fd, flags);
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return {-1, Errno::BADF};
|
||||
return {-1, Network::Errno::BADF};
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return {-1, Errno::BADF};
|
||||
return {-1, Network::Errno::BADF};
|
||||
}
|
||||
|
||||
Network::SockAddrIn addr_in;
|
||||
Network::SockAddrIn addr_in{};
|
||||
Network::SockAddrIn* p_addr_in = nullptr;
|
||||
if (!addr.empty()) {
|
||||
ASSERT(addr.size() >= 16);
|
||||
auto guest_addr_in = GetValue<SockAddrIn>(addr);
|
||||
addr_in = Translate(guest_addr_in);
|
||||
auto guest_addr_in = GetValue<Network::SockAddrIn>(addr);
|
||||
addr_in = guest_addr_in;
|
||||
p_addr_in = &addr_in;
|
||||
}
|
||||
|
||||
return Translate(file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in));
|
||||
return file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in);
|
||||
}
|
||||
|
||||
Errno BSD::CloseImpl(s32 fd) {
|
||||
Network::Errno BSD::CloseImpl(s32 fd) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Errno::BADF;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
if (!file_descriptors[fd]->socket) {
|
||||
LOG_WARNING(Service, "Uninitialized socket");
|
||||
return Errno::BADF;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
|
||||
const Errno bsd_errno = Translate(file_descriptors[fd]->socket->Close());
|
||||
if (bsd_errno != Errno::SUCCESS) {
|
||||
auto const bsd_errno = file_descriptors[fd]->socket->Close();
|
||||
if (bsd_errno != Network::Errno::SUCCESS) {
|
||||
return bsd_errno;
|
||||
}
|
||||
|
||||
@@ -983,15 +926,16 @@ Errno BSD::CloseImpl(s32 fd) {
|
||||
return bsd_errno;
|
||||
}
|
||||
|
||||
std::variant<s32, Errno> BSD::DuplicateSocketImpl(s32 fd) {
|
||||
std::variant<s32, Network::Errno> BSD::DuplicateSocketImpl(s32 fd) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return Errno::BADF;
|
||||
return Network::Errno::BADF;
|
||||
}
|
||||
|
||||
const s32 new_fd = FindFreeFileDescriptorHandle();
|
||||
if (new_fd < 0) {
|
||||
if (!IsFileDescriptorValid(new_fd)) {
|
||||
LOG_ERROR(Service, "No more file descriptors available");
|
||||
return Errno::MFILE;
|
||||
return Network::Errno::MFILE;
|
||||
}
|
||||
|
||||
file_descriptors[new_fd] = FileDescriptor{
|
||||
@@ -1003,6 +947,7 @@ std::variant<s32, Errno> BSD::DuplicateSocketImpl(s32 fd) {
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<Network::SocketBase>> BSD::GetSocket(s32 fd) {
|
||||
LOG_DEBUG(Network, "fd={}", fd);
|
||||
if (!IsFileDescriptorValid(fd)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -1014,41 +959,40 @@ std::optional<std::shared_ptr<Network::SocketBase>> BSD::GetSocket(s32 fd) {
|
||||
}
|
||||
|
||||
s32 BSD::FindFreeFileDescriptorHandle() noexcept {
|
||||
for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) {
|
||||
if (!file_descriptors[fd]) {
|
||||
// first three file descriptors are reserved for:
|
||||
// STDOUT_FILENO, STDIN_FILENO and STDERR_FILENO
|
||||
for (s32 fd = 0; fd < s32(file_descriptors.size()); ++fd)
|
||||
if (!file_descriptors[fd])
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool BSD::IsFileDescriptorValid(s32 fd) const noexcept {
|
||||
if (fd > static_cast<s32>(MAX_FD) || fd < 0) {
|
||||
LOG_ERROR(Service, "Invalid file descriptor handle={}", fd);
|
||||
if (fd < 0 || fd >= s32(file_descriptors.size())) {
|
||||
LOG_ERROR(Service, "Invalid handle={}", fd);
|
||||
return false;
|
||||
}
|
||||
if (!file_descriptors[fd]) {
|
||||
LOG_ERROR(Service, "File descriptor handle={} is not allocated", fd);
|
||||
LOG_ERROR(Service, "handle={} is not allocated", fd);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BSD::BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept {
|
||||
void BSD::BuildErrnoResponse(HLERequestContext& ctx, Network::Errno bsd_errno) const noexcept {
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
|
||||
rb.Push<s32>(bsd_errno == Network::Errno::SUCCESS ? 0 : -1);
|
||||
rb.PushEnum(bsd_errno);
|
||||
}
|
||||
|
||||
void BSD::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
|
||||
for (auto& optional_descriptor : file_descriptors) {
|
||||
if (!optional_descriptor.has_value()) {
|
||||
continue;
|
||||
if (optional_descriptor.has_value()) {
|
||||
FileDescriptor& descriptor = *optional_descriptor;
|
||||
descriptor.socket.get()->HandleProxyPacket(packet);
|
||||
}
|
||||
FileDescriptor& descriptor = *optional_descriptor;
|
||||
descriptor.socket.get()->HandleProxyPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <variant>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sockets/sockets.h"
|
||||
#include "network/network.h"
|
||||
@@ -35,8 +35,8 @@ public:
|
||||
// These methods are called from SSL; the first two are also called from
|
||||
// this class for the corresponding IPC methods.
|
||||
// On the real device, the SSL service makes IPC calls to this service.
|
||||
std::variant<s32, Errno> DuplicateSocketImpl(s32 fd);
|
||||
Errno CloseImpl(s32 fd);
|
||||
std::variant<s32, Network::Errno> DuplicateSocketImpl(s32 fd);
|
||||
Network::Errno CloseImpl(s32 fd);
|
||||
std::optional<std::shared_ptr<Network::SocketBase>> GetSocket(s32 fd);
|
||||
|
||||
private:
|
||||
@@ -58,7 +58,7 @@ private:
|
||||
std::span<const u8> read_buffer;
|
||||
std::vector<u8> write_buffer;
|
||||
s32 ret{};
|
||||
Errno bsd_errno{};
|
||||
Network::Errno bsd_errno{};
|
||||
};
|
||||
|
||||
struct AcceptWork {
|
||||
@@ -68,7 +68,7 @@ private:
|
||||
s32 fd;
|
||||
std::vector<u8> write_buffer;
|
||||
s32 ret{};
|
||||
Errno bsd_errno{};
|
||||
Network::Errno bsd_errno{};
|
||||
};
|
||||
|
||||
struct ConnectWork {
|
||||
@@ -77,7 +77,7 @@ private:
|
||||
|
||||
s32 fd;
|
||||
std::span<const u8> addr;
|
||||
Errno bsd_errno{};
|
||||
Network::Errno bsd_errno{};
|
||||
};
|
||||
|
||||
struct RecvWork {
|
||||
@@ -88,7 +88,7 @@ private:
|
||||
u32 flags;
|
||||
std::vector<u8> message;
|
||||
s32 ret{};
|
||||
Errno bsd_errno{};
|
||||
Network::Errno bsd_errno{};
|
||||
};
|
||||
|
||||
struct RecvFromWork {
|
||||
@@ -100,7 +100,7 @@ private:
|
||||
std::vector<u8> message;
|
||||
std::vector<u8> addr;
|
||||
s32 ret{};
|
||||
Errno bsd_errno{};
|
||||
Network::Errno bsd_errno{};
|
||||
};
|
||||
|
||||
struct SendWork {
|
||||
@@ -111,7 +111,7 @@ private:
|
||||
u32 flags;
|
||||
std::span<const u8> message;
|
||||
s32 ret{};
|
||||
Errno bsd_errno{};
|
||||
Network::Errno bsd_errno{};
|
||||
};
|
||||
|
||||
struct SendToWork {
|
||||
@@ -123,7 +123,7 @@ private:
|
||||
std::span<const u8> message;
|
||||
std::span<const u8> addr;
|
||||
s32 ret{};
|
||||
Errno bsd_errno{};
|
||||
Network::Errno bsd_errno{};
|
||||
};
|
||||
|
||||
void RegisterClient(HLERequestContext& ctx);
|
||||
@@ -154,30 +154,30 @@ private:
|
||||
template <typename Work>
|
||||
void ExecuteWork(HLERequestContext& ctx, Work work);
|
||||
|
||||
std::pair<s32, Errno> SocketImpl(Domain domain, Type type, Protocol protocol);
|
||||
std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
|
||||
std::pair<s32, Network::Errno> SocketImpl(Network::Domain domain, Network::Type type, Network::Protocol protocol);
|
||||
std::pair<s32, Network::Errno> PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
|
||||
s32 nfds, s32 timeout);
|
||||
std::pair<s32, Errno> AcceptImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||
Errno BindImpl(s32 fd, std::span<const u8> addr);
|
||||
Errno ConnectImpl(s32 fd, std::span<const u8> addr);
|
||||
Errno GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||
Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||
Errno ListenImpl(s32 fd, s32 backlog);
|
||||
std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg);
|
||||
Errno GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval);
|
||||
Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval);
|
||||
Errno ShutdownImpl(s32 fd, s32 how);
|
||||
std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
|
||||
std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
|
||||
std::pair<s32, Network::Errno> AcceptImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||
Network::Errno BindImpl(s32 fd, std::span<const u8> addr);
|
||||
Network::Errno ConnectImpl(s32 fd, std::span<const u8> addr);
|
||||
Network::Errno GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||
Network::Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer);
|
||||
Network::Errno ListenImpl(s32 fd, s32 backlog);
|
||||
std::pair<s32, Network::Errno> FcntlImpl(s32 fd, Network::FcntlCmd cmd, s32 arg);
|
||||
Network::Errno GetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::vector<u8>& optval);
|
||||
Network::Errno SetSockOptImpl(s32 fd, Network::SocketLevel level, Network::OptName optname, std::span<const u8> optval);
|
||||
Network::Errno ShutdownImpl(s32 fd, s32 how);
|
||||
std::pair<s32, Network::Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
|
||||
std::pair<s32, Network::Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
|
||||
std::vector<u8>& addr);
|
||||
std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, std::span<const u8> message);
|
||||
std::pair<s32, Errno> SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
|
||||
std::pair<s32, Network::Errno> SendImpl(s32 fd, u32 flags, std::span<const u8> message);
|
||||
std::pair<s32, Network::Errno> SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
|
||||
std::span<const u8> addr);
|
||||
|
||||
s32 FindFreeFileDescriptorHandle() noexcept;
|
||||
bool IsFileDescriptorValid(s32 fd) const noexcept;
|
||||
|
||||
void BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept;
|
||||
void BuildErrnoResponse(HLERequestContext& ctx, Network::Errno bsd_errno) const noexcept;
|
||||
|
||||
static inline std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors{};
|
||||
|
||||
|
||||
@@ -102,39 +102,39 @@ static bool IsBlockedHost(const std::string& host) {
|
||||
[&host](const std::string& domain) { return host.find(domain) != std::string::npos; });
|
||||
}
|
||||
|
||||
static NetDbError GetAddrInfoErrorToNetDbError(GetAddrInfoError result) {
|
||||
static NetDbError GetAddrInfoErrorToNetDbError(Network::GetAddrInfoError result) {
|
||||
// These combinations have been verified on console (but are not
|
||||
// exhaustive).
|
||||
switch (result) {
|
||||
case GetAddrInfoError::SUCCESS:
|
||||
case Network::GetAddrInfoError::SUCCESS:
|
||||
return NetDbError::Success;
|
||||
case GetAddrInfoError::AGAIN:
|
||||
case Network::GetAddrInfoError::AGAIN:
|
||||
return NetDbError::TryAgain;
|
||||
case GetAddrInfoError::NODATA:
|
||||
case Network::GetAddrInfoError::NODATA:
|
||||
return NetDbError::HostNotFound;
|
||||
case GetAddrInfoError::SERVICE:
|
||||
case Network::GetAddrInfoError::SERVICE:
|
||||
return NetDbError::Success;
|
||||
default:
|
||||
return NetDbError::HostNotFound;
|
||||
}
|
||||
}
|
||||
|
||||
static Errno GetAddrInfoErrorToErrno(GetAddrInfoError result) {
|
||||
static Network::Errno GetAddrInfoErrorToErrno(Network::GetAddrInfoError result) {
|
||||
// These combinations have been verified on console (but are not
|
||||
// exhaustive).
|
||||
switch (result) {
|
||||
case GetAddrInfoError::SUCCESS:
|
||||
case Network::GetAddrInfoError::SUCCESS:
|
||||
// Note: Sometimes a successful lookup sets errno to EADDRNOTAVAIL for
|
||||
// some reason, but that doesn't seem useful to implement.
|
||||
return Errno::SUCCESS;
|
||||
case GetAddrInfoError::AGAIN:
|
||||
return Errno::SUCCESS;
|
||||
case GetAddrInfoError::NODATA:
|
||||
return Errno::SUCCESS;
|
||||
case GetAddrInfoError::SERVICE:
|
||||
return Errno::INVAL;
|
||||
return Network::Errno::SUCCESS;
|
||||
case Network::GetAddrInfoError::AGAIN:
|
||||
return Network::Errno::SUCCESS;
|
||||
case Network::GetAddrInfoError::NODATA:
|
||||
return Network::Errno::SUCCESS;
|
||||
case Network::GetAddrInfoError::SERVICE:
|
||||
return Network::Errno::INVAL;
|
||||
default:
|
||||
return Errno::SUCCESS;
|
||||
return Network::Errno::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,9 +155,7 @@ static void AppendNulTerminated(std::vector<u8>& vec, std::string_view str) {
|
||||
// host's gethostbyname, because it simplifies portability: e.g., getaddrinfo
|
||||
// behaves the same on Unix and Windows, unlike gethostbyname where Windows
|
||||
// doesn't implement h_errno.
|
||||
static std::vector<u8> SerializeAddrInfoAsHostEnt(const std::vector<Network::AddrInfo>& vec,
|
||||
std::string_view host) {
|
||||
|
||||
static std::vector<u8> SerializeAddrInfoAsHostEnt(std::span<const Network::AddrInfo> vec, std::string_view host) {
|
||||
std::vector<u8> data;
|
||||
// h_name: use the input hostname (append nul-terminated)
|
||||
AppendNulTerminated(data, host);
|
||||
@@ -165,12 +163,12 @@ static std::vector<u8> SerializeAddrInfoAsHostEnt(const std::vector<Network::Add
|
||||
|
||||
Append<u32_be>(data, 0); // count of h_aliases
|
||||
// (If the count were nonzero, the aliases would be appended as nul-terminated here.)
|
||||
Append<u16_be>(data, static_cast<u16>(Domain::INET)); // h_addrtype
|
||||
Append<u16_be>(data, u16(Network::Domain::INET)); // h_addrtype
|
||||
Append<u16_be>(data, sizeof(Network::IPv4Address)); // h_length
|
||||
// h_addr_list:
|
||||
size_t count = vec.size();
|
||||
ASSERT(count <= UINT32_MAX);
|
||||
Append<u32_be>(data, static_cast<uint32_t>(count));
|
||||
Append<u32_be>(data, u32(count));
|
||||
for (const Network::AddrInfo& addrinfo : vec) {
|
||||
// On the Switch, this is passed through htonl despite already being
|
||||
// big-endian, so it ends up as little-endian.
|
||||
@@ -182,7 +180,7 @@ static std::vector<u8> SerializeAddrInfoAsHostEnt(const std::vector<Network::Add
|
||||
return data;
|
||||
}
|
||||
|
||||
static std::pair<u32, GetAddrInfoError> GetHostByNameRequestImpl(HLERequestContext& ctx) {
|
||||
static std::pair<u32, Network::GetAddrInfoError> GetHostByNameRequestImpl(HLERequestContext& ctx) {
|
||||
struct InputParameters {
|
||||
u8 use_nsd_resolve;
|
||||
u32 cancel_handle;
|
||||
@@ -205,7 +203,7 @@ static std::pair<u32, GetAddrInfoError> GetHostByNameRequestImpl(HLERequestConte
|
||||
// Prevent resolution of Nintendo servers
|
||||
if (IsBlockedHost(host)) {
|
||||
LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host);
|
||||
return {0, GetAddrInfoError::AGAIN};
|
||||
return {0, Network::GetAddrInfoError::AGAIN};
|
||||
}
|
||||
|
||||
auto res_v = Network::GetAddressInfo(host, /*service*/ std::nullopt);
|
||||
@@ -213,10 +211,10 @@ static std::pair<u32, GetAddrInfoError> GetHostByNameRequestImpl(HLERequestConte
|
||||
const std::vector<u8> data = SerializeAddrInfoAsHostEnt(*res, host);
|
||||
const u32 data_size = u32(data.size());
|
||||
ctx.WriteBuffer(data, 0);
|
||||
return {data_size, GetAddrInfoError::SUCCESS};
|
||||
return {data_size, Network::GetAddrInfoError::SUCCESS};
|
||||
}
|
||||
auto* err = std::get_if<Network::GetAddrInfoError>(&res_v);
|
||||
return {0, Translate(*err)};
|
||||
return {0, *err};
|
||||
}
|
||||
|
||||
void SFDNSRES::GetHostByNameRequest(HLERequestContext& ctx) {
|
||||
@@ -224,7 +222,7 @@ void SFDNSRES::GetHostByNameRequest(HLERequestContext& ctx) {
|
||||
|
||||
struct OutputParameters {
|
||||
NetDbError netdb_error;
|
||||
Errno bsd_errno;
|
||||
Network::Errno bsd_errno;
|
||||
u32 data_size;
|
||||
};
|
||||
static_assert(sizeof(OutputParameters) == 0xc);
|
||||
@@ -244,7 +242,7 @@ void SFDNSRES::GetHostByNameRequestWithOptions(HLERequestContext& ctx) {
|
||||
struct OutputParameters {
|
||||
u32 data_size;
|
||||
NetDbError netdb_error;
|
||||
Errno bsd_errno;
|
||||
Network::Errno bsd_errno;
|
||||
};
|
||||
static_assert(sizeof(OutputParameters) == 0xc);
|
||||
|
||||
@@ -257,24 +255,23 @@ void SFDNSRES::GetHostByNameRequestWithOptions(HLERequestContext& ctx) {
|
||||
});
|
||||
}
|
||||
|
||||
static std::vector<u8> SerializeAddrInfo(const std::vector<Network::AddrInfo>& vec,
|
||||
std::string_view host) {
|
||||
static std::vector<u8> SerializeAddrInfo(std::span<const Network::AddrInfo> vec, std::string_view host) {
|
||||
// Adapted from
|
||||
// https://github.com/switchbrew/libnx/blob/c5a9a909a91657a9818a3b7e18c9b91ff0cbb6e3/nx/source/runtime/resolver.c#L190
|
||||
std::vector<u8> data;
|
||||
|
||||
for (const Network::AddrInfo& addrinfo : vec) {
|
||||
// serialized addrinfo:
|
||||
Append<u32_be>(data, 0xBEEFCAFE); // magic
|
||||
Append<u32_be>(data, 0); // ai_flags
|
||||
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.family))); // ai_family
|
||||
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.socket_type))); // ai_socktype
|
||||
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.protocol))); // ai_protocol
|
||||
Append<u32_be>(data, 0xBEEFCAFE); // magic
|
||||
Append<u32_be>(data, 0); // ai_flags
|
||||
Append<u32_be>(data, u32(addrinfo.family)); // ai_family
|
||||
Append<u32_be>(data, u32(addrinfo.socket_type)); // ai_socktype
|
||||
Append<u32_be>(data, u32(addrinfo.protocol)); // ai_protocol
|
||||
Append<u32_be>(data, 16); // ai_addrlen
|
||||
// ^ *not* sizeof(SerializedSockAddrIn), not that it matters since they're the same size
|
||||
|
||||
// ai_addr:
|
||||
Append<u16_be>(data, static_cast<u16>(Translate(addrinfo.addr.family))); // sin_family
|
||||
Append<u16_be>(data, u16(addrinfo.addr.family)); // sin_family
|
||||
// On the Switch, the following fields are passed through htonl despite
|
||||
// already being big-endian, so they end up as little-endian.
|
||||
Append<u16_le>(data, addrinfo.addr.portno); // sin_port
|
||||
@@ -296,7 +293,7 @@ static std::vector<u8> SerializeAddrInfo(const std::vector<Network::AddrInfo>& v
|
||||
return data;
|
||||
}
|
||||
|
||||
static std::pair<u32, GetAddrInfoError> GetAddrInfoRequestImpl(HLERequestContext& ctx) {
|
||||
static std::pair<u32, Network::GetAddrInfoError> GetAddrInfoRequestImpl(HLERequestContext& ctx) {
|
||||
struct InputParameters {
|
||||
u8 use_nsd_resolve;
|
||||
u32 cancel_handle;
|
||||
@@ -321,7 +318,7 @@ static std::pair<u32, GetAddrInfoError> GetAddrInfoRequestImpl(HLERequestContext
|
||||
// Prevent resolution of Nintendo servers
|
||||
if (IsBlockedHost(host)) {
|
||||
LOG_WARNING(Network, "Resolution of hostname {} requested, returning EAI_AGAIN", host);
|
||||
return {0, GetAddrInfoError::AGAIN};
|
||||
return {0, Network::GetAddrInfoError::AGAIN};
|
||||
}
|
||||
|
||||
std::optional<std::string> service = std::nullopt;
|
||||
@@ -331,24 +328,23 @@ static std::pair<u32, GetAddrInfoError> GetAddrInfoRequestImpl(HLERequestContext
|
||||
}
|
||||
|
||||
// Serialized hints are also passed in a buffer, but are ignored for now.
|
||||
|
||||
auto res_v = Network::GetAddressInfo(host, service);
|
||||
if (auto* res = std::get_if<std::vector<Network::AddrInfo>>(&res_v)) {
|
||||
const std::vector<u8> data = SerializeAddrInfo(*res, host);
|
||||
const u32 data_size = u32(data.size());
|
||||
ctx.WriteBuffer(data, 0);
|
||||
return {data_size, GetAddrInfoError::SUCCESS};
|
||||
return {data_size, Network::GetAddrInfoError::SUCCESS};
|
||||
}
|
||||
auto* err = std::get_if<Network::GetAddrInfoError>(&res_v);
|
||||
return {0, Translate(*err)};
|
||||
return {0, *err};
|
||||
}
|
||||
|
||||
void SFDNSRES::GetAddrInfoRequest(HLERequestContext& ctx) {
|
||||
auto [data_size, emu_gai_err] = GetAddrInfoRequestImpl(ctx);
|
||||
|
||||
struct OutputParameters {
|
||||
Errno bsd_errno;
|
||||
GetAddrInfoError gai_error;
|
||||
Network::Errno bsd_errno;
|
||||
Network::GetAddrInfoError gai_error;
|
||||
u32 data_size;
|
||||
};
|
||||
static_assert(sizeof(OutputParameters) == 0xc);
|
||||
@@ -364,7 +360,7 @@ void SFDNSRES::GetAddrInfoRequest(HLERequestContext& ctx) {
|
||||
|
||||
void SFDNSRES::GetGaiStringErrorRequest(HLERequestContext& ctx) {
|
||||
struct InputParameters {
|
||||
GetAddrInfoError gai_errno;
|
||||
Network::GetAddrInfoError gai_errno;
|
||||
};
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto input = rp.PopRaw<InputParameters>();
|
||||
@@ -382,9 +378,9 @@ void SFDNSRES::GetAddrInfoRequestWithOptions(HLERequestContext& ctx) {
|
||||
|
||||
struct OutputParameters {
|
||||
u32 data_size;
|
||||
GetAddrInfoError gai_error;
|
||||
Network::GetAddrInfoError gai_error;
|
||||
NetDbError netdb_error;
|
||||
Errno bsd_errno;
|
||||
Network::Errno bsd_errno;
|
||||
};
|
||||
static_assert(sizeof(OutputParameters) == 0x10);
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -11,7 +14,6 @@ namespace Service::Sockets {
|
||||
|
||||
void LoopProcess(Core::System& system) {
|
||||
auto server_manager = std::make_unique<ServerManager>(system);
|
||||
|
||||
server_manager->RegisterNamedService("bsd:s", std::make_shared<BSD>(system, "bsd:s"));
|
||||
server_manager->RegisterNamedService("bsd:u", std::make_shared<BSD>(system, "bsd:u"));
|
||||
server_manager->RegisterNamedService("bsdcfg", std::make_shared<BSDCFG>(system));
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
@@ -15,242 +16,6 @@ class System;
|
||||
|
||||
namespace Service::Sockets {
|
||||
|
||||
enum class Errno : u32 {
|
||||
SUCCESS = 0,
|
||||
BADF = 9,
|
||||
AGAIN = 11,
|
||||
INVAL = 22,
|
||||
MFILE = 24,
|
||||
PIPE = 32,
|
||||
MSGSIZE = 90,
|
||||
CONNABORTED = 103,
|
||||
CONNRESET = 104,
|
||||
NOTCONN = 107,
|
||||
TIMEDOUT = 110,
|
||||
CONNREFUSED = 111,
|
||||
INPROGRESS = 115,
|
||||
ISCONN = 106,
|
||||
};
|
||||
|
||||
enum class GetAddrInfoError : s32 {
|
||||
SUCCESS = 0,
|
||||
ADDRFAMILY = 1,
|
||||
AGAIN = 2,
|
||||
BADFLAGS = 3,
|
||||
FAIL = 4,
|
||||
FAMILY = 5,
|
||||
MEMORY = 6,
|
||||
NODATA = 7,
|
||||
NONAME = 8,
|
||||
SERVICE = 9,
|
||||
SOCKTYPE = 10,
|
||||
SYSTEM = 11,
|
||||
BADHINTS = 12,
|
||||
PROTOCOL = 13,
|
||||
OVERFLOW_ = 14, // avoid name collision with Windows macro
|
||||
OTHER = 15,
|
||||
};
|
||||
|
||||
enum class Domain : u32 {
|
||||
Unspecified = 0,
|
||||
INET = 2,
|
||||
};
|
||||
|
||||
enum class Type : u32 {
|
||||
Unspecified = 0,
|
||||
STREAM = 1,
|
||||
DGRAM = 2,
|
||||
RAW = 3,
|
||||
SEQPACKET = 5,
|
||||
};
|
||||
|
||||
enum class Protocol : u32 {
|
||||
IP = 0,
|
||||
ICMP = 1,
|
||||
TCP = 6,
|
||||
UDP = 17,
|
||||
//
|
||||
IPV6 = 41,
|
||||
RAW = 255,
|
||||
//
|
||||
HOPOPTS = 0,
|
||||
IGMP = 2,
|
||||
GGP = 3,
|
||||
IPV4 = 4,
|
||||
ST = 7,
|
||||
EGP = 8,
|
||||
PIGP = 9,
|
||||
RCCMON = 10,
|
||||
NVPII = 11,
|
||||
PUP = 12,
|
||||
ARGUS = 13,
|
||||
EMCON = 14,
|
||||
XNET = 15,
|
||||
CHAOS = 16,
|
||||
MUX = 18,
|
||||
MEAS = 19,
|
||||
HMP = 20,
|
||||
PRM = 21,
|
||||
IDP = 22,
|
||||
TRUNK1 = 23,
|
||||
TRUNK2 = 24,
|
||||
LEAF1 = 25,
|
||||
LEAF2 = 26,
|
||||
RDP = 27,
|
||||
IRTP = 28,
|
||||
TP = 29,
|
||||
BLT = 30,
|
||||
NSP = 31,
|
||||
INP = 32,
|
||||
DCCP = 33,
|
||||
//3PC = 34,
|
||||
IDPR = 35,
|
||||
XTP = 36,
|
||||
DDP = 37,
|
||||
CMTP = 38,
|
||||
TPXX = 39,
|
||||
IL = 40,
|
||||
SDRP = 42,
|
||||
ROUTING = 43,
|
||||
FRAGMENT = 44,
|
||||
IDRP = 45,
|
||||
RSVP = 46,
|
||||
GRE = 47,
|
||||
MHRP = 48,
|
||||
BHA = 49,
|
||||
ESP = 50,
|
||||
AH = 51,
|
||||
INLSP = 52,
|
||||
SWIPE = 53,
|
||||
NHRP = 54,
|
||||
MOBILE = 55,
|
||||
TLSP = 56,
|
||||
SKIP = 57,
|
||||
ICMPV6 = 58,
|
||||
NONE = 59,
|
||||
DSTOPTS = 60,
|
||||
AHIP = 61,
|
||||
CFTP = 62,
|
||||
HELLO = 63,
|
||||
SATEXPAK = 64,
|
||||
KRYPTOLAN = 65,
|
||||
RVD = 66,
|
||||
IPPC = 67,
|
||||
ADFS = 68,
|
||||
SATMON = 69,
|
||||
VISA = 70,
|
||||
IPCV = 71,
|
||||
CPNX = 72,
|
||||
CPHB = 73,
|
||||
WSN = 74,
|
||||
PVP = 75,
|
||||
BRSATMON = 76,
|
||||
ND = 77,
|
||||
WBMON = 78,
|
||||
WBEXPAK = 79,
|
||||
EON = 80,
|
||||
VMTP = 81,
|
||||
SVMTP = 82,
|
||||
VINES = 83,
|
||||
TTP = 84,
|
||||
IGP = 85,
|
||||
DGP = 86,
|
||||
TCF = 87,
|
||||
IGRP = 88,
|
||||
OSPFIGP = 89,
|
||||
SRPC = 90,
|
||||
LARP = 91,
|
||||
MTP = 92,
|
||||
AX25 = 93,
|
||||
IPEIP = 94,
|
||||
MICP = 95,
|
||||
SCCSP = 96,
|
||||
ETHERIP = 97,
|
||||
ENCAP = 98,
|
||||
APES = 99,
|
||||
GMTP = 100,
|
||||
IPCOMP = 108,
|
||||
SCTP = 132,
|
||||
MH = 135,
|
||||
UDPLITE = 136,
|
||||
HIP = 139,
|
||||
SHIM6 = 140,
|
||||
PIM = 103,
|
||||
CARP = 112,
|
||||
PGM = 113,
|
||||
MPLS = 137,
|
||||
PFSYNC = 240,
|
||||
};
|
||||
|
||||
enum class SocketLevel : u32 {
|
||||
IP = 0,
|
||||
TCP = 6,
|
||||
SOCKET = 0xffff, // i.e. SOL_SOCKET
|
||||
};
|
||||
|
||||
enum class OptName : u32 {
|
||||
REUSEADDR = 0x4,
|
||||
KEEPALIVE = 0x8,
|
||||
BROADCAST = 0x20,
|
||||
LINGER = 0x80,
|
||||
SNDBUF = 0x1001,
|
||||
RCVBUF = 0x1002,
|
||||
SNDTIMEO = 0x1005,
|
||||
RCVTIMEO = 0x1006,
|
||||
ERROR_ = 0x1007, // avoid name collision with Windows macro
|
||||
NOSIGPIPE = 0x800, // at least according to libnx
|
||||
ACCEPTFILTER = 0x1000,
|
||||
BINTIME = 0x2000,
|
||||
NO_OFFLOAD = 0x4000,
|
||||
NO_DDP = 0x8000,
|
||||
};
|
||||
|
||||
enum class ShutdownHow : s32 {
|
||||
RD = 0,
|
||||
WR = 1,
|
||||
RDWR = 2,
|
||||
};
|
||||
|
||||
enum class FcntlCmd : s32 {
|
||||
GETFL = 3,
|
||||
SETFL = 4,
|
||||
};
|
||||
|
||||
struct SockAddrIn {
|
||||
u8 len;
|
||||
u8 family;
|
||||
u16 portno;
|
||||
std::array<u8, 4> ip;
|
||||
std::array<u8, 248> zeroes;
|
||||
};
|
||||
static_assert(sizeof(SockAddrIn) == 0x100);
|
||||
|
||||
enum class PollEvents : u16 {
|
||||
// Using Pascal case because IN is a macro on Windows.
|
||||
In = 1 << 0,
|
||||
Pri = 1 << 1,
|
||||
Out = 1 << 2,
|
||||
Err = 1 << 3,
|
||||
Hup = 1 << 4,
|
||||
Nval = 1 << 5,
|
||||
RdNorm = 1 << 6,
|
||||
RdBand = 1 << 7,
|
||||
WrBand = 1 << 8,
|
||||
};
|
||||
|
||||
DECLARE_ENUM_FLAG_OPERATORS(PollEvents);
|
||||
|
||||
struct PollFD {
|
||||
s32 fd;
|
||||
PollEvents events;
|
||||
PollEvents revents;
|
||||
};
|
||||
|
||||
struct Linger {
|
||||
u32 onoff;
|
||||
u32 linger;
|
||||
};
|
||||
|
||||
void LoopProcess(Core::System& system);
|
||||
|
||||
} // namespace Service::Sockets
|
||||
|
||||
@@ -15,388 +15,42 @@
|
||||
|
||||
namespace Service::Sockets {
|
||||
|
||||
Errno Translate(Network::Errno value) {
|
||||
switch (value) {
|
||||
case Network::Errno::SUCCESS:
|
||||
return Errno::SUCCESS;
|
||||
case Network::Errno::BADF:
|
||||
return Errno::BADF;
|
||||
case Network::Errno::AGAIN:
|
||||
return Errno::AGAIN;
|
||||
case Network::Errno::INVAL:
|
||||
return Errno::INVAL;
|
||||
case Network::Errno::MFILE:
|
||||
return Errno::MFILE;
|
||||
case Network::Errno::PIPE:
|
||||
return Errno::PIPE;
|
||||
case Network::Errno::CONNREFUSED:
|
||||
return Errno::CONNREFUSED;
|
||||
case Network::Errno::NOTCONN:
|
||||
return Errno::NOTCONN;
|
||||
case Network::Errno::TIMEDOUT:
|
||||
return Errno::TIMEDOUT;
|
||||
case Network::Errno::CONNABORTED:
|
||||
return Errno::CONNABORTED;
|
||||
case Network::Errno::CONNRESET:
|
||||
return Errno::CONNRESET;
|
||||
case Network::Errno::INPROGRESS:
|
||||
return Errno::INPROGRESS;
|
||||
case Network::Errno::ISCONN:
|
||||
return Errno::ISCONN;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented errno={}", value);
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value) {
|
||||
return {value.first, Translate(value.second)};
|
||||
}
|
||||
|
||||
GetAddrInfoError Translate(Network::GetAddrInfoError error) {
|
||||
switch (error) {
|
||||
case Network::GetAddrInfoError::SUCCESS:
|
||||
return GetAddrInfoError::SUCCESS;
|
||||
case Network::GetAddrInfoError::ADDRFAMILY:
|
||||
return GetAddrInfoError::ADDRFAMILY;
|
||||
case Network::GetAddrInfoError::AGAIN:
|
||||
return GetAddrInfoError::AGAIN;
|
||||
case Network::GetAddrInfoError::BADFLAGS:
|
||||
return GetAddrInfoError::BADFLAGS;
|
||||
case Network::GetAddrInfoError::FAIL:
|
||||
return GetAddrInfoError::FAIL;
|
||||
case Network::GetAddrInfoError::FAMILY:
|
||||
return GetAddrInfoError::FAMILY;
|
||||
case Network::GetAddrInfoError::MEMORY:
|
||||
return GetAddrInfoError::MEMORY;
|
||||
case Network::GetAddrInfoError::NODATA:
|
||||
return GetAddrInfoError::NODATA;
|
||||
case Network::GetAddrInfoError::NONAME:
|
||||
return GetAddrInfoError::NONAME;
|
||||
case Network::GetAddrInfoError::SERVICE:
|
||||
return GetAddrInfoError::SERVICE;
|
||||
case Network::GetAddrInfoError::SOCKTYPE:
|
||||
return GetAddrInfoError::SOCKTYPE;
|
||||
case Network::GetAddrInfoError::SYSTEM:
|
||||
return GetAddrInfoError::SYSTEM;
|
||||
case Network::GetAddrInfoError::BADHINTS:
|
||||
return GetAddrInfoError::BADHINTS;
|
||||
case Network::GetAddrInfoError::PROTOCOL:
|
||||
return GetAddrInfoError::PROTOCOL;
|
||||
case Network::GetAddrInfoError::OVERFLOW_:
|
||||
return GetAddrInfoError::OVERFLOW_;
|
||||
case Network::GetAddrInfoError::OTHER:
|
||||
return GetAddrInfoError::OTHER;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented GetAddrInfoError={}", error);
|
||||
return GetAddrInfoError::OTHER;
|
||||
}
|
||||
}
|
||||
|
||||
const char* Translate(GetAddrInfoError error) {
|
||||
const char* Translate(Network::GetAddrInfoError error) {
|
||||
// https://android.googlesource.com/platform/bionic/+/085543106/libc/dns/net/getaddrinfo.c#254
|
||||
switch (error) {
|
||||
case GetAddrInfoError::SUCCESS:
|
||||
case Network::GetAddrInfoError::SUCCESS:
|
||||
return "Success";
|
||||
case GetAddrInfoError::ADDRFAMILY:
|
||||
case Network::GetAddrInfoError::ADDRFAMILY:
|
||||
return "Address family for hostname not supported";
|
||||
case GetAddrInfoError::AGAIN:
|
||||
case Network::GetAddrInfoError::AGAIN:
|
||||
return "Temporary failure in name resolution";
|
||||
case GetAddrInfoError::BADFLAGS:
|
||||
case Network::GetAddrInfoError::BADFLAGS:
|
||||
return "Invalid value for ai_flags";
|
||||
case GetAddrInfoError::FAIL:
|
||||
case Network::GetAddrInfoError::FAIL:
|
||||
return "Non-recoverable failure in name resolution";
|
||||
case GetAddrInfoError::FAMILY:
|
||||
case Network::GetAddrInfoError::FAMILY:
|
||||
return "ai_family not supported";
|
||||
case GetAddrInfoError::MEMORY:
|
||||
case Network::GetAddrInfoError::MEMORY:
|
||||
return "Memory allocation failure";
|
||||
case GetAddrInfoError::NODATA:
|
||||
case Network::GetAddrInfoError::NODATA:
|
||||
return "No address associated with hostname";
|
||||
case GetAddrInfoError::NONAME:
|
||||
case Network::GetAddrInfoError::NONAME:
|
||||
return "hostname nor servname provided, or not known";
|
||||
case GetAddrInfoError::SERVICE:
|
||||
case Network::GetAddrInfoError::SERVICE:
|
||||
return "servname not supported for ai_socktype";
|
||||
case GetAddrInfoError::SOCKTYPE:
|
||||
case Network::GetAddrInfoError::SOCKTYPE:
|
||||
return "ai_socktype not supported";
|
||||
case GetAddrInfoError::SYSTEM:
|
||||
case Network::GetAddrInfoError::SYSTEM:
|
||||
return "System error returned in errno";
|
||||
case GetAddrInfoError::BADHINTS:
|
||||
case Network::GetAddrInfoError::BADHINTS:
|
||||
return "Invalid value for hints";
|
||||
case GetAddrInfoError::PROTOCOL:
|
||||
case Network::GetAddrInfoError::PROTOCOL:
|
||||
return "Resolved protocol is unknown";
|
||||
case GetAddrInfoError::OVERFLOW_:
|
||||
case Network::GetAddrInfoError::OVERFLOW_:
|
||||
return "Argument buffer overflow";
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
Network::Domain Translate(Domain domain) {
|
||||
switch (domain) {
|
||||
case Domain::Unspecified:
|
||||
return Network::Domain::Unspecified;
|
||||
case Domain::INET:
|
||||
return Network::Domain::INET;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented domain={}", domain);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Domain Translate(Network::Domain domain) {
|
||||
switch (domain) {
|
||||
case Network::Domain::Unspecified:
|
||||
return Domain::Unspecified;
|
||||
case Network::Domain::INET:
|
||||
return Domain::INET;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented domain={}", domain);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Network::Type Translate(Type type) {
|
||||
switch (type) {
|
||||
case Type::Unspecified:
|
||||
return Network::Type::Unspecified;
|
||||
case Type::STREAM:
|
||||
return Network::Type::STREAM;
|
||||
case Type::DGRAM:
|
||||
return Network::Type::DGRAM;
|
||||
case Type::RAW:
|
||||
return Network::Type::RAW;
|
||||
case Type::SEQPACKET:
|
||||
return Network::Type::SEQPACKET;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented type={}", type);
|
||||
return Network::Type{};
|
||||
}
|
||||
}
|
||||
|
||||
Type Translate(Network::Type type) {
|
||||
switch (type) {
|
||||
case Network::Type::Unspecified: return Type::Unspecified;
|
||||
case Network::Type::STREAM: return Type::STREAM;
|
||||
case Network::Type::DGRAM: return Type::DGRAM;
|
||||
case Network::Type::RAW: return Type::RAW;
|
||||
case Network::Type::SEQPACKET: return Type::SEQPACKET;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented type={}", type);
|
||||
return Type{};
|
||||
}
|
||||
}
|
||||
|
||||
#define NETWORK_PROTOCOL_TRANSLATE_LIST \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ICMP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TCP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(UDP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IPV6) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(RAW) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IGMP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(GGP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IPV4) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ST) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(EGP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PIGP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(RCCMON) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(NVPII) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PUP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ARGUS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(EMCON) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(XNET) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(CHAOS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MUX) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MEAS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(HMP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PRM) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IDP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TRUNK1) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TRUNK2) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(LEAF1) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(LEAF2) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(RDP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IRTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(BLT) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(NSP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(INP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(DCCP) \
|
||||
/*NETWORK_PROTOCOL_TRANSLATE_ELEM(3PC)*/ \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IDPR) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(XTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(DDP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(CMTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TPXX) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IL) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SDRP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ROUTING) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(FRAGMENT) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IDRP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(RSVP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(GRE) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MHRP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(BHA) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ESP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(AH) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(INLSP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SWIPE) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(NHRP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MOBILE) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TLSP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SKIP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ICMPV6) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(NONE) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(DSTOPTS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(AHIP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(CFTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(HELLO) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SATEXPAK) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(KRYPTOLAN) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(RVD) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IPPC) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ADFS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SATMON) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(VISA) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IPCV) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(CPNX) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(CPHB) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(WSN) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PVP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(BRSATMON) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ND) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(WBMON) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(WBEXPAK) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(EON) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(VMTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SVMTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(VINES) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IGP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(DGP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(TCF) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IGRP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(OSPFIGP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SRPC) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(LARP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(AX25) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IPEIP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MICP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SCCSP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ETHERIP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(ENCAP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(APES) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(GMTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(IPCOMP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SCTP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MH) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(UDPLITE) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(HIP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(SHIM6) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PIM) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(CARP) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PGM) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(MPLS) \
|
||||
NETWORK_PROTOCOL_TRANSLATE_ELEM(PFSYNC)
|
||||
[[nodiscard]] Network::Protocol Translate(Protocol protocol) {
|
||||
switch (protocol) {
|
||||
#define NETWORK_PROTOCOL_TRANSLATE_ELEM(name) case Protocol::name: return Network::Protocol::name;
|
||||
NETWORK_PROTOCOL_TRANSLATE_LIST
|
||||
#undef NETWORK_PROTOCOL_TRANSLATE_ELEM
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented protocol={}", protocol);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
[[nodiscard]] Protocol Translate(Network::Protocol protocol) {
|
||||
switch (protocol) {
|
||||
#define NETWORK_PROTOCOL_TRANSLATE_ELEM(name) case Network::Protocol::name: return Protocol::name;
|
||||
NETWORK_PROTOCOL_TRANSLATE_LIST
|
||||
#undef NETWORK_PROTOCOL_TRANSLATE_ELEM
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented protocol={}", protocol);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
#undef NETWORK_PROTOCOL_TRANSLATE_LIST
|
||||
|
||||
Network::PollEvents Translate(PollEvents flags) {
|
||||
Network::PollEvents result{};
|
||||
const auto translate = [&result, &flags](PollEvents from, Network::PollEvents to) {
|
||||
if (True(flags & from)) {
|
||||
flags &= ~from;
|
||||
result |= to;
|
||||
}
|
||||
};
|
||||
translate(PollEvents::In, Network::PollEvents::In);
|
||||
translate(PollEvents::Pri, Network::PollEvents::Pri);
|
||||
translate(PollEvents::Out, Network::PollEvents::Out);
|
||||
translate(PollEvents::Err, Network::PollEvents::Err);
|
||||
translate(PollEvents::Hup, Network::PollEvents::Hup);
|
||||
translate(PollEvents::Nval, Network::PollEvents::Nval);
|
||||
translate(PollEvents::RdNorm, Network::PollEvents::RdNorm);
|
||||
translate(PollEvents::RdBand, Network::PollEvents::RdBand);
|
||||
translate(PollEvents::WrBand, Network::PollEvents::WrBand);
|
||||
|
||||
UNIMPLEMENTED_IF_MSG((u16)flags != 0, "Unimplemented flags={}", (u16)flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
PollEvents Translate(Network::PollEvents flags) {
|
||||
PollEvents result{};
|
||||
const auto translate = [&result, &flags](Network::PollEvents from, PollEvents to) {
|
||||
if (True(flags & from)) {
|
||||
flags &= ~from;
|
||||
result |= to;
|
||||
}
|
||||
};
|
||||
|
||||
translate(Network::PollEvents::In, PollEvents::In);
|
||||
translate(Network::PollEvents::Pri, PollEvents::Pri);
|
||||
translate(Network::PollEvents::Out, PollEvents::Out);
|
||||
translate(Network::PollEvents::Err, PollEvents::Err);
|
||||
translate(Network::PollEvents::Hup, PollEvents::Hup);
|
||||
translate(Network::PollEvents::Nval, PollEvents::Nval);
|
||||
translate(Network::PollEvents::RdNorm, PollEvents::RdNorm);
|
||||
translate(Network::PollEvents::RdBand, PollEvents::RdBand);
|
||||
translate(Network::PollEvents::WrBand, PollEvents::WrBand);
|
||||
|
||||
UNIMPLEMENTED_IF_MSG((u16)flags != 0, "Unimplemented flags={}", (u16)flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
Network::SockAddrIn Translate(SockAddrIn value) {
|
||||
// All lengths are valid, from [0 upto 256]
|
||||
return {
|
||||
.family = Translate(Domain(value.family)),
|
||||
.ip = value.ip,
|
||||
.portno = static_cast<u16>(value.portno >> 8 | value.portno << 8),
|
||||
};
|
||||
}
|
||||
|
||||
SockAddrIn Translate(Network::SockAddrIn value) {
|
||||
return {
|
||||
.len = 16,
|
||||
.family = static_cast<u8>(Translate(value.family)),
|
||||
.portno = static_cast<u16>(value.portno >> 8 | value.portno << 8),
|
||||
.ip = value.ip,
|
||||
.zeroes = {},
|
||||
};
|
||||
}
|
||||
|
||||
Network::ShutdownHow Translate(ShutdownHow how) {
|
||||
switch (how) {
|
||||
case ShutdownHow::RD:
|
||||
return Network::ShutdownHow::RD;
|
||||
case ShutdownHow::WR:
|
||||
return Network::ShutdownHow::WR;
|
||||
case ShutdownHow::RDWR:
|
||||
return Network::ShutdownHow::RDWR;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented how={}", how);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::Sockets
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -11,49 +14,7 @@
|
||||
|
||||
namespace Service::Sockets {
|
||||
|
||||
/// Translate abstract errno to guest errno
|
||||
Errno Translate(Network::Errno value);
|
||||
|
||||
/// Translate abstract return value errno pair to guest return value errno pair
|
||||
std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value);
|
||||
|
||||
/// Translate abstract getaddrinfo error to guest getaddrinfo error
|
||||
GetAddrInfoError Translate(Network::GetAddrInfoError value);
|
||||
|
||||
/// Translate guest error to string
|
||||
const char* Translate(GetAddrInfoError value);
|
||||
|
||||
/// Translate guest domain to abstract domain
|
||||
Network::Domain Translate(Domain domain);
|
||||
|
||||
/// Translate abstract domain to guest domain
|
||||
Domain Translate(Network::Domain domain);
|
||||
|
||||
/// Translate guest type to abstract type
|
||||
Network::Type Translate(Type type);
|
||||
|
||||
/// Translate abstract type to guest type
|
||||
Type Translate(Network::Type type);
|
||||
|
||||
/// Translate guest protocol to abstract protocol
|
||||
Network::Protocol Translate(Protocol protocol);
|
||||
|
||||
/// Translate abstract protocol to guest protocol
|
||||
Protocol Translate(Network::Protocol protocol);
|
||||
|
||||
/// Translate guest poll event flags to abstract poll event flags
|
||||
Network::PollEvents Translate(PollEvents flags);
|
||||
|
||||
/// Translate abstract poll event flags to guest poll event flags
|
||||
PollEvents Translate(Network::PollEvents flags);
|
||||
|
||||
/// Translate guest socket address structure to abstract socket address structure
|
||||
Network::SockAddrIn Translate(SockAddrIn value);
|
||||
|
||||
/// Translate abstract socket address structure to guest socket address structure
|
||||
SockAddrIn Translate(Network::SockAddrIn value);
|
||||
|
||||
/// Translate guest shutdown mode to abstract shutdown mode
|
||||
Network::ShutdownHow Translate(ShutdownHow how);
|
||||
const char* Translate(Network::GetAddrInfoError value);
|
||||
|
||||
} // namespace Service::Sockets
|
||||
|
||||
@@ -132,7 +132,7 @@ public:
|
||||
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u");
|
||||
if (bsd) {
|
||||
auto err = bsd->CloseImpl(fd);
|
||||
if (err != Service::Sockets::Errno::SUCCESS) {
|
||||
if (err != Network::Errno::SUCCESS) {
|
||||
LOG_ERROR(Service_SSL, "Failed to close duplicated socket: {}", err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <common/socket_types.h>
|
||||
#include <mutex>
|
||||
#include "core/internal_network/socket_types.h"
|
||||
|
||||
namespace Network {
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
@@ -31,68 +31,10 @@ namespace Network {
|
||||
class SocketBase;
|
||||
class Socket;
|
||||
|
||||
/// Error code for network functions
|
||||
enum class Errno {
|
||||
SUCCESS,
|
||||
BADF,
|
||||
INVAL,
|
||||
MFILE,
|
||||
PIPE,
|
||||
NOTCONN,
|
||||
AGAIN,
|
||||
CONNREFUSED,
|
||||
CONNRESET,
|
||||
CONNABORTED,
|
||||
HOSTUNREACH,
|
||||
NETDOWN,
|
||||
NETUNREACH,
|
||||
TIMEDOUT,
|
||||
MSGSIZE,
|
||||
INPROGRESS,
|
||||
ISCONN,
|
||||
OTHER,
|
||||
};
|
||||
|
||||
enum class GetAddrInfoError {
|
||||
SUCCESS,
|
||||
ADDRFAMILY,
|
||||
AGAIN,
|
||||
BADFLAGS,
|
||||
FAIL,
|
||||
FAMILY,
|
||||
MEMORY,
|
||||
NODATA,
|
||||
NONAME,
|
||||
SERVICE,
|
||||
SOCKTYPE,
|
||||
SYSTEM,
|
||||
BADHINTS,
|
||||
PROTOCOL,
|
||||
OVERFLOW_,
|
||||
OTHER,
|
||||
};
|
||||
|
||||
/// Cross-platform poll fd structure
|
||||
|
||||
enum class PollEvents : u16 {
|
||||
// Using Pascal case because IN is a macro on Windows.
|
||||
In = 1 << 0,
|
||||
Pri = 1 << 1,
|
||||
Out = 1 << 2,
|
||||
Err = 1 << 3,
|
||||
Hup = 1 << 4,
|
||||
Nval = 1 << 5,
|
||||
RdNorm = 1 << 6,
|
||||
RdBand = 1 << 7,
|
||||
WrBand = 1 << 8,
|
||||
};
|
||||
|
||||
DECLARE_ENUM_FLAG_OPERATORS(PollEvents);
|
||||
|
||||
struct PollFD {
|
||||
SocketBase* socket;
|
||||
PollEvents events;
|
||||
PollEvents revents;
|
||||
struct HostPollFD {
|
||||
SocketBase* socket = nullptr;
|
||||
Network::PollEvents events = {};
|
||||
Network::PollEvents revents = {};
|
||||
};
|
||||
|
||||
class NetworkInstance {
|
||||
@@ -101,6 +43,10 @@ public:
|
||||
~NetworkInstance();
|
||||
};
|
||||
|
||||
sockaddr_in TranslateFromSockAddrIn(Network::SockAddrIn input);
|
||||
Network::SockAddrIn TranslateToSockAddrIn(sockaddr_in input);
|
||||
s32 TranslateMsgOptToNative(s32 flags);
|
||||
|
||||
void CancelPendingSocketOperations();
|
||||
void RestartSocketOperations();
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace Network {
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
|
||||
ULONG buf_size = 0;
|
||||
if (GetAdaptersAddresses(
|
||||
@@ -66,7 +66,7 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<Network::NetworkInterface> result;
|
||||
std::vector<NetworkInterface> result;
|
||||
|
||||
for (auto* a = addrs; a; a = a->Next) {
|
||||
|
||||
@@ -89,7 +89,7 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
gw = reinterpret_cast<sockaddr_in*>(a->FirstGatewayAddress->Address.lpSockaddr)
|
||||
->sin_addr;
|
||||
|
||||
result.emplace_back(Network::NetworkInterface{
|
||||
result.emplace_back(NetworkInterface{
|
||||
.name = Common::UTF16ToUTF8(std::wstring{a->FriendlyName}),
|
||||
.ip_address = ip,
|
||||
.subnet_mask = mask,
|
||||
@@ -103,7 +103,7 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
|
||||
#else
|
||||
|
||||
std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
#if defined(__ANDROID__) || defined(__linux__)
|
||||
struct ifaddrs* ifaddr = nullptr;
|
||||
if (getifaddrs(&ifaddr) != 0) {
|
||||
@@ -135,7 +135,7 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
LOG_WARNING(Network, "\"/proc/net/route\" not found - using gateway 0");
|
||||
}
|
||||
#endif
|
||||
std::vector<Network::NetworkInterface> ifaces;
|
||||
std::vector<NetworkInterface> ifaces;
|
||||
for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
|
||||
if (ifa->ifa_addr == nullptr || ifa->ifa_netmask == nullptr /* Have a netmask and address */
|
||||
|| ifa->ifa_addr->sa_family != AF_INET /* Must be of kind AF_INET */
|
||||
@@ -149,7 +149,7 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
});
|
||||
in_addr gw; // Solaris defines s_addr as a macro, can't use special C++ shenanigans here
|
||||
gw.s_addr = it != routes.end() ? it->gateway : 0;
|
||||
ifaces.emplace_back(Network::NetworkInterface{
|
||||
ifaces.emplace_back(NetworkInterface{
|
||||
.name = ifa->ifa_name,
|
||||
.ip_address = std::bit_cast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr,
|
||||
.subnet_mask = std::bit_cast<struct sockaddr_in>(*ifa->ifa_netmask).sin_addr,
|
||||
@@ -159,7 +159,7 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
freeifaddrs(ifaddr);
|
||||
return ifaces;
|
||||
#elif defined(__FreeBSD__)
|
||||
std::vector<Network::NetworkInterface> ifaces;
|
||||
std::vector<NetworkInterface> ifaces;
|
||||
int fd = ::socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
|
||||
if (fd < 0) {
|
||||
LOG_ERROR(Network, "socket: {}", std::strerror(errno));
|
||||
@@ -191,7 +191,7 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
size_t msglen = rtm->rtm_msglen - sizeof(*ifm);
|
||||
char const* p = (char const*)(ifm + 1);
|
||||
|
||||
Network::NetworkInterface iface{};
|
||||
NetworkInterface iface{};
|
||||
for (size_t i = 0; i < RTAX_MAX; i++)
|
||||
if ((ifm->ifm_addrs & (1 << i)) != 0) {
|
||||
struct sockaddr const* sa = reinterpret_cast<struct sockaddr const*>(p);
|
||||
@@ -220,7 +220,7 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
std::optional<Network::NetworkInterface> GetSelectedNetworkInterface() {
|
||||
std::optional<NetworkInterface> GetSelectedNetworkInterface() {
|
||||
auto const& sel_if = Settings::values.network_interface.GetValue();
|
||||
if (auto const ifaces = Network::GetAvailableNetworkInterfaces(); ifaces.size() > 0) {
|
||||
if (sel_if.empty())
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <cstdio>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging.h"
|
||||
#include "core/internal_network/socket_icmp.h"
|
||||
|
||||
#ifdef __unix__
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
namespace Network {
|
||||
|
||||
namespace {
|
||||
|
||||
u16 ComputeChecksum(std::span<const u8> data) {
|
||||
u32 sum = 0;
|
||||
for (size_t i = 0; i < data.size(); i += 2) {
|
||||
u32 value = (u32(data[i + 0]) << 8ull) | u32(data[i + 1]); //big endian
|
||||
sum += value;
|
||||
}
|
||||
if (data.size() % 2 != 0){
|
||||
sum += u16(data[data.size() - 1]) << 8;
|
||||
}
|
||||
while ((sum >> 16) != 0)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
return (~sum) & 0xffff;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
IcmpSocket::IcmpSocket() noexcept {}
|
||||
|
||||
IcmpSocket::~IcmpSocket() {
|
||||
if (fd == INVALID_SOCKET) {
|
||||
return;
|
||||
}
|
||||
fd = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
Errno IcmpSocket::SetSockOpt(Network::SocketLevel level, Network::OptName optname, std::span<const u8> optval) {
|
||||
LOG_WARNING(Network, "(stubbed) level={},optname={},optval={}", level, optname, optval.size());
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Errno IcmpSocket::Initialize(Domain domain, Type type, Protocol socket_protocol) {
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<IcmpSocket::AcceptResult, Errno> IcmpSocket::Accept() {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return {AcceptResult{}, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
Errno IcmpSocket::Connect(Network::SockAddrIn addr_in) {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<Network::SockAddrIn, Errno> IcmpSocket::GetPeerName() {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return {Network::SockAddrIn{}, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
std::pair<Network::SockAddrIn, Errno> IcmpSocket::GetSockName() {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return {Network::SockAddrIn{}, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
Errno IcmpSocket::Bind(Network::SockAddrIn addr) {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Errno IcmpSocket::Listen(s32 backlog) {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Errno IcmpSocket::Shutdown(ShutdownHow how) {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> IcmpSocket::Recv(int flags, std::span<u8> message) {
|
||||
LOG_DEBUG(Network, "(stubbed) called");
|
||||
return {s32(0), Errno::NOTCONN};
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> IcmpSocket::RecvFrom(int flags, std::span<u8> message, Network::SockAddrIn* addr) {
|
||||
LOG_DEBUG(Network, "(stubbed) called");
|
||||
ASSERT(flags == 0);
|
||||
ASSERT(message.size() < std::size_t((std::numeric_limits<int>::max)()));
|
||||
#ifdef __unix__
|
||||
if (addr) {
|
||||
if (seq_ident.empty())
|
||||
return {0, Errno::SUCCESS};
|
||||
// PLEASE DON'T KILL ME, I SWEAR THIS IS LEGITIMATELY THE BEST WAY TO DO IT
|
||||
// IF YOU OPEN socket() GOOGLE WILL STRAIGHT UP IP BAN YOU AFTER 2 HOURS
|
||||
auto const cmd = fmt::format("ping -t 3 -o {}.{}.{}.{}", addr->ip[0], addr->ip[1], addr->ip[2], addr->ip[3]);
|
||||
if (::system(cmd.c_str()) == 0) {
|
||||
std::vector<u8> data{
|
||||
8,
|
||||
0,
|
||||
0, //checksum
|
||||
0,
|
||||
u8(seq_ident.front() >> 24), //ident
|
||||
u8(seq_ident.front() >> 16),
|
||||
u8(seq_ident.front() >> 8), // seq
|
||||
u8(seq_ident.front() >> 0),
|
||||
};
|
||||
seq_ident.pop_back();
|
||||
auto const csum = ComputeChecksum(std::span<const u8>{data.begin(), data.end()});
|
||||
data[2] = u8(csum >> 8); //hi
|
||||
data[3] = u8(csum); //lo
|
||||
auto const n = (std::max)(data.size(), message.size());
|
||||
std::copy(data.begin(), data.begin() + n, message.begin());
|
||||
return {n, Errno::SUCCESS};
|
||||
}
|
||||
return {-1, Errno::TIMEDOUT};
|
||||
}
|
||||
#endif
|
||||
return {-1, Errno::INVAL};
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> IcmpSocket::Send(std::span<const u8> message, int flags) {
|
||||
LOG_DEBUG(Network, "(stubbed) called");
|
||||
seq_ident.push_back(
|
||||
(u32(message[4]) << 24)
|
||||
| (u32(message[5]) << 16)
|
||||
| (u32(message[6]) << 8)
|
||||
| (u32(message[7]) << 0)
|
||||
);
|
||||
return {s32(0), Errno::NOTCONN};
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> IcmpSocket::SendTo(u32 flags, std::span<const u8> message, const Network::SockAddrIn* addr) {
|
||||
LOG_DEBUG(Network, "(stubbed) called");
|
||||
ASSERT(message.size() < size_t((std::numeric_limits<int>::max)()));
|
||||
// 0 -> 8 (IPv4), 128 (IPv6)
|
||||
// 1 -> 0
|
||||
// 2..4 -> checksum
|
||||
// 4..6 -> ident
|
||||
// 6..8 -> seq
|
||||
if (!message.empty())
|
||||
return {s32(message.size()), Errno::SUCCESS};
|
||||
return {-1, Errno::INVAL};
|
||||
}
|
||||
|
||||
Errno IcmpSocket::Close() {
|
||||
LOG_DEBUG(Network, "called");
|
||||
fd = INVALID_SOCKET;
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<Errno, Errno> IcmpSocket::GetPendingError() {
|
||||
LOG_DEBUG(Network, "called");
|
||||
return {Errno::SUCCESS, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
bool IcmpSocket::IsOpened() const {
|
||||
return fd != INVALID_SOCKET;
|
||||
}
|
||||
|
||||
void IcmpSocket::HandleProxyPacket(const ProxyPacket& packet) {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
}
|
||||
Errno IcmpSocket::SetNonBlock(bool enable) {
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace Network
|
||||
@@ -0,0 +1,37 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include "core/internal_network/sockets.h"
|
||||
|
||||
namespace Network {
|
||||
|
||||
class IcmpSocket : public Network::SocketBase {
|
||||
public:
|
||||
explicit IcmpSocket() noexcept;
|
||||
~IcmpSocket() override;
|
||||
Errno Initialize(Domain domain, Type type, Protocol socket_protocol) override;
|
||||
Errno Close() override;
|
||||
std::pair<AcceptResult, Errno> Accept() override;
|
||||
Errno Connect(Network::SockAddrIn addr_in) override;
|
||||
std::pair<Network::SockAddrIn, Errno> GetPeerName() override;
|
||||
std::pair<Network::SockAddrIn, Errno> GetSockName() override;
|
||||
Errno Bind(Network::SockAddrIn addr) override;
|
||||
Errno Listen(s32 backlog) override;
|
||||
Errno Shutdown(ShutdownHow how) override;
|
||||
std::pair<s32, Errno> Recv(int flags, std::span<u8> message) override;
|
||||
std::pair<s32, Errno> RecvFrom(int flags, std::span<u8> message, Network::SockAddrIn* addr) override;
|
||||
std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override;
|
||||
std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message, const Network::SockAddrIn* addr) override;
|
||||
Errno SetSockOpt(Network::SocketLevel level, Network::OptName option, std::span<const u8> value) override;
|
||||
std::pair<Errno, Errno> GetPendingError() override;
|
||||
bool IsOpened() const override;
|
||||
void HandleProxyPacket(const ProxyPacket& packet) override;
|
||||
Errno SetNonBlock(bool enable) override;
|
||||
|
||||
std::vector<u32> seq_ident;
|
||||
};
|
||||
|
||||
} // namespace Network
|
||||
@@ -47,71 +47,82 @@ void ProxySocket::HandleProxyPacket(const ProxyPacket& packet) {
|
||||
received_packets.push(decompressed);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Errno ProxySocket::SetSockOpt(SOCKET fd_, int option, T value) {
|
||||
LOG_DEBUG(Network, "(STUBBED) called");
|
||||
Errno ProxySocket::SetNonBlock(bool enable) {
|
||||
blocking = !enable;
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetSockOpt(Network::SocketLevel level, Network::OptName optname, std::span<const u8> optval) {
|
||||
LOG_DEBUG(Network, "level={},optname={},optval={}", level, optname, optval.size());
|
||||
// numeric values?
|
||||
if (optval.size() >= sizeof(u32)) {
|
||||
u32 value;
|
||||
std::memcpy(&value, optval.data(), sizeof(value));
|
||||
if (optname == Network::OptName::BROADCAST)
|
||||
broadcast = bool(value);
|
||||
if (optname == Network::OptName::SNDTIMEO)
|
||||
send_timeout = value;
|
||||
if (optname == Network::OptName::RCVTIMEO)
|
||||
receive_timeout = value;
|
||||
}
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Errno ProxySocket::Initialize(Domain domain, Type type, Protocol socket_protocol) {
|
||||
protocol = socket_protocol;
|
||||
SetSockOpt(fd, SO_TYPE, type);
|
||||
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<ProxySocket::AcceptResult, Errno> ProxySocket::Accept() {
|
||||
LOG_WARNING(Network, "(STUBBED) called");
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return {AcceptResult{}, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
Errno ProxySocket::Connect(SockAddrIn addr_in) {
|
||||
LOG_WARNING(Network, "(STUBBED) called");
|
||||
Errno ProxySocket::Connect(Network::SockAddrIn addr_in) {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<SockAddrIn, Errno> ProxySocket::GetPeerName() {
|
||||
LOG_WARNING(Network, "(STUBBED) called");
|
||||
return {SockAddrIn{}, Errno::SUCCESS};
|
||||
std::pair<Network::SockAddrIn, Errno> ProxySocket::GetPeerName() {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return {Network::SockAddrIn{}, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
std::pair<SockAddrIn, Errno> ProxySocket::GetSockName() {
|
||||
LOG_WARNING(Network, "(STUBBED) called");
|
||||
return {SockAddrIn{}, Errno::SUCCESS};
|
||||
std::pair<Network::SockAddrIn, Errno> ProxySocket::GetSockName() {
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return {Network::SockAddrIn{}, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
Errno ProxySocket::Bind(SockAddrIn addr) {
|
||||
Errno ProxySocket::Bind(Network::SockAddrIn addr) {
|
||||
if (is_bound) {
|
||||
LOG_WARNING(Network, "Rebinding Socket is unimplemented!");
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
local_endpoint = addr;
|
||||
is_bound = true;
|
||||
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Errno ProxySocket::Listen(s32 backlog) {
|
||||
LOG_WARNING(Network, "(STUBBED) called");
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Errno ProxySocket::Shutdown(ShutdownHow how) {
|
||||
LOG_WARNING(Network, "(STUBBED) called");
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> ProxySocket::Recv(int flags, std::span<u8> message) {
|
||||
LOG_WARNING(Network, "(STUBBED) called");
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
ASSERT(flags == 0);
|
||||
ASSERT(message.size() < static_cast<size_t>((std::numeric_limits<int>::max)()));
|
||||
|
||||
return {static_cast<s32>(0), Errno::SUCCESS};
|
||||
ASSERT(message.size() < std::size_t((std::numeric_limits<int>::max)()));
|
||||
return {s32(0), Errno::SUCCESS};
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> ProxySocket::RecvFrom(int flags, std::span<u8> message, SockAddrIn* addr) {
|
||||
std::pair<s32, Errno> ProxySocket::RecvFrom(int flags, std::span<u8> message, Network::SockAddrIn* addr) {
|
||||
ASSERT(flags == 0);
|
||||
ASSERT(message.size() < static_cast<size_t>((std::numeric_limits<int>::max)()));
|
||||
ASSERT(message.size() < std::size_t((std::numeric_limits<int>::max)()));
|
||||
|
||||
// TODO (flTobi): Verify the timeout behavior and break when connection is lost
|
||||
const auto timestamp = std::chrono::steady_clock::now();
|
||||
@@ -134,29 +145,29 @@ std::pair<s32, Errno> ProxySocket::RecvFrom(int flags, std::span<u8> message, So
|
||||
std::this_thread::yield();
|
||||
|
||||
const auto time_diff = std::chrono::steady_clock::now() - timestamp;
|
||||
const auto time_diff_ms =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(time_diff).count();
|
||||
|
||||
const auto time_diff_ms = std::chrono::duration_cast<std::chrono::milliseconds>(time_diff).count();
|
||||
if (time_diff_ms > timeout) {
|
||||
return {-1, Errno::TIMEDOUT};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> ProxySocket::ReceivePacket(int flags, std::span<u8> message, SockAddrIn* addr,
|
||||
std::size_t max_length) {
|
||||
std::pair<s32, Errno> ProxySocket::ReceivePacket(int flags, std::span<u8> message, Network::SockAddrIn* addr, std::size_t max_length) {
|
||||
LOG_DEBUG(Network, "called");
|
||||
ProxyPacket& packet = received_packets.front();
|
||||
if (addr) {
|
||||
addr->family = Domain::INET;
|
||||
addr->len = 16;
|
||||
addr->family = u8(Network::Domain::INET);
|
||||
addr->ip = packet.local_endpoint.ip; // The senders ip address
|
||||
addr->portno = packet.local_endpoint.portno; // The senders port number
|
||||
addr->zeroes = {};
|
||||
}
|
||||
|
||||
bool peek = (flags & FLAG_MSG_PEEK) != 0;
|
||||
bool peek = (flags & u32(Network::MsgOpt::PEEK)) != 0;
|
||||
std::size_t read_bytes;
|
||||
if (packet.data.size() > max_length) {
|
||||
read_bytes = max_length;
|
||||
memcpy(message.data(), packet.data.data(), max_length);
|
||||
std::memcpy(message.data(), packet.data.data(), max_length);
|
||||
|
||||
if (protocol == Protocol::UDP) {
|
||||
if (!peek) {
|
||||
@@ -165,51 +176,48 @@ std::pair<s32, Errno> ProxySocket::ReceivePacket(int flags, std::span<u8> messag
|
||||
return {-1, Errno::MSGSIZE};
|
||||
} else if (protocol == Protocol::TCP) {
|
||||
std::vector<u8> numArray(packet.data.size() - max_length);
|
||||
std::copy(packet.data.begin() + max_length, packet.data.end(),
|
||||
std::back_inserter(numArray));
|
||||
std::copy(packet.data.begin() + max_length, packet.data.end(), std::back_inserter(numArray));
|
||||
packet.data = numArray;
|
||||
}
|
||||
} else {
|
||||
read_bytes = packet.data.size();
|
||||
memcpy(message.data(), packet.data.data(), read_bytes);
|
||||
std::memcpy(message.data(), packet.data.data(), read_bytes);
|
||||
if (!peek) {
|
||||
received_packets.pop();
|
||||
}
|
||||
}
|
||||
|
||||
return {static_cast<u32>(read_bytes), Errno::SUCCESS};
|
||||
return {u32(read_bytes), Errno::SUCCESS};
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> ProxySocket::Send(std::span<const u8> message, int flags) {
|
||||
LOG_WARNING(Network, "(STUBBED) called");
|
||||
ASSERT(message.size() < static_cast<size_t>((std::numeric_limits<int>::max)()));
|
||||
LOG_WARNING(Network, "(stubbed) called");
|
||||
ASSERT(message.size() < size_t((std::numeric_limits<int>::max)()));
|
||||
ASSERT(flags == 0);
|
||||
|
||||
return {static_cast<s32>(0), Errno::SUCCESS};
|
||||
return {s32(0), Errno::SUCCESS};
|
||||
}
|
||||
|
||||
void ProxySocket::SendPacket(ProxyPacket& packet) {
|
||||
if (auto room_member = Network::GetRoomMember().lock()) {
|
||||
if (room_member->IsConnected()) {
|
||||
packet.data = Common::Compression::CompressDataZSTDDefault(packet.data.data(),
|
||||
packet.data.size());
|
||||
packet.data = Common::Compression::CompressDataZSTDDefault(packet.data.data(), packet.data.size());
|
||||
room_member->SendProxyPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, std::span<const u8> message,
|
||||
const SockAddrIn* addr) {
|
||||
std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, std::span<const u8> message, const Network::SockAddrIn* addr) {
|
||||
LOG_DEBUG(Network, "called");
|
||||
ASSERT(flags == 0);
|
||||
|
||||
if (!is_bound) {
|
||||
LOG_ERROR(Network, "ProxySocket is not bound!");
|
||||
return {static_cast<s32>(message.size()), Errno::SUCCESS};
|
||||
return {s32(message.size()), Errno::SUCCESS};
|
||||
}
|
||||
|
||||
if (auto room_member = Network::GetRoomMember().lock()) {
|
||||
if (!room_member->IsConnected()) {
|
||||
return {static_cast<s32>(message.size()), Errno::SUCCESS};
|
||||
return {s32(message.size()), Errno::SUCCESS};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,65 +242,19 @@ std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, std::span<const u8> message
|
||||
|
||||
SendPacket(packet);
|
||||
|
||||
return {static_cast<s32>(message.size()), Errno::SUCCESS};
|
||||
return {s32(message.size()), Errno::SUCCESS};
|
||||
}
|
||||
|
||||
Errno ProxySocket::Close() {
|
||||
LOG_DEBUG(Network, "called");
|
||||
fd = INVALID_SOCKET;
|
||||
closed = true;
|
||||
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetLinger(bool enable, u32 linger) {
|
||||
struct Linger {
|
||||
u16 linger_enable;
|
||||
u16 linger_time;
|
||||
} values;
|
||||
values.linger_enable = enable ? 1 : 0;
|
||||
values.linger_time = static_cast<u16>(linger);
|
||||
|
||||
return SetSockOpt(fd, SO_LINGER, values);
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetReuseAddr(bool enable) {
|
||||
return SetSockOpt<u32>(fd, SO_REUSEADDR, enable ? 1 : 0);
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetBroadcast(bool enable) {
|
||||
broadcast = enable;
|
||||
return SetSockOpt<u32>(fd, SO_BROADCAST, enable ? 1 : 0);
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetSndBuf(u32 value) {
|
||||
return SetSockOpt(fd, SO_SNDBUF, value);
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetKeepAlive(bool enable) {
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetRcvBuf(u32 value) {
|
||||
return SetSockOpt(fd, SO_RCVBUF, value);
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetSndTimeo(u32 value) {
|
||||
send_timeout = value;
|
||||
return SetSockOpt(fd, SO_SNDTIMEO, static_cast<int>(value));
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetRcvTimeo(u32 value) {
|
||||
receive_timeout = value;
|
||||
return SetSockOpt(fd, SO_RCVTIMEO, static_cast<int>(value));
|
||||
}
|
||||
|
||||
Errno ProxySocket::SetNonBlock(bool enable) {
|
||||
blocking = !enable;
|
||||
return Errno::SUCCESS;
|
||||
}
|
||||
|
||||
std::pair<Errno, Errno> ProxySocket::GetPendingError() {
|
||||
LOG_DEBUG(Network, "(STUBBED) called");
|
||||
LOG_DEBUG(Network, "called");
|
||||
return {Errno::SUCCESS, Errno::SUCCESS};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
@@ -29,13 +29,13 @@ public:
|
||||
|
||||
std::pair<AcceptResult, Errno> Accept() override;
|
||||
|
||||
Errno Connect(SockAddrIn addr_in) override;
|
||||
Errno Connect(Network::SockAddrIn addr_in) override;
|
||||
|
||||
std::pair<SockAddrIn, Errno> GetPeerName() override;
|
||||
std::pair<Network::SockAddrIn, Errno> GetPeerName() override;
|
||||
|
||||
std::pair<SockAddrIn, Errno> GetSockName() override;
|
||||
std::pair<Network::SockAddrIn, Errno> GetSockName() override;
|
||||
|
||||
Errno Bind(SockAddrIn addr) override;
|
||||
Errno Bind(Network::SockAddrIn addr) override;
|
||||
|
||||
Errno Listen(s32 backlog) override;
|
||||
|
||||
@@ -43,9 +43,9 @@ public:
|
||||
|
||||
std::pair<s32, Errno> Recv(int flags, std::span<u8> message) override;
|
||||
|
||||
std::pair<s32, Errno> RecvFrom(int flags, std::span<u8> message, SockAddrIn* addr) override;
|
||||
std::pair<s32, Errno> RecvFrom(int flags, std::span<u8> message, Network::SockAddrIn* addr) override;
|
||||
|
||||
std::pair<s32, Errno> ReceivePacket(int flags, std::span<u8> message, SockAddrIn* addr,
|
||||
std::pair<s32, Errno> ReceivePacket(int flags, std::span<u8> message, Network::SockAddrIn* addr,
|
||||
std::size_t max_length);
|
||||
|
||||
std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override;
|
||||
@@ -53,28 +53,11 @@ public:
|
||||
void SendPacket(ProxyPacket& packet);
|
||||
|
||||
std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message,
|
||||
const SockAddrIn* addr) override;
|
||||
|
||||
Errno SetLinger(bool enable, u32 linger) override;
|
||||
|
||||
Errno SetReuseAddr(bool enable) override;
|
||||
|
||||
Errno SetBroadcast(bool enable) override;
|
||||
|
||||
Errno SetKeepAlive(bool enable) override;
|
||||
|
||||
Errno SetSndBuf(u32 value) override;
|
||||
|
||||
Errno SetRcvBuf(u32 value) override;
|
||||
|
||||
Errno SetSndTimeo(u32 value) override;
|
||||
|
||||
Errno SetRcvTimeo(u32 value) override;
|
||||
const Network::SockAddrIn* addr) override;
|
||||
|
||||
Errno SetNonBlock(bool enable) override;
|
||||
|
||||
template <typename T>
|
||||
Errno SetSockOpt(SOCKET fd, int option, T value);
|
||||
Errno SetSockOpt(Network::SocketLevel level, Network::OptName option, std::span<const u8> value) override;
|
||||
|
||||
std::pair<Errno, Errno> GetPendingError() override;
|
||||
|
||||
@@ -86,7 +69,7 @@ private:
|
||||
u32 send_timeout = 0;
|
||||
u32 receive_timeout = 0;
|
||||
bool is_bound = false;
|
||||
SockAddrIn local_endpoint{};
|
||||
Network::SockAddrIn local_endpoint{};
|
||||
bool blocking = true;
|
||||
std::queue<ProxyPacket> received_packets;
|
||||
Protocol protocol;
|
||||
|
||||
@@ -0,0 +1,360 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/common_funcs.h"
|
||||
|
||||
// Most of these structures are direct mappings of guest's
|
||||
// expectations for these values, in other words, they're the
|
||||
// values that HOS is expected to use AND handle.
|
||||
|
||||
namespace Network {
|
||||
|
||||
enum class Errno : u32 {
|
||||
SUCCESS = 0,
|
||||
BADF = 9,
|
||||
AGAIN = 11,
|
||||
INVAL = 22,
|
||||
MFILE = 24,
|
||||
PIPE = 32,
|
||||
NOTSOCK = 88,
|
||||
MSGSIZE = 90,
|
||||
PROTOTYPE = 91,
|
||||
NOPROTOOPT = 92,
|
||||
PROTONOSUPPORT = 93,
|
||||
SOCKTNOSUPPORT = 94,
|
||||
NOTSUP = 95,
|
||||
ADDRINUSE = 98,
|
||||
ADDRNOTAVAIL = 99,
|
||||
NETDOWN = 100,
|
||||
NETUNREACH = 101,
|
||||
CONNABORTED = 103,
|
||||
CONNRESET = 104,
|
||||
ISCONN = 106,
|
||||
NOTCONN = 107,
|
||||
TIMEDOUT = 110,
|
||||
CONNREFUSED = 111,
|
||||
HOSTUNREACH = 113,
|
||||
ALREADY = 114,
|
||||
INPROGRESS = 115,
|
||||
STALE = 116,
|
||||
/* made up error? */
|
||||
OTHER = 196,
|
||||
};
|
||||
|
||||
enum class GetAddrInfoError : s32 {
|
||||
SUCCESS = 0,
|
||||
ADDRFAMILY = 1,
|
||||
AGAIN = 2,
|
||||
BADFLAGS = 3,
|
||||
FAIL = 4,
|
||||
FAMILY = 5,
|
||||
MEMORY = 6,
|
||||
NODATA = 7,
|
||||
NONAME = 8,
|
||||
SERVICE = 9,
|
||||
SOCKTYPE = 10,
|
||||
SYSTEM = 11,
|
||||
BADHINTS = 12,
|
||||
PROTOCOL = 13,
|
||||
OVERFLOW_ = 14, // avoid name collision with Windows macro
|
||||
OTHER = 15,
|
||||
};
|
||||
|
||||
enum class Domain : u32 {
|
||||
Unspecified = 0,
|
||||
UNIX = 1,
|
||||
INET = 2,
|
||||
IMPLINK = 3,
|
||||
PUP = 4,
|
||||
CHAOS = 5,
|
||||
NETBIOS = 6,
|
||||
ISO = 7,
|
||||
ECMA = 8,
|
||||
DATAKIT = 9,
|
||||
CCITT = 10,
|
||||
SNA = 11,
|
||||
DECnet = 12,
|
||||
DLI = 13,
|
||||
LAT = 14,
|
||||
HYLINK = 15,
|
||||
APPLETALK = 16,
|
||||
ROUTE = 17,
|
||||
LINK = 18,
|
||||
COIP = 20,
|
||||
CNT = 21,
|
||||
IPX = 23,
|
||||
SIP = 24,
|
||||
ISDN = 26,
|
||||
INET6 = 28,
|
||||
NATM = 29,
|
||||
ATM = 30,
|
||||
NETGRAPH = 32,
|
||||
SLOW = 33,
|
||||
SCLUSTER = 34,
|
||||
ARP = 35,
|
||||
BLUETOOTH = 36,
|
||||
IEEE80211 = 37,
|
||||
NETLINK = 38,
|
||||
INET_SDP = 40,
|
||||
INET6_SDP = 42,
|
||||
};
|
||||
|
||||
enum class Type : u32 {
|
||||
Unspecified = 0,
|
||||
STREAM = 1,
|
||||
DGRAM = 2,
|
||||
RAW = 3,
|
||||
RDM = 4,
|
||||
SEQPACKET = 5,
|
||||
};
|
||||
|
||||
enum class Protocol : u32 {
|
||||
IP = 0,
|
||||
ICMP = 1,
|
||||
TCP = 6,
|
||||
UDP = 17,
|
||||
//
|
||||
IPV6 = 41,
|
||||
RAW = 255,
|
||||
//
|
||||
HOPOPTS = 0,
|
||||
IGMP = 2,
|
||||
GGP = 3,
|
||||
IPV4 = 4,
|
||||
ST = 7,
|
||||
EGP = 8,
|
||||
PIGP = 9,
|
||||
RCCMON = 10,
|
||||
NVPII = 11,
|
||||
PUP = 12,
|
||||
ARGUS = 13,
|
||||
EMCON = 14,
|
||||
XNET = 15,
|
||||
CHAOS = 16,
|
||||
MUX = 18,
|
||||
MEAS = 19,
|
||||
HMP = 20,
|
||||
PRM = 21,
|
||||
IDP = 22,
|
||||
TRUNK1 = 23,
|
||||
TRUNK2 = 24,
|
||||
LEAF1 = 25,
|
||||
LEAF2 = 26,
|
||||
RDP = 27,
|
||||
IRTP = 28,
|
||||
TP = 29,
|
||||
BLT = 30,
|
||||
NSP = 31,
|
||||
INP = 32,
|
||||
DCCP = 33,
|
||||
//3PC = 34,
|
||||
IDPR = 35,
|
||||
XTP = 36,
|
||||
DDP = 37,
|
||||
CMTP = 38,
|
||||
TPXX = 39,
|
||||
IL = 40,
|
||||
SDRP = 42,
|
||||
ROUTING = 43,
|
||||
FRAGMENT = 44,
|
||||
IDRP = 45,
|
||||
RSVP = 46,
|
||||
GRE = 47,
|
||||
MHRP = 48,
|
||||
BHA = 49,
|
||||
ESP = 50,
|
||||
AH = 51,
|
||||
INLSP = 52,
|
||||
SWIPE = 53,
|
||||
NHRP = 54,
|
||||
MOBILE = 55,
|
||||
TLSP = 56,
|
||||
SKIP = 57,
|
||||
ICMPV6 = 58,
|
||||
NONE = 59,
|
||||
DSTOPTS = 60,
|
||||
AHIP = 61,
|
||||
CFTP = 62,
|
||||
HELLO = 63,
|
||||
SATEXPAK = 64,
|
||||
KRYPTOLAN = 65,
|
||||
RVD = 66,
|
||||
IPPC = 67,
|
||||
ADFS = 68,
|
||||
SATMON = 69,
|
||||
VISA = 70,
|
||||
IPCV = 71,
|
||||
CPNX = 72,
|
||||
CPHB = 73,
|
||||
WSN = 74,
|
||||
PVP = 75,
|
||||
BRSATMON = 76,
|
||||
ND = 77,
|
||||
WBMON = 78,
|
||||
WBEXPAK = 79,
|
||||
EON = 80,
|
||||
VMTP = 81,
|
||||
SVMTP = 82,
|
||||
VINES = 83,
|
||||
TTP = 84,
|
||||
IGP = 85,
|
||||
DGP = 86,
|
||||
TCF = 87,
|
||||
IGRP = 88,
|
||||
OSPFIGP = 89,
|
||||
SRPC = 90,
|
||||
LARP = 91,
|
||||
MTP = 92,
|
||||
AX25 = 93,
|
||||
IPEIP = 94,
|
||||
MICP = 95,
|
||||
SCCSP = 96,
|
||||
ETHERIP = 97,
|
||||
ENCAP = 98,
|
||||
APES = 99,
|
||||
GMTP = 100,
|
||||
IPCOMP = 108,
|
||||
SCTP = 132,
|
||||
MH = 135,
|
||||
UDPLITE = 136,
|
||||
HIP = 139,
|
||||
SHIM6 = 140,
|
||||
PIM = 103,
|
||||
CARP = 112,
|
||||
PGM = 113,
|
||||
MPLS = 137,
|
||||
PFSYNC = 240,
|
||||
};
|
||||
|
||||
enum class SocketLevel : u32 {
|
||||
IP = 0,
|
||||
ICMP = 1,
|
||||
TCP = 6,
|
||||
UDP = 17,
|
||||
CONFIG = 0xfffe,
|
||||
SOCKET = 0xffff, // i.e. SOL_SOCKET
|
||||
};
|
||||
|
||||
enum class MsgOpt : u32 {
|
||||
OOB = 0x00001,
|
||||
PEEK = 0x00002,
|
||||
DONTROUTE = 0x00004,
|
||||
EOR_ = 0x00008,
|
||||
TRUNC = 0x00010,
|
||||
CTRUNC = 0x00020,
|
||||
WAITALL = 0x00040,
|
||||
DONTWAIT = 0x00080,
|
||||
EOF_ = 0x00100,
|
||||
NOSIGNAL = 0x20000,
|
||||
};
|
||||
|
||||
enum class OptName : u32 {
|
||||
DEBUG = 0x0001,
|
||||
ACCEPTCONN = 0x0002,
|
||||
REUSEADDR = 0x0004,
|
||||
KEEPALIVE = 0x0008,
|
||||
DONTROUTE = 0x0010,
|
||||
BROADCAST = 0x0020,
|
||||
USELOOPBACK = 0x0040,
|
||||
LINGER = 0x0080,
|
||||
OOBINLINE = 0x0100,
|
||||
REUSEPORT = 0x0200,
|
||||
TIMESTAMP = 0x0400,
|
||||
NOSIGPIPE = 0x0800, // at least according to libnx
|
||||
ACCEPTFILER = 0x1000,
|
||||
SNDBUF = 0x1001,
|
||||
RCVBUF = 0x1002,
|
||||
SNDTIMEO = 0x1005,
|
||||
RCVTIMEO = 0x1006,
|
||||
ERROR_ = 0x1007, // avoid name collision with Windows macro
|
||||
ACCEPTFILTER = 0x1000,
|
||||
BINTIME = 0x2000,
|
||||
NO_OFFLOAD = 0x4000,
|
||||
NO_DDP = 0x8000,
|
||||
};
|
||||
enum class TcpOptName : u32 {
|
||||
NODELAY = 0x0001,
|
||||
MAXSEG = 0x0002,
|
||||
NOPUSH = 0x0004,
|
||||
NOOPT = 0x0008,
|
||||
MS5SIG = 0x0010,
|
||||
INFO = 0x0020
|
||||
};
|
||||
|
||||
enum class ShutdownHow : s32 {
|
||||
RD = 0,
|
||||
WR = 1,
|
||||
RDWR = 2,
|
||||
};
|
||||
|
||||
enum class FcntlCmd : s32 {
|
||||
GETFL = 3,
|
||||
SETFL = 4,
|
||||
};
|
||||
|
||||
enum class FcntlFlags : u32 {
|
||||
NONBLOCK = 0x004,
|
||||
NONBLOCK_NX = 0x800,
|
||||
// Provided for convenience
|
||||
NONBLOCK_ANY = u32(NONBLOCK) | u32(NONBLOCK_NX),
|
||||
};
|
||||
|
||||
/// Array of IPv4 address
|
||||
using IPv4Address = std::array<u8, 4>;
|
||||
|
||||
struct SockAddrIn {
|
||||
u8 len;
|
||||
u8 family;
|
||||
u16 portno;
|
||||
IPv4Address ip;
|
||||
std::array<u8, 248> zeroes;
|
||||
};
|
||||
static_assert(sizeof(SockAddrIn) == 0x100);
|
||||
|
||||
enum class PollEvents : u16 {
|
||||
// Using Pascal case because IN is a macro on Windows.
|
||||
IN_ = 0x0001,
|
||||
PRI_ = 0x0002,
|
||||
OUT_ = 0x0004,
|
||||
ERR_ = 0x0008,
|
||||
HUP_ = 0x0010,
|
||||
NVAL = 0x0020,
|
||||
RDNORM = 0x0040,
|
||||
RDBAND = 0x0080,
|
||||
WRBAND = 0x0100,
|
||||
IGNEOF = 0x2000,
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(PollEvents);
|
||||
|
||||
struct PollFD {
|
||||
s32 fd;
|
||||
Network::PollEvents events;
|
||||
Network::PollEvents revents;
|
||||
};
|
||||
static_assert(sizeof(PollFD) == 8);
|
||||
|
||||
struct Linger {
|
||||
s32 onoff;
|
||||
s32 linger;
|
||||
};
|
||||
static_assert(sizeof(Linger) == 8);
|
||||
|
||||
/// @brief Cross-platform addrinfo structure (not guest)
|
||||
struct AddrInfo {
|
||||
Domain family;
|
||||
Type socket_type;
|
||||
Protocol protocol;
|
||||
SockAddrIn addr;
|
||||
std::optional<std::string> canon_name;
|
||||
};
|
||||
|
||||
} // namespace Network
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
|
||||
struct AcceptResult {
|
||||
std::unique_ptr<SocketBase> socket;
|
||||
SockAddrIn sockaddr_in;
|
||||
Network::SockAddrIn sockaddr_in;
|
||||
};
|
||||
|
||||
SocketBase() = default;
|
||||
@@ -46,13 +46,13 @@ public:
|
||||
|
||||
virtual std::pair<AcceptResult, Errno> Accept() = 0;
|
||||
|
||||
virtual Errno Connect(SockAddrIn addr_in) = 0;
|
||||
virtual Errno Connect(Network::SockAddrIn addr_in) = 0;
|
||||
|
||||
virtual std::pair<SockAddrIn, Errno> GetPeerName() = 0;
|
||||
virtual std::pair<Network::SockAddrIn, Errno> GetPeerName() = 0;
|
||||
|
||||
virtual std::pair<SockAddrIn, Errno> GetSockName() = 0;
|
||||
virtual std::pair<Network::SockAddrIn, Errno> GetSockName() = 0;
|
||||
|
||||
virtual Errno Bind(SockAddrIn addr) = 0;
|
||||
virtual Errno Bind(Network::SockAddrIn addr) = 0;
|
||||
|
||||
virtual Errno Listen(s32 backlog) = 0;
|
||||
|
||||
@@ -60,31 +60,16 @@ public:
|
||||
|
||||
virtual std::pair<s32, Errno> Recv(int flags, std::span<u8> message) = 0;
|
||||
|
||||
virtual std::pair<s32, Errno> RecvFrom(int flags, std::span<u8> message, SockAddrIn* addr) = 0;
|
||||
virtual std::pair<s32, Errno> RecvFrom(int flags, std::span<u8> message, Network::SockAddrIn* addr) = 0;
|
||||
|
||||
virtual std::pair<s32, Errno> Send(std::span<const u8> message, int flags) = 0;
|
||||
|
||||
virtual std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message,
|
||||
const SockAddrIn* addr) = 0;
|
||||
|
||||
virtual Errno SetLinger(bool enable, u32 linger) = 0;
|
||||
|
||||
virtual Errno SetReuseAddr(bool enable) = 0;
|
||||
|
||||
virtual Errno SetKeepAlive(bool enable) = 0;
|
||||
|
||||
virtual Errno SetBroadcast(bool enable) = 0;
|
||||
|
||||
virtual Errno SetSndBuf(u32 value) = 0;
|
||||
|
||||
virtual Errno SetRcvBuf(u32 value) = 0;
|
||||
|
||||
virtual Errno SetSndTimeo(u32 value) = 0;
|
||||
|
||||
virtual Errno SetRcvTimeo(u32 value) = 0;
|
||||
virtual std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message, const Network::SockAddrIn* addr) = 0;
|
||||
|
||||
virtual Errno SetNonBlock(bool enable) = 0;
|
||||
|
||||
virtual Errno SetSockOpt(Network::SocketLevel level, Network::OptName option, std::span<const u8> value) = 0;
|
||||
|
||||
virtual std::pair<Errno, Errno> GetPendingError() = 0;
|
||||
|
||||
virtual bool IsOpened() const = 0;
|
||||
@@ -95,7 +80,6 @@ public:
|
||||
return fd;
|
||||
}
|
||||
|
||||
protected:
|
||||
SOCKET fd = INVALID_SOCKET;
|
||||
};
|
||||
|
||||
@@ -114,13 +98,13 @@ public:
|
||||
|
||||
std::pair<AcceptResult, Errno> Accept() override;
|
||||
|
||||
Errno Connect(SockAddrIn addr_in) override;
|
||||
Errno Connect(Network::SockAddrIn addr_in) override;
|
||||
|
||||
std::pair<SockAddrIn, Errno> GetPeerName() override;
|
||||
std::pair<Network::SockAddrIn, Errno> GetPeerName() override;
|
||||
|
||||
std::pair<SockAddrIn, Errno> GetSockName() override;
|
||||
std::pair<Network::SockAddrIn, Errno> GetSockName() override;
|
||||
|
||||
Errno Bind(SockAddrIn addr) override;
|
||||
Errno Bind(Network::SockAddrIn addr) override;
|
||||
|
||||
Errno Listen(s32 backlog) override;
|
||||
|
||||
@@ -128,38 +112,19 @@ public:
|
||||
|
||||
std::pair<s32, Errno> Recv(int flags, std::span<u8> message) override;
|
||||
|
||||
std::pair<s32, Errno> RecvFrom(int flags, std::span<u8> message, SockAddrIn* addr) override;
|
||||
std::pair<s32, Errno> RecvFrom(int flags, std::span<u8> message, Network::SockAddrIn* addr) override;
|
||||
|
||||
std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override;
|
||||
|
||||
std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message,
|
||||
const SockAddrIn* addr) override;
|
||||
|
||||
Errno SetLinger(bool enable, u32 linger) override;
|
||||
|
||||
Errno SetReuseAddr(bool enable) override;
|
||||
|
||||
Errno SetKeepAlive(bool enable) override;
|
||||
|
||||
Errno SetBroadcast(bool enable) override;
|
||||
|
||||
Errno SetSndBuf(u32 value) override;
|
||||
|
||||
Errno SetRcvBuf(u32 value) override;
|
||||
|
||||
Errno SetSndTimeo(u32 value) override;
|
||||
|
||||
Errno SetRcvTimeo(u32 value) override;
|
||||
std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message, const Network::SockAddrIn* addr) override;
|
||||
|
||||
Errno SetNonBlock(bool enable) override;
|
||||
|
||||
template <typename T>
|
||||
Errno SetSockOpt(SOCKET fd, int option, T value);
|
||||
Errno SetSockOpt(Network::SocketLevel level, Network::OptName option, std::span<const u8> value) override;
|
||||
|
||||
std::pair<Errno, Errno> GetPendingError() override;
|
||||
|
||||
template <typename T>
|
||||
std::pair<T, Errno> GetSockOpt(SOCKET fd, int option);
|
||||
Errno GetSockOpt(Network::SocketLevel level, Network::OptName optname, std::span<u8> value);
|
||||
|
||||
bool IsOpened() const override;
|
||||
|
||||
@@ -169,6 +134,6 @@ private:
|
||||
bool is_non_blocking = false;
|
||||
};
|
||||
|
||||
std::pair<s32, Errno> Poll(std::vector<PollFD>& poll_fds, s32 timeout);
|
||||
std::pair<s32, Errno> Poll(std::span<Network::HostPollFD> poll_fds, s32 timeout);
|
||||
|
||||
} // namespace Network
|
||||
|
||||
@@ -25,7 +25,7 @@ endif()
|
||||
# Dynarmic project options
|
||||
option(DYNARMIC_ENABLE_CPU_FEATURE_DETECTION "Turning this off causes dynarmic to assume the host CPU doesn't support anything later than SSE3" ON)
|
||||
|
||||
if (PLATFORM_OPENBSD OR PLATFORM_DRAGONFLY OR PLATFORM_NETBSD)
|
||||
if (OPENBSD OR DRAGONFLY OR NETBSD)
|
||||
set(REQUIRE_WX ON)
|
||||
else()
|
||||
set(REQUIRE_WX OFF)
|
||||
|
||||
@@ -363,7 +363,7 @@ elseif (APPLE)
|
||||
backend/exception_handler_macos_mig.c
|
||||
)
|
||||
endif()
|
||||
elseif (UNIX AND NOT PLATFORM_HAIKU)
|
||||
elseif (UNIX AND NOT HAIKUOS)
|
||||
# Haiku lacks <ucontext.h>
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
target_link_libraries(dynarmic PRIVATE rt)
|
||||
|
||||
@@ -234,7 +234,7 @@ private:
|
||||
BlockOfCode block_of_code;
|
||||
A32EmitX64 emitter;
|
||||
Optimization::PolyfillOptions polyfill_options;
|
||||
// Keep it here, you don't wanna mess with the fuckery that's initializer lists
|
||||
// Keep it here in order to not mess with initializer lists
|
||||
const A32::UserConfig conf;
|
||||
Jit* jit_interface;
|
||||
|
||||
|
||||
@@ -2160,8 +2160,6 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
|
||||
ROUNDING_MODE_CASE(CASE, 0x3e) \
|
||||
ROUNDING_MODE_CASE(CASE, 0x3f)
|
||||
|
||||
// FUCK YOU MSVC, FUCKING DEPTH CANT EVEN HANDLE 8+16+32+64 DEPTH OF A ELSE STATMENT YOU FUCKING STUPID
|
||||
// BURN MSVC BURN IT STUPID COMPILER CAN'T EVEN COMPILE THE MOST BASIC C++
|
||||
ROUNDING_MODE_SWITCH(ToNearest_TieEven)
|
||||
ROUNDING_MODE_SWITCH(TowardsPlusInfinity)
|
||||
ROUNDING_MODE_SWITCH(TowardsMinusInfinity)
|
||||
|
||||
@@ -787,7 +787,7 @@ static void FoldCountLeadingZeros(IR::Inst& inst, bool is_32_bit) {
|
||||
/// Folds division operations based on the following:
|
||||
///
|
||||
/// 1. x / 0 -> 0 (NOTE: This is an ARM-specific behavior defined in the architecture reference manual)
|
||||
/// 2a. 0x8000_0000 / 0xFFFF_FFFF -> 0x8000_0000 (NOTE: More ARM bullshit)
|
||||
/// 2a. 0x8000_0000 / 0xFFFF_FFFF -> 0x8000_0000 (NOTE: More ARM errata)
|
||||
/// 2b. 0x8000_0000_0000_0000 / 0xFFFF_FFFF_FFFF_FFFF -> 0x8000_0000_0000_0000
|
||||
/// 3. imm_x / imm_y -> result
|
||||
/// 4. x / 1 -> x
|
||||
|
||||
@@ -151,7 +151,7 @@ if (MSVC)
|
||||
)
|
||||
else()
|
||||
target_compile_options(hid_core PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=conversion>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wconversion>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-sign-conversion>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-cast-function-type>
|
||||
$<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>)
|
||||
|
||||
@@ -44,7 +44,7 @@ if (MSVC)
|
||||
/we4800 # Implicit conversion from 'type' to bool. Possible information loss
|
||||
)
|
||||
else()
|
||||
target_compile_options(input_common PRIVATE $<$<COMPILE_LANGUAGE:C,CXX>:-Werror=conversion>)
|
||||
target_compile_options(input_common PRIVATE $<$<COMPILE_LANGUAGE:C,CXX>:-Wconversion>)
|
||||
endif()
|
||||
|
||||
if (ANDROID)
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -157,8 +160,8 @@ Common::ParamPackage Android::BuildButtonParamPackageForButton(PadIdentifier ide
|
||||
|
||||
bool Android::MatchVID(Common::UUID device, const std::vector<std::string>& vids) const {
|
||||
for (size_t i = 0; i < vids.size(); ++i) {
|
||||
auto fucker = device.RawString();
|
||||
if (fucker.find(vids[i]) != std::string::npos) {
|
||||
auto dev_str = device.RawString();
|
||||
if (dev_str.find(vids[i]) != std::string::npos) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -648,6 +648,13 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en
|
||||
// Disable raw input. When enabled this setting causes SDL to die when a web applet opens
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, Settings::values.enable_raw_input ? "1" : "0");
|
||||
|
||||
#ifdef _WIN32
|
||||
if (Settings::values.disable_wgi_xinput) {
|
||||
SDL_SetHintWithPriority(SDL_HINT_JOYSTICK_RAWINPUT_CORRELATE_XINPUT, "0", SDL_HINT_OVERRIDE);
|
||||
SDL_SetHintWithPriority(SDL_HINT_JOYSTICK_WGI, "0", SDL_HINT_OVERRIDE);
|
||||
}
|
||||
#endif
|
||||
|
||||
// SDL3 defaults Steam Controller Bluetooth HIDAPI support to off, which can disable gyro.
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_STEAM, "1");
|
||||
SDL_SetHint(SDL_HINT_GAMECONTROLLER_SENSOR_FUSION, "1");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# SPDX-FileCopyrightText: 2022 yuzu Emulator Project
|
||||
@@ -28,6 +28,6 @@ if (ENABLE_WEB_SERVICE)
|
||||
endif()
|
||||
|
||||
# Solaris uses /lib/amd64/libsocket.so and /lib/amd64/libnsl.so
|
||||
if (PLATFORM_SUN)
|
||||
if (SOLARIS)
|
||||
target_link_libraries(network PRIVATE socket nsl)
|
||||
endif()
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <vector>
|
||||
#include "common/announce_multiplayer_room.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "network/verify_user.h"
|
||||
|
||||
namespace Network {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <thread>
|
||||
#include "common/assert.h"
|
||||
#include "common/polyfill_thread.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "enet/enet.h"
|
||||
#include "network/packet.h"
|
||||
#include "network/room_member.h"
|
||||
@@ -358,19 +358,23 @@ void RoomMember::RoomMemberImpl::HandleProxyPackets(const ENetEvent* event) {
|
||||
// Parse the ProxyPacket from the packet
|
||||
u8 local_family;
|
||||
packet.Read(local_family);
|
||||
proxy_packet.local_endpoint.family = static_cast<Domain>(local_family);
|
||||
proxy_packet.local_endpoint.len = 16;
|
||||
proxy_packet.local_endpoint.family = u8(Network::Domain(local_family));
|
||||
packet.Read(proxy_packet.local_endpoint.ip);
|
||||
packet.Read(proxy_packet.local_endpoint.portno);
|
||||
proxy_packet.local_endpoint.zeroes = {};
|
||||
|
||||
u8 remote_family;
|
||||
packet.Read(remote_family);
|
||||
proxy_packet.remote_endpoint.family = static_cast<Domain>(remote_family);
|
||||
proxy_packet.remote_endpoint.len = 16;
|
||||
proxy_packet.remote_endpoint.family = u8(Network::Domain(remote_family));
|
||||
packet.Read(proxy_packet.remote_endpoint.ip);
|
||||
packet.Read(proxy_packet.remote_endpoint.portno);
|
||||
proxy_packet.local_endpoint.zeroes = {};
|
||||
|
||||
u8 protocol_type;
|
||||
packet.Read(protocol_type);
|
||||
proxy_packet.protocol = static_cast<Protocol>(protocol_type);
|
||||
proxy_packet.protocol = Network::Protocol(protocol_type);
|
||||
|
||||
packet.Read(proxy_packet.broadcast);
|
||||
packet.Read(proxy_packet.data);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <vector>
|
||||
#include "common/announce_multiplayer_room.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/socket_types.h"
|
||||
#include "core/internal_network/socket_types.h"
|
||||
#include "network/room.h"
|
||||
|
||||
namespace Network {
|
||||
@@ -39,8 +39,8 @@ struct LDNPacket {
|
||||
|
||||
/// Information about the received proxy packets.
|
||||
struct ProxyPacket {
|
||||
SockAddrIn local_endpoint;
|
||||
SockAddrIn remote_endpoint;
|
||||
Network::SockAddrIn local_endpoint;
|
||||
Network::SockAddrIn remote_endpoint;
|
||||
Protocol protocol;
|
||||
bool broadcast;
|
||||
std::vector<u8> data;
|
||||
|
||||
@@ -227,8 +227,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
|
||||
tr("Preserves GPU-modified data by reading it back before uploading.\nSome games require this to render certain effects properly."));
|
||||
INSERT(Settings, use_asynchronous_shaders, tr("Enable asynchronous shader compilation"),
|
||||
tr("May reduce shader stutter."));
|
||||
INSERT(Settings, use_unified_memory, tr("Enable unified memory access"),
|
||||
tr("Lets the GPU write buffer readbacks directly into guest memory."));
|
||||
INSERT(Settings, gpu_clock, tr("GPU Clocks"),
|
||||
tr("Makes the game believe GPU work finishes faster than it does, so it stops lowering "
|
||||
"resolution and render distance to fit the Switch's clocks."));
|
||||
|
||||
@@ -253,7 +253,7 @@ if (MSVC)
|
||||
)
|
||||
else()
|
||||
target_compile_options(shader_recompiler PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Werror=conversion>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wconversion>
|
||||
# Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6.
|
||||
# And this in turns limits the size of a std::array.
|
||||
$<$<CXX_COMPILER_ID:Clang>:-fbracket-depth=1024>
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
namespace Shader::Backend::SPIRV {
|
||||
namespace {
|
||||
Id SharedPointer(EmitContext& ctx, Id offset, u32 index_offset = 0) {
|
||||
offset = ctx.BoundSharedOffset(offset, 4 + index_offset * 4);
|
||||
const Id shift_id{ctx.Const(2U)};
|
||||
Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)};
|
||||
if (index_offset > 0) {
|
||||
@@ -161,8 +160,7 @@ Id EmitSharedAtomicExchange32(EmitContext& ctx, Id offset, Id value) {
|
||||
Id EmitSharedAtomicExchange64(EmitContext& ctx, Id offset, Id value) {
|
||||
if (ctx.profile.support_shared_int64_atomics && ctx.uses_explicit_workgroup_layout) {
|
||||
const Id shift_id{ctx.Const(3U)};
|
||||
const Id index{
|
||||
ctx.OpShiftRightArithmetic(ctx.U32[1], ctx.BoundSharedOffset(offset, 8), shift_id)};
|
||||
const Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)};
|
||||
const Id pointer{
|
||||
ctx.OpAccessChain(ctx.shared_u64, ctx.shared_memory_u64, ctx.u32_zero_value, index)};
|
||||
const auto [scope, semantics]{AtomicArgs(ctx)};
|
||||
|
||||
@@ -31,7 +31,6 @@ std::pair<Id, Id> ExtractArgs(EmitContext& ctx, Id offset, u32 mask, u32 count)
|
||||
} // Anonymous namespace
|
||||
|
||||
Id EmitLoadSharedU8(EmitContext& ctx, Id offset) {
|
||||
offset = ctx.BoundSharedOffset(offset, 1);
|
||||
if (ctx.uses_explicit_workgroup_layout) {
|
||||
const Id pointer{
|
||||
ctx.OpAccessChain(ctx.shared_u8, ctx.shared_memory_u8, ctx.u32_zero_value, offset)};
|
||||
@@ -43,7 +42,6 @@ Id EmitLoadSharedU8(EmitContext& ctx, Id offset) {
|
||||
}
|
||||
|
||||
Id EmitLoadSharedS8(EmitContext& ctx, Id offset) {
|
||||
offset = ctx.BoundSharedOffset(offset, 1);
|
||||
if (ctx.uses_explicit_workgroup_layout) {
|
||||
const Id pointer{
|
||||
ctx.OpAccessChain(ctx.shared_u8, ctx.shared_memory_u8, ctx.u32_zero_value, offset)};
|
||||
@@ -55,7 +53,6 @@ Id EmitLoadSharedS8(EmitContext& ctx, Id offset) {
|
||||
}
|
||||
|
||||
Id EmitLoadSharedU16(EmitContext& ctx, Id offset) {
|
||||
offset = ctx.BoundSharedOffset(offset, 2);
|
||||
if (ctx.uses_explicit_workgroup_layout) {
|
||||
const Id pointer{Pointer(ctx, ctx.shared_u16, ctx.shared_memory_u16, offset, 1)};
|
||||
return ctx.OpUConvert(ctx.U32[1], ctx.OpLoad(ctx.U16, pointer));
|
||||
@@ -66,7 +63,6 @@ Id EmitLoadSharedU16(EmitContext& ctx, Id offset) {
|
||||
}
|
||||
|
||||
Id EmitLoadSharedS16(EmitContext& ctx, Id offset) {
|
||||
offset = ctx.BoundSharedOffset(offset, 2);
|
||||
if (ctx.uses_explicit_workgroup_layout) {
|
||||
const Id pointer{Pointer(ctx, ctx.shared_u16, ctx.shared_memory_u16, offset, 1)};
|
||||
return ctx.OpSConvert(ctx.U32[1], ctx.OpLoad(ctx.U16, pointer));
|
||||
@@ -77,7 +73,6 @@ Id EmitLoadSharedS16(EmitContext& ctx, Id offset) {
|
||||
}
|
||||
|
||||
Id EmitLoadSharedU32(EmitContext& ctx, Id offset) {
|
||||
offset = ctx.BoundSharedOffset(offset, 4);
|
||||
if (ctx.uses_explicit_workgroup_layout) {
|
||||
const Id pointer{Pointer(ctx, ctx.shared_u32, ctx.shared_memory_u32, offset, 2)};
|
||||
return ctx.OpLoad(ctx.U32[1], pointer);
|
||||
@@ -87,7 +82,6 @@ Id EmitLoadSharedU32(EmitContext& ctx, Id offset) {
|
||||
}
|
||||
|
||||
Id EmitLoadSharedU64(EmitContext& ctx, Id offset) {
|
||||
offset = ctx.BoundSharedOffset(offset, 8);
|
||||
if (ctx.uses_explicit_workgroup_layout) {
|
||||
const Id pointer{Pointer(ctx, ctx.shared_u32x2, ctx.shared_memory_u32x2, offset, 3)};
|
||||
return ctx.OpLoad(ctx.U32[2], pointer);
|
||||
@@ -103,7 +97,6 @@ Id EmitLoadSharedU64(EmitContext& ctx, Id offset) {
|
||||
}
|
||||
|
||||
Id EmitLoadSharedU128(EmitContext& ctx, Id offset) {
|
||||
offset = ctx.BoundSharedOffset(offset, 16);
|
||||
if (ctx.uses_explicit_workgroup_layout) {
|
||||
const Id pointer{Pointer(ctx, ctx.shared_u32x4, ctx.shared_memory_u32x4, offset, 4)};
|
||||
return ctx.OpLoad(ctx.U32[4], pointer);
|
||||
@@ -120,7 +113,6 @@ Id EmitLoadSharedU128(EmitContext& ctx, Id offset) {
|
||||
}
|
||||
|
||||
void EmitWriteSharedU8(EmitContext& ctx, Id offset, Id value) {
|
||||
offset = ctx.BoundSharedOffset(offset, 1);
|
||||
if (ctx.uses_explicit_workgroup_layout) {
|
||||
const Id pointer{
|
||||
ctx.OpAccessChain(ctx.shared_u8, ctx.shared_memory_u8, ctx.u32_zero_value, offset)};
|
||||
@@ -131,7 +123,6 @@ void EmitWriteSharedU8(EmitContext& ctx, Id offset, Id value) {
|
||||
}
|
||||
|
||||
void EmitWriteSharedU16(EmitContext& ctx, Id offset, Id value) {
|
||||
offset = ctx.BoundSharedOffset(offset, 2);
|
||||
if (ctx.uses_explicit_workgroup_layout) {
|
||||
const Id pointer{Pointer(ctx, ctx.shared_u16, ctx.shared_memory_u16, offset, 1)};
|
||||
ctx.OpStore(pointer, ctx.OpUConvert(ctx.U16, value));
|
||||
@@ -141,7 +132,6 @@ void EmitWriteSharedU16(EmitContext& ctx, Id offset, Id value) {
|
||||
}
|
||||
|
||||
void EmitWriteSharedU32(EmitContext& ctx, Id offset, Id value) {
|
||||
offset = ctx.BoundSharedOffset(offset, 4);
|
||||
Id pointer{};
|
||||
if (ctx.uses_explicit_workgroup_layout) {
|
||||
pointer = Pointer(ctx, ctx.shared_u32, ctx.shared_memory_u32, offset, 2);
|
||||
@@ -154,7 +144,6 @@ void EmitWriteSharedU32(EmitContext& ctx, Id offset, Id value) {
|
||||
}
|
||||
|
||||
void EmitWriteSharedU64(EmitContext& ctx, Id offset, Id value) {
|
||||
offset = ctx.BoundSharedOffset(offset, 8);
|
||||
if (ctx.uses_explicit_workgroup_layout) {
|
||||
const Id pointer{Pointer(ctx, ctx.shared_u32x2, ctx.shared_memory_u32x2, offset, 3)};
|
||||
ctx.OpStore(pointer, value);
|
||||
@@ -170,7 +159,6 @@ void EmitWriteSharedU64(EmitContext& ctx, Id offset, Id value) {
|
||||
}
|
||||
|
||||
void EmitWriteSharedU128(EmitContext& ctx, Id offset, Id value) {
|
||||
offset = ctx.BoundSharedOffset(offset, 16);
|
||||
if (ctx.uses_explicit_workgroup_layout) {
|
||||
const Id pointer{Pointer(ctx, ctx.shared_u32x4, ctx.shared_memory_u32x4, offset, 4)};
|
||||
ctx.OpStore(pointer, value);
|
||||
|
||||
@@ -600,16 +600,6 @@ void EmitContext::DefineLocalMemory(const IR::Program& program) {
|
||||
}
|
||||
}
|
||||
|
||||
Id EmitContext::BoundSharedOffset(Id offset, u32 access_bytes) {
|
||||
if (shared_memory_declared_bytes == 0) {
|
||||
return offset;
|
||||
}
|
||||
const u32 last_valid{shared_memory_declared_bytes > access_bytes
|
||||
? shared_memory_declared_bytes - access_bytes
|
||||
: 0U};
|
||||
return OpUMin(U32[1], offset, Const(last_valid));
|
||||
}
|
||||
|
||||
void EmitContext::DefineSharedMemory(const IR::Program& program) {
|
||||
uses_explicit_workgroup_layout =
|
||||
profile.support_explicit_workgroup_layout &&
|
||||
@@ -618,15 +608,8 @@ void EmitContext::DefineSharedMemory(const IR::Program& program) {
|
||||
if (program.shared_memory_size == 0) {
|
||||
return;
|
||||
}
|
||||
const u32 device_limit{profile.max_shared_memory_size};
|
||||
const u32 shared_memory_size{device_limit != 0 && program.shared_memory_size > device_limit
|
||||
? device_limit
|
||||
: program.shared_memory_size};
|
||||
if (shared_memory_size != program.shared_memory_size) {
|
||||
shared_memory_declared_bytes = shared_memory_size;
|
||||
}
|
||||
const auto make{[&](Id element_type, u32 element_size) {
|
||||
const u32 num_elements{Common::DivCeil(shared_memory_size, element_size)};
|
||||
const u32 num_elements{Common::DivCeil(program.shared_memory_size, element_size)};
|
||||
const Id array_type{TypeArray(element_type, Const(num_elements))};
|
||||
Decorate(array_type, spv::Decoration::ArrayStride, element_size);
|
||||
|
||||
@@ -661,7 +644,7 @@ void EmitContext::DefineSharedMemory(const IR::Program& program) {
|
||||
std::tie(shared_memory_u32x4, shared_u32x4, std::ignore) = make(U32[4], 16);
|
||||
return;
|
||||
}
|
||||
const u32 num_elements{Common::DivCeil(shared_memory_size, 4U)};
|
||||
const u32 num_elements{Common::DivCeil(program.shared_memory_size, 4U)};
|
||||
const Id type{TypeArray(U32[1], Const(num_elements))};
|
||||
shared_memory_u32_type = TypePointer(spv::StorageClass::Workgroup, type);
|
||||
|
||||
|
||||
@@ -312,8 +312,6 @@ public:
|
||||
Id local_memory{};
|
||||
|
||||
bool uses_explicit_workgroup_layout{};
|
||||
u32 shared_memory_declared_bytes{};
|
||||
[[nodiscard]] Id BoundSharedOffset(Id offset, u32 access_bytes);
|
||||
Id shared_memory_u8{};
|
||||
Id shared_memory_u16{};
|
||||
Id shared_memory_u32{};
|
||||
|
||||
@@ -101,9 +101,6 @@ struct Profile {
|
||||
|
||||
u32 gl_max_compute_smem_size{};
|
||||
|
||||
/// Largest workgroup shared memory allocation the device accepts, 0 when unconstrained
|
||||
u32 max_shared_memory_size{};
|
||||
|
||||
/// Maxwell and earlier nVidia architectures have broken robust support
|
||||
bool has_broken_robust{};
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -16,9 +19,11 @@ TEST_CASE("Network::Errors", "[core]") {
|
||||
}
|
||||
|
||||
Network::SockAddrIn addr{
|
||||
Network::Domain::INET,
|
||||
{127, 0, 0, 1},
|
||||
16,
|
||||
u8(Network::Domain::INET),
|
||||
1, // hopefully nobody running this test has something listening on port 1
|
||||
{127, 0, 0, 1},
|
||||
{},
|
||||
};
|
||||
REQUIRE(socks[0].Connect(addr) == Network::Errno::CONNREFUSED);
|
||||
|
||||
|
||||
@@ -373,7 +373,7 @@ else()
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-shadow>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-unused-local-typedef>)
|
||||
else()
|
||||
target_compile_options(video_core PRIVATE $<$<COMPILE_LANGUAGE:C,CXX>:-Werror=conversion>)
|
||||
target_compile_options(video_core PRIVATE $<$<COMPILE_LANGUAGE:C,CXX>:-Wconversion>)
|
||||
endif()
|
||||
|
||||
target_compile_options(video_core PRIVATE $<$<COMPILE_LANGUAGE:C,CXX>:-Wno-sign-conversion>)
|
||||
|
||||
@@ -571,11 +571,7 @@ void BufferCache<P>::AccumulateFlushes() {
|
||||
|
||||
template <class P>
|
||||
bool BufferCache<P>::ShouldWaitAsyncFlushes() const noexcept {
|
||||
if (async_buffers.empty()) {
|
||||
return false;
|
||||
}
|
||||
return async_buffers.front().has_value() ||
|
||||
!pending_downloads.front().unified_copies.empty();
|
||||
return (!async_buffers.empty() && async_buffers.front().has_value());
|
||||
}
|
||||
|
||||
template <class P>
|
||||
@@ -583,7 +579,6 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
|
||||
AccumulateFlushes();
|
||||
|
||||
if (committed_gpu_modified_ranges.empty()) {
|
||||
pending_downloads.emplace_back();
|
||||
async_buffers.emplace_back(std::optional<Async_Buffer>{});
|
||||
return;
|
||||
}
|
||||
@@ -643,84 +638,27 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
|
||||
}
|
||||
committed_gpu_modified_ranges.clear();
|
||||
if (downloads.empty()) {
|
||||
pending_downloads.emplace_back();
|
||||
async_buffers.emplace_back(std::optional<Async_Buffer>{});
|
||||
return;
|
||||
}
|
||||
|
||||
struct QueuedUnifiedCopy {
|
||||
u64 window;
|
||||
BufferId buffer_id;
|
||||
boost::container::small_vector<BufferCopy, 16> copies;
|
||||
};
|
||||
|
||||
AsyncDownloadBatch batch;
|
||||
boost::container::small_vector<std::pair<BufferCopy, BufferId>, 16> staging_downloads;
|
||||
boost::container::small_vector<QueuedUnifiedCopy, 4> unified_copy_queue;
|
||||
boost::container::small_vector<u64, 4> window_ids;
|
||||
UnifiedWindowGroups groups;
|
||||
u64 staging_size_bytes = 0;
|
||||
for (auto& [copy, buffer_id] : downloads) {
|
||||
Buffer& buffer = slot_buffers[buffer_id];
|
||||
const DAddr orig_device_addr = buffer.CpuAddr() + copy.src_offset;
|
||||
bool unified = false;
|
||||
if constexpr (USE_UNIFIED_MEMORY) {
|
||||
if (runtime.HasUnifiedMemory()) {
|
||||
window_ids.clear();
|
||||
groups.clear();
|
||||
unified = ResolveUnifiedWindows(orig_device_addr, copy.src_offset, copy.size,
|
||||
window_ids, groups);
|
||||
}
|
||||
}
|
||||
BufferCopy record{copy};
|
||||
record.src_offset = static_cast<size_t>(orig_device_addr);
|
||||
if (unified) {
|
||||
async_downloads.Add(orig_device_addr, copy.size);
|
||||
buffer.MarkUsage(copy.src_offset, copy.size);
|
||||
for (size_t i = 0; i < window_ids.size(); ++i) {
|
||||
unified_copy_queue.push_back(
|
||||
QueuedUnifiedCopy{window_ids[i], buffer_id, std::move(groups[i])});
|
||||
}
|
||||
batch.unified_copies.push_back(record);
|
||||
continue;
|
||||
}
|
||||
copy.dst_offset = staging_size_bytes;
|
||||
constexpr u64 align = 64ULL;
|
||||
staging_size_bytes += (copy.size + align - 1) & ~(align - 1ULL);
|
||||
staging_downloads.push_back({copy, buffer_id});
|
||||
}
|
||||
|
||||
std::optional<Async_Buffer> download_staging;
|
||||
if (!staging_downloads.empty()) {
|
||||
download_staging = runtime.DownloadStagingBuffer(staging_size_bytes, true);
|
||||
}
|
||||
auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes, true);
|
||||
boost::container::small_vector<BufferCopy, 4> normalized_copies;
|
||||
runtime.PreCopyBarrier();
|
||||
for (auto& [copy, buffer_id] : staging_downloads) {
|
||||
copy.dst_offset += download_staging->offset;
|
||||
for (auto& [copy, buffer_id] : downloads) {
|
||||
copy.dst_offset += download_staging.offset;
|
||||
const std::array copies{copy};
|
||||
BufferCopy second_copy{copy};
|
||||
Buffer& buffer = slot_buffers[buffer_id];
|
||||
BufferCopy record{copy};
|
||||
record.src_offset = static_cast<size_t>(buffer.CpuAddr()) + copy.src_offset;
|
||||
const DAddr orig_device_addr = static_cast<DAddr>(record.src_offset);
|
||||
second_copy.src_offset = static_cast<size_t>(buffer.CpuAddr()) + copy.src_offset;
|
||||
const DAddr orig_device_addr = static_cast<DAddr>(second_copy.src_offset);
|
||||
async_downloads.Add(orig_device_addr, copy.size);
|
||||
buffer.MarkUsage(copy.src_offset, copy.size);
|
||||
runtime.CopyBuffer(download_staging->buffer, buffer, copies, false);
|
||||
batch.staging_copies.push_back(record);
|
||||
}
|
||||
if constexpr (USE_UNIFIED_MEMORY) {
|
||||
for (const auto& queued : unified_copy_queue) {
|
||||
const std::span<const BufferCopy> group_span(queued.copies.data(),
|
||||
queued.copies.size());
|
||||
runtime.CopyToUnifiedMemory(queued.window, slot_buffers[queued.buffer_id], group_span);
|
||||
}
|
||||
if (!unified_copy_queue.empty()) {
|
||||
runtime.FlushUnifiedMemoryCopies();
|
||||
runtime.UnifiedMemoryHostBarrier();
|
||||
}
|
||||
runtime.CopyBuffer(download_staging.buffer, buffer, copies, false);
|
||||
normalized_copies.push_back(second_copy);
|
||||
}
|
||||
runtime.PostCopyBarrier();
|
||||
pending_downloads.emplace_back(std::move(batch));
|
||||
async_buffers.emplace_back(std::move(download_staging));
|
||||
pending_downloads.emplace_back(std::move(normalized_copies));
|
||||
async_buffers.emplace_back(download_staging);
|
||||
}
|
||||
|
||||
template <class P>
|
||||
@@ -735,49 +673,32 @@ void BufferCache<P>::PopAsyncFlushes() {
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::PopAsyncBuffers() {
|
||||
struct Writeback {
|
||||
DAddr addr;
|
||||
const u8* src;
|
||||
u64 size;
|
||||
};
|
||||
boost::container::small_vector<Writeback, 8> writebacks;
|
||||
{
|
||||
std::scoped_lock lock{mutex};
|
||||
if (async_buffers.empty()) {
|
||||
return;
|
||||
}
|
||||
auto& batch = pending_downloads.front();
|
||||
auto& async_buffer = async_buffers.front();
|
||||
if (async_buffer.has_value()) {
|
||||
const u8* base = async_buffer->mapped_span.data();
|
||||
const size_t base_offset = async_buffer->offset;
|
||||
for (const auto& copy : batch.staging_copies) {
|
||||
const DAddr device_addr = static_cast<DAddr>(copy.src_offset);
|
||||
const u64 dst_offset = copy.dst_offset - base_offset;
|
||||
const u8* read_mapped_memory = base + dst_offset;
|
||||
async_downloads.ForEachInRange(
|
||||
device_addr, copy.size, [&](DAddr start, DAddr end, s32) {
|
||||
writebacks.push_back(
|
||||
{start, &read_mapped_memory[start - device_addr], end - start});
|
||||
});
|
||||
async_downloads.Subtract(device_addr, copy.size, [&](DAddr start, DAddr end) {
|
||||
gpu_modified_ranges.Subtract(start, end - start);
|
||||
});
|
||||
}
|
||||
async_buffers_death_ring.emplace_back(*async_buffer);
|
||||
}
|
||||
for (const auto& copy : batch.unified_copies) {
|
||||
const DAddr device_addr = static_cast<DAddr>(copy.src_offset);
|
||||
async_downloads.Subtract(device_addr, copy.size, [&](DAddr start, DAddr end) {
|
||||
gpu_modified_ranges.Subtract(start, end - start);
|
||||
});
|
||||
}
|
||||
if (async_buffers.empty()) {
|
||||
return;
|
||||
}
|
||||
if (!async_buffers.front().has_value()) {
|
||||
async_buffers.pop_front();
|
||||
pending_downloads.pop_front();
|
||||
return;
|
||||
}
|
||||
for (const auto& wb : writebacks) {
|
||||
device_memory.WriteBlockUnsafe(wb.addr, wb.src, wb.size);
|
||||
auto& downloads = pending_downloads.front();
|
||||
auto& async_buffer = async_buffers.front();
|
||||
u8* base = async_buffer->mapped_span.data();
|
||||
const size_t base_offset = async_buffer->offset;
|
||||
for (const auto& copy : downloads) {
|
||||
const DAddr device_addr = static_cast<DAddr>(copy.src_offset);
|
||||
const u64 dst_offset = copy.dst_offset - base_offset;
|
||||
const u8* read_mapped_memory = base + dst_offset;
|
||||
async_downloads.ForEachInRange(device_addr, copy.size, [&](DAddr start, DAddr end, s32) {
|
||||
device_memory.WriteBlockUnsafe(start, &read_mapped_memory[start - device_addr],
|
||||
end - start);
|
||||
});
|
||||
async_downloads.Subtract(device_addr, copy.size, [&](DAddr start, DAddr end) {
|
||||
gpu_modified_ranges.Subtract(start, end - start);
|
||||
});
|
||||
}
|
||||
async_buffers_death_ring.emplace_back(*async_buffer);
|
||||
async_buffers.pop_front();
|
||||
pending_downloads.pop_front();
|
||||
}
|
||||
|
||||
template <class P>
|
||||
@@ -1778,99 +1699,6 @@ void BufferCache<P>::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer,
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
bool BufferCache<P>::ResolveUnifiedWindows(
|
||||
[[maybe_unused]] DAddr device_addr, [[maybe_unused]] u64 buffer_offset,
|
||||
[[maybe_unused]] u64 size, [[maybe_unused]] boost::container::small_vector<u64, 4>& window_ids,
|
||||
[[maybe_unused]] UnifiedWindowGroups& groups) {
|
||||
if constexpr (USE_UNIFIED_MEMORY) {
|
||||
const u8* const physical_base = device_memory.GetPhysicalBase();
|
||||
const u64 unified_base = runtime.UnifiedMemoryBase();
|
||||
const u64 unified_size = runtime.UnifiedMemorySize();
|
||||
const u64 window_size = runtime.UnifiedMemoryWindowSize();
|
||||
if (window_size == 0) {
|
||||
return false;
|
||||
}
|
||||
const auto group_for = [&](u64 window) -> boost::container::small_vector<BufferCopy, 16>& {
|
||||
for (size_t i = 0; i < window_ids.size(); ++i) {
|
||||
if (window_ids[i] == window) {
|
||||
return groups[i];
|
||||
}
|
||||
}
|
||||
window_ids.push_back(window);
|
||||
groups.emplace_back();
|
||||
return groups.back();
|
||||
};
|
||||
u64 downloaded = 0;
|
||||
while (downloaded < size) {
|
||||
const DAddr page_addr = device_addr + downloaded;
|
||||
const u8* const ptr = device_memory.GetPointer<u8>(page_addr);
|
||||
if (ptr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const u64 page_offset = page_addr & Core::DEVICE_PAGEMASK;
|
||||
u64 chunk = (std::min)(size - downloaded,
|
||||
static_cast<u64>(Core::DEVICE_PAGESIZE) - page_offset);
|
||||
const u64 phys_offset = static_cast<u64>(ptr - physical_base);
|
||||
if (phys_offset < unified_base || phys_offset - unified_base + chunk > unified_size) {
|
||||
return false;
|
||||
}
|
||||
const u64 relative = phys_offset - unified_base;
|
||||
const u64 window = relative / window_size;
|
||||
const u64 local_offset = relative % window_size;
|
||||
chunk = (std::min)(chunk, window_size - local_offset);
|
||||
auto& group = group_for(window);
|
||||
if (!group.empty()) {
|
||||
BufferCopy& last = group.back();
|
||||
if (last.src_offset + last.size == buffer_offset + downloaded &&
|
||||
last.dst_offset + last.size == local_offset) {
|
||||
last.size += chunk;
|
||||
downloaded += chunk;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
group.push_back(BufferCopy{
|
||||
.src_offset = buffer_offset + downloaded,
|
||||
.dst_offset = local_offset,
|
||||
.size = chunk,
|
||||
});
|
||||
downloaded += chunk;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
bool BufferCache<P>::TryUnifiedDownloadMemory([[maybe_unused]] Buffer& buffer,
|
||||
[[maybe_unused]] std::span<BufferCopy> copies) {
|
||||
if constexpr (USE_UNIFIED_MEMORY) {
|
||||
boost::container::small_vector<u64, 4> window_ids;
|
||||
UnifiedWindowGroups groups;
|
||||
for (const BufferCopy& copy : copies) {
|
||||
if (!ResolveUnifiedWindows(buffer.CpuAddr() + copy.src_offset, copy.src_offset,
|
||||
copy.size, window_ids, groups)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const BufferCopy& copy : copies) {
|
||||
buffer.MarkUsage(copy.src_offset, copy.size);
|
||||
}
|
||||
runtime.PreCopyBarrier();
|
||||
for (size_t i = 0; i < window_ids.size(); ++i) {
|
||||
const std::span<const BufferCopy> group_span(groups[i].data(), groups[i].size());
|
||||
runtime.CopyToUnifiedMemory(window_ids[i], buffer, group_span);
|
||||
}
|
||||
runtime.FlushUnifiedMemoryCopies();
|
||||
runtime.UnifiedMemoryHostBarrier();
|
||||
runtime.Finish();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::MappedUploadMemory([[maybe_unused]] Buffer& buffer,
|
||||
[[maybe_unused]] u64 total_size_bytes,
|
||||
@@ -1974,12 +1802,6 @@ void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, DAddr device_addr, u64
|
||||
}
|
||||
|
||||
if constexpr (USE_MEMORY_MAPS) {
|
||||
if constexpr (USE_UNIFIED_MEMORY) {
|
||||
if (runtime.HasUnifiedMemory() &&
|
||||
TryUnifiedDownloadMemory(buffer, std::span(copies.data(), copies.size()))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes);
|
||||
const u8* const mapped_memory = download_staging.mapped_span.data();
|
||||
const std::span<BufferCopy> copies_span(copies.data(), copies.data() + copies.size());
|
||||
|
||||
@@ -180,7 +180,6 @@ class BufferCache : public VideoCommon::ChannelSetupCaches<BufferCacheChannelInf
|
||||
static constexpr bool USE_MEMORY_MAPS = P::USE_MEMORY_MAPS;
|
||||
static constexpr bool SEPARATE_IMAGE_BUFFERS_BINDINGS = P::SEPARATE_IMAGE_BUFFER_BINDINGS;
|
||||
static constexpr bool USE_MEMORY_MAPS_FOR_UPLOADS = P::USE_MEMORY_MAPS_FOR_UPLOADS;
|
||||
static constexpr bool USE_UNIFIED_MEMORY = P::USE_UNIFIED_MEMORY;
|
||||
|
||||
#ifdef YUZU_LEGACY
|
||||
static constexpr s64 TARGET_THRESHOLD = 3_GiB;
|
||||
@@ -444,15 +443,6 @@ private:
|
||||
|
||||
void MappedUploadMemory(Buffer& buffer, u64 total_size_bytes, std::span<BufferCopy> copies);
|
||||
|
||||
bool TryUnifiedDownloadMemory(Buffer& buffer, std::span<BufferCopy> copies);
|
||||
|
||||
using UnifiedWindowGroups =
|
||||
boost::container::small_vector<boost::container::small_vector<BufferCopy, 16>, 4>;
|
||||
|
||||
bool ResolveUnifiedWindows(DAddr device_addr, u64 buffer_offset, u64 size,
|
||||
boost::container::small_vector<u64, 4>& window_ids,
|
||||
UnifiedWindowGroups& groups);
|
||||
|
||||
void DownloadBufferMemory(Buffer& buffer_id);
|
||||
|
||||
void DownloadBufferMemory(Buffer& buffer_id, DAddr device_addr, u64 size);
|
||||
@@ -508,14 +498,9 @@ private:
|
||||
std::deque<Common::RangeSet<DAddr>> committed_gpu_modified_ranges;
|
||||
|
||||
// Async Buffers
|
||||
struct AsyncDownloadBatch {
|
||||
boost::container::small_vector<BufferCopy, 4> staging_copies;
|
||||
boost::container::small_vector<BufferCopy, 4> unified_copies;
|
||||
};
|
||||
|
||||
Common::OverlapRangeSet<DAddr> async_downloads;
|
||||
std::deque<std::optional<Async_Buffer>> async_buffers;
|
||||
std::deque<AsyncDownloadBatch> pending_downloads;
|
||||
std::deque<boost::container::small_vector<BufferCopy, 4>> pending_downloads;
|
||||
std::optional<Async_Buffer> current_buffer;
|
||||
|
||||
std::deque<Async_Buffer> async_buffers_death_ring;
|
||||
|
||||
@@ -2257,7 +2257,7 @@ public:
|
||||
/// Returns whether the vertex array specified by index is supposed to be
|
||||
/// accessed per instance or not.
|
||||
bool IsInstancingEnabled(std::size_t index) const {
|
||||
return bool(is_instanced[index]); //FUCK YOU MSVC
|
||||
return bool(is_instanced[index]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@ public:
|
||||
}
|
||||
|
||||
struct Regs {
|
||||
// No fucking idea
|
||||
INSERT_PADDING_BYTES_NOINIT(0x48);
|
||||
} regs{};
|
||||
private:
|
||||
|
||||
@@ -963,7 +963,7 @@ void Vic::WriteABGR(const OutputSurfaceConfig& output_surface_config, VideoPixel
|
||||
auto pixel1213 = _mm_load_si128((__m128i*)&inp[src + x + 12]);
|
||||
auto pixel1415 = _mm_load_si128((__m128i*)&inp[src + x + 14]);
|
||||
|
||||
// Right-shift the channels by 16 to un-do the left shit on read and bring the range
|
||||
// Right-shift the channels by 16 to un-do the left shift on read and bring the range
|
||||
// back to 8-bit.
|
||||
pixel01 = _mm_srli_epi16(pixel01, 2);
|
||||
pixel23 = _mm_srli_epi16(pixel23, 2);
|
||||
|
||||
@@ -88,7 +88,7 @@ set(SHADER_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/sgsr1_shader_mobile_edge_direction.frag
|
||||
)
|
||||
|
||||
if (PLATFORM_HAIKU)
|
||||
if (HAIKUOS)
|
||||
# glslangValidator WILL crash, glslang will not
|
||||
set(GLSLANGVALIDATOR "glslang")
|
||||
else()
|
||||
|
||||
@@ -441,7 +441,7 @@ void MacroInterpreterImpl::Reset() {
|
||||
pc = 0;
|
||||
delayed_pc = {};
|
||||
method_address.raw = 0;
|
||||
// Vector must hold its last indices otherwise wonky shit will happen
|
||||
// Vector must hold its last indices otherwise chaos will ensue
|
||||
// The next parameter index starts at 1, because $r1 already has the value of the first
|
||||
// parameter.
|
||||
next_parameter_index = 1;
|
||||
|
||||
@@ -261,7 +261,6 @@ struct BufferCacheParams {
|
||||
|
||||
// TODO: Investigate why OpenGL seems to perform worse with persistently mapped buffer uploads
|
||||
static constexpr bool USE_MEMORY_MAPS_FOR_UPLOADS = false;
|
||||
static constexpr bool USE_UNIFIED_MEMORY = false;
|
||||
};
|
||||
|
||||
using BufferCache = VideoCommon::BufferCache<BufferCacheParams>;
|
||||
|
||||
@@ -59,7 +59,7 @@ std::vector<std::string> GetExtensions() {
|
||||
std::vector<std::string> extensions;
|
||||
for (GLint index = 0; index < num_extensions; ++index) {
|
||||
auto const* p = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, GLuint(index)));
|
||||
if (p != nullptr) // Fuck you? - sincerely, buggy mesa drivers
|
||||
if (p != nullptr)
|
||||
extensions.push_back(std::string{p});
|
||||
}
|
||||
return extensions;
|
||||
|
||||
@@ -237,7 +237,6 @@ ShaderCache::ShaderCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
.has_gl_bool_ref_bug = device.HasBoolRefBug(),
|
||||
.ignore_nan_fp_comparisons = true,
|
||||
.gl_max_compute_smem_size = device.GetMaxComputeSharedMemorySize(),
|
||||
.max_shared_memory_size = device.GetMaxComputeSharedMemorySize(),
|
||||
.min_ssbo_alignment = device.GetShaderStorageBufferAlignment(),
|
||||
// Use the host limit, but never more than the guest can produce. Maxwell exposes 8 clip
|
||||
// distances and the SPIR-V output array is sized for at most 8, so clamping here keeps a
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <span>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "video_core/buffer_cache/buffer_cache_base.h"
|
||||
@@ -33,32 +32,6 @@ VkBufferCopy MakeBufferCopy(const VideoCommon::BufferCopy& copy) {
|
||||
};
|
||||
}
|
||||
|
||||
constexpr size_t MAX_WINDOW_BARRIER_RANGES = 8;
|
||||
|
||||
using WindowRange = std::pair<VkDeviceSize, VkDeviceSize>;
|
||||
using WindowRanges = boost::container::small_vector<WindowRange, MAX_WINDOW_BARRIER_RANGES>;
|
||||
|
||||
void CoalesceWindowRanges(WindowRanges& ranges) {
|
||||
if (ranges.size() < 2) {
|
||||
return;
|
||||
}
|
||||
std::sort(ranges.begin(), ranges.end());
|
||||
size_t merged = 0;
|
||||
for (size_t index = 1; index < ranges.size(); ++index) {
|
||||
if (ranges[index].first <= ranges[merged].second) {
|
||||
ranges[merged].second = (std::max)(ranges[merged].second, ranges[index].second);
|
||||
} else {
|
||||
ranges[++merged] = ranges[index];
|
||||
}
|
||||
}
|
||||
ranges.resize(merged + 1);
|
||||
if (ranges.size() > MAX_WINDOW_BARRIER_RANGES) {
|
||||
const WindowRange bounding{ranges.front().first, ranges.back().second};
|
||||
ranges.clear();
|
||||
ranges.push_back(bounding);
|
||||
}
|
||||
}
|
||||
|
||||
VkIndexType IndexTypeFromNumElements(const Device& device, u32 num_elements) {
|
||||
if (num_elements <= 0xff && device.IsExtIndexTypeUint8Supported()) {
|
||||
return VK_INDEX_TYPE_UINT8_EXT;
|
||||
@@ -392,141 +365,6 @@ BufferCacheRuntime::BufferCacheRuntime(const Device& device_, MemoryAllocator& m
|
||||
scheduler_, staging_pool_);
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::TryEnableUnifiedMemory(void* base, size_t size,
|
||||
std::span<AHardwareBuffer* const> hardware_buffers,
|
||||
size_t hardware_buffer_window,
|
||||
size_t hardware_buffer_base) {
|
||||
unified_memory = std::make_unique<HostMemoryImport>(
|
||||
device, base, size, hardware_buffers, hardware_buffer_window, hardware_buffer_base);
|
||||
if (!unified_memory->IsValid()) {
|
||||
unified_memory.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::CopyToUnifiedMemory(
|
||||
size_t window_index, VkBuffer src_buffer,
|
||||
std::span<const VideoCommon::BufferCopy> copies) {
|
||||
if (!unified_memory || src_buffer == VK_NULL_HANDLE || copies.empty() ||
|
||||
window_index >= unified_memory->GetWindowCount() ||
|
||||
unified_memory->GetWindowBuffer(window_index) == VK_NULL_HANDLE) {
|
||||
return;
|
||||
}
|
||||
PendingUnifiedCopy& pending = pending_unified_copies.emplace_back();
|
||||
pending.window = window_index;
|
||||
pending.buffer = src_buffer;
|
||||
pending.copies.resize(copies.size());
|
||||
std::ranges::transform(copies, pending.copies.begin(), MakeBufferCopy);
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::FlushUnifiedMemoryCopies() {
|
||||
if (pending_unified_copies.empty()) {
|
||||
return;
|
||||
}
|
||||
struct UnifiedCopyCommand {
|
||||
VkBuffer buffer;
|
||||
boost::container::small_vector<VkBufferCopy, 8> copies;
|
||||
};
|
||||
|
||||
std::stable_sort(pending_unified_copies.begin(), pending_unified_copies.end(),
|
||||
[](const PendingUnifiedCopy& lhs, const PendingUnifiedCopy& rhs) {
|
||||
return lhs.window < rhs.window;
|
||||
});
|
||||
|
||||
const bool foreign = unified_memory->NeedsForeignOwnershipTransfer();
|
||||
const u32 queue_family = device.GetGraphicsFamily();
|
||||
|
||||
size_t group_begin = 0;
|
||||
while (group_begin < pending_unified_copies.size()) {
|
||||
const size_t window = pending_unified_copies[group_begin].window;
|
||||
size_t group_end = group_begin;
|
||||
while (group_end < pending_unified_copies.size() &&
|
||||
pending_unified_copies[group_end].window == window) {
|
||||
++group_end;
|
||||
}
|
||||
const VkBuffer window_buffer = unified_memory->GetWindowBuffer(window);
|
||||
|
||||
WindowRanges ranges;
|
||||
for (size_t index = group_begin; index < group_end; ++index) {
|
||||
for (const VkBufferCopy& copy : pending_unified_copies[index].copies) {
|
||||
ranges.emplace_back(copy.dstOffset, copy.dstOffset + copy.size);
|
||||
}
|
||||
}
|
||||
CoalesceWindowRanges(ranges);
|
||||
|
||||
boost::container::small_vector<VkBufferMemoryBarrier, MAX_WINDOW_BARRIER_RANGES> acquire;
|
||||
boost::container::small_vector<VkBufferMemoryBarrier, MAX_WINDOW_BARRIER_RANGES> release;
|
||||
if (foreign) {
|
||||
for (const WindowRange& range : ranges) {
|
||||
acquire.push_back(VkBufferMemoryBarrier{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = 0,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT,
|
||||
.dstQueueFamilyIndex = queue_family,
|
||||
.buffer = window_buffer,
|
||||
.offset = range.first,
|
||||
.size = range.second - range.first,
|
||||
});
|
||||
release.push_back(VkBufferMemoryBarrier{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = 0,
|
||||
.srcQueueFamilyIndex = queue_family,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT,
|
||||
.buffer = window_buffer,
|
||||
.offset = range.first,
|
||||
.size = range.second - range.first,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
boost::container::small_vector<UnifiedCopyCommand, 4> commands;
|
||||
commands.reserve(group_end - group_begin);
|
||||
for (size_t index = group_begin; index < group_end; ++index) {
|
||||
PendingUnifiedCopy& pending = pending_unified_copies[index];
|
||||
commands.push_back(UnifiedCopyCommand{pending.buffer, std::move(pending.copies)});
|
||||
}
|
||||
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([window_buffer, acquire = std::move(acquire), release = std::move(release),
|
||||
commands = std::move(commands)](vk::CommandBuffer cmdbuf) {
|
||||
if (!acquire.empty()) {
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, {},
|
||||
VideoCommon::FixSmallVectorADL(acquire), {});
|
||||
}
|
||||
for (const UnifiedCopyCommand& command : commands) {
|
||||
cmdbuf.CopyBuffer(command.buffer, window_buffer,
|
||||
VideoCommon::FixSmallVectorADL(command.copies));
|
||||
}
|
||||
if (!release.empty()) {
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, {},
|
||||
VideoCommon::FixSmallVectorADL(release), {});
|
||||
}
|
||||
});
|
||||
|
||||
group_begin = group_end;
|
||||
}
|
||||
pending_unified_copies.clear();
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::UnifiedMemoryHostBarrier() {
|
||||
static constexpr VkMemoryBarrier HOST_BARRIER{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_HOST_READ_BIT,
|
||||
};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0,
|
||||
HOST_BARRIER);
|
||||
});
|
||||
}
|
||||
|
||||
StagingBufferRef BufferCacheRuntime::UploadStagingBuffer(size_t size) {
|
||||
return staging_pool.Request(size, MemoryUsage::Upload);
|
||||
}
|
||||
@@ -564,7 +402,6 @@ u32 BufferCacheRuntime::GetStorageBufferAlignment() const {
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::TickFrame(Common::SlotVector<Buffer>& slot_buffers) noexcept {
|
||||
FlushUnifiedMemoryCopies();
|
||||
for (auto it = slot_buffers.begin(); it != slot_buffers.end(); it++) {
|
||||
if (scheduler.IsFree(it->LastUsageTick())) {
|
||||
it->ResetUsageTracking();
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
#include "video_core/buffer_cache/buffer_cache_base.h"
|
||||
#include "video_core/buffer_cache/memory_tracker_base.h"
|
||||
@@ -101,33 +97,6 @@ public:
|
||||
|
||||
void TickFrame(Common::SlotVector<Buffer>& slot_buffers) noexcept;
|
||||
|
||||
void TryEnableUnifiedMemory(void* base, size_t size,
|
||||
std::span<AHardwareBuffer* const> hardware_buffers,
|
||||
size_t hardware_buffer_window, size_t hardware_buffer_base);
|
||||
|
||||
[[nodiscard]] bool HasUnifiedMemory() const noexcept {
|
||||
return unified_memory != nullptr && unified_memory->IsValid();
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 UnifiedMemorySize() const noexcept {
|
||||
return unified_memory ? unified_memory->GetSize() : 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 UnifiedMemoryBase() const noexcept {
|
||||
return unified_memory ? unified_memory->GetBaseOffset() : 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 UnifiedMemoryWindowSize() const noexcept {
|
||||
return unified_memory ? unified_memory->GetWindowSize() : 0;
|
||||
}
|
||||
|
||||
void CopyToUnifiedMemory(size_t window_index, VkBuffer src_buffer,
|
||||
std::span<const VideoCommon::BufferCopy> copies);
|
||||
|
||||
void FlushUnifiedMemoryCopies();
|
||||
|
||||
void UnifiedMemoryHostBarrier();
|
||||
|
||||
u64 CurrentTick();
|
||||
|
||||
u64 KnownGpuTick();
|
||||
@@ -211,12 +180,6 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
struct PendingUnifiedCopy {
|
||||
size_t window;
|
||||
VkBuffer buffer;
|
||||
boost::container::small_vector<VkBufferCopy, 8> copies;
|
||||
};
|
||||
|
||||
void BindBuffer(const Buffer& buffer, u32 offset, u32 size) {
|
||||
const VkBuffer handle = buffer.Handle();
|
||||
if (handle == VK_NULL_HANDLE) {
|
||||
@@ -241,8 +204,6 @@ private:
|
||||
std::shared_ptr<QuadStripIndexBuffer> quad_strip_index_buffer;
|
||||
|
||||
vk::Buffer null_buffer;
|
||||
std::unique_ptr<HostMemoryImport> unified_memory;
|
||||
boost::container::small_vector<PendingUnifiedCopy, 8> pending_unified_copies;
|
||||
|
||||
std::unique_ptr<Uint8Pass> uint8_pass;
|
||||
QuadIndexedPass quad_index_pass;
|
||||
@@ -265,7 +226,6 @@ struct BufferCacheParams {
|
||||
static constexpr bool USE_MEMORY_MAPS = true;
|
||||
static constexpr bool SEPARATE_IMAGE_BUFFER_BINDINGS = false;
|
||||
static constexpr bool USE_MEMORY_MAPS_FOR_UPLOADS = true;
|
||||
static constexpr bool USE_UNIFIED_MEMORY = true;
|
||||
};
|
||||
|
||||
using BufferCache = VideoCommon::BufferCache<BufferCacheParams>;
|
||||
|
||||
@@ -446,7 +446,6 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
.has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY,
|
||||
.ignore_nan_fp_comparisons = false,
|
||||
.has_broken_spirv_subgroup_mask_vector_extract_dynamic = false,
|
||||
.max_shared_memory_size = device.GetMaxComputeSharedMemorySize(),
|
||||
.has_broken_robust =
|
||||
device.IsNvidia() && device.GetNvidiaArch() <= NvidiaArchitecture::Arch_Pascal,
|
||||
.min_ssbo_alignment = device.GetStorageBufferAlignment(),
|
||||
@@ -922,6 +921,19 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
|
||||
}
|
||||
|
||||
auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)};
|
||||
const VkDriverIdKHR driver_id = device.GetDriverID();
|
||||
const bool needs_shared_mem_clamp =
|
||||
driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY ||
|
||||
driver_id == VK_DRIVER_ID_ARM_PROPRIETARY;
|
||||
const u32 max_shared_memory = device.GetMaxComputeSharedMemorySize();
|
||||
if (needs_shared_mem_clamp && program.shared_memory_size > max_shared_memory) {
|
||||
LOG_WARNING(Render_Vulkan,
|
||||
"Compute shader {:#016x} requests {}KB shared memory but device max is {}KB - clamping",
|
||||
key.unique_hash,
|
||||
program.shared_memory_size / 1024,
|
||||
max_shared_memory / 1024);
|
||||
program.shared_memory_size = max_shared_memory;
|
||||
}
|
||||
const std::vector<u32> code{EmitSPIRV(profile, program)};
|
||||
device.SaveShader(code);
|
||||
vk::ShaderModule spv_module{BuildShader(device, code)};
|
||||
|
||||
@@ -225,13 +225,6 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
|
||||
fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler),
|
||||
wfi_event(device.GetLogical().CreateEvent()) {
|
||||
scheduler.SetQueryCache(query_cache);
|
||||
if (Settings::values.use_unified_memory.GetValue() && device_memory.IsBackingShared()) {
|
||||
buffer_cache_runtime.TryEnableUnifiedMemory(
|
||||
device_memory.GetPhysicalBase(), device_memory.GetPhysicalSize(),
|
||||
device_memory.GetBackingHardwareBuffers(),
|
||||
device_memory.GetBackingHardwareBufferWindowSize(),
|
||||
device_memory.GetBackingHardwareBufferBase());
|
||||
}
|
||||
}
|
||||
|
||||
RasterizerVulkan::~RasterizerVulkan() {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/host_memory.h"
|
||||
#include "common/literals.h"
|
||||
#include <ranges>
|
||||
#include "common/settings.h"
|
||||
@@ -975,7 +974,6 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||
|
||||
FOR_EACH_VK_FEATURE_EXT(FEATURE_EXTENSION);
|
||||
FOR_EACH_VK_EXTENSION(EXTENSION);
|
||||
FOR_EACH_VK_PLATFORM_EXTENSION(EXTENSION);
|
||||
|
||||
if (supported_extensions.contains(VK_KHR_ROBUSTNESS_2_EXTENSION_NAME)) {
|
||||
loaded_extensions.erase(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME);
|
||||
@@ -988,13 +986,6 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||
extensions.robustness_2 = false;
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if (extensions.external_memory_ahb && !extensions.queue_family_foreign) {
|
||||
loaded_extensions.erase(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME);
|
||||
extensions.external_memory_ahb = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef FEATURE_EXTENSION
|
||||
#undef EXTENSION
|
||||
|
||||
@@ -1151,21 +1142,6 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES_KHR;
|
||||
SetNext(next, properties.maintenance5);
|
||||
}
|
||||
if (extensions.external_memory_host) {
|
||||
properties.external_memory_host.sType =
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT;
|
||||
SetNext(next, properties.external_memory_host);
|
||||
}
|
||||
if (extensions.maintenance3 || instance_version >= VK_API_VERSION_1_1) {
|
||||
properties.maintenance3.sType =
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES;
|
||||
SetNext(next, properties.maintenance3);
|
||||
}
|
||||
if (extensions.maintenance4 || features.maintenance4.maintenance4) {
|
||||
properties.maintenance4.sType =
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES;
|
||||
SetNext(next, properties.maintenance4);
|
||||
}
|
||||
|
||||
// Perform the property fetch.
|
||||
physical.GetProperties2(properties2);
|
||||
@@ -1540,27 +1516,12 @@ void Device::CollectPhysicalMemoryInfo() {
|
||||
device_access_memory = 0;
|
||||
u64 device_initial_usage = 0;
|
||||
u64 local_memory = 0;
|
||||
const auto heap_has_usable_type = [&mem_properties](size_t heap) {
|
||||
for (u32 index = 0; index < mem_properties.memoryTypeCount; ++index) {
|
||||
if (mem_properties.memoryTypes[index].heapIndex != heap) {
|
||||
continue;
|
||||
}
|
||||
if ((mem_properties.memoryTypes[index].propertyFlags &
|
||||
VK_MEMORY_PROPERTY_PROTECTED_BIT) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
for (size_t element = 0; element < num_properties; ++element) {
|
||||
const bool is_heap_local =
|
||||
(mem_properties.memoryHeaps[element].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0;
|
||||
if (!is_integrated && !is_heap_local) {
|
||||
continue;
|
||||
}
|
||||
if (!heap_has_usable_type(element)) {
|
||||
continue;
|
||||
}
|
||||
valid_heap_memory.push_back(element);
|
||||
if (is_heap_local) {
|
||||
local_memory += mem_properties.memoryHeaps[element].size;
|
||||
@@ -1572,13 +1533,6 @@ void Device::CollectPhysicalMemoryInfo() {
|
||||
}
|
||||
device_access_memory += mem_properties.memoryHeaps[element].size;
|
||||
}
|
||||
const u64 committed_backing = Common::GetCommittedBackingSize();
|
||||
if (committed_backing != 0) {
|
||||
LOG_INFO(Render_Vulkan, "Discounting {} MiB of guest memory committed by the host",
|
||||
committed_backing >> 20);
|
||||
local_memory -= std::min(local_memory, committed_backing);
|
||||
device_access_memory -= std::min(device_access_memory, committed_backing);
|
||||
}
|
||||
if (is_integrated) {
|
||||
const s64 available_memory = static_cast<s64>(device_access_memory - device_initial_usage);
|
||||
const u64 memory_size = Settings::values.vram_usage_mode.GetValue() == Settings::VramUsageMode::Aggressive ? 6_GiB : 4_GiB;
|
||||
|
||||
@@ -83,7 +83,6 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
||||
EXTENSION(EXT, CONDITIONAL_RENDERING, conditional_rendering) \
|
||||
EXTENSION(EXT, CONSERVATIVE_RASTERIZATION, conservative_rasterization) \
|
||||
EXTENSION(EXT, DEPTH_RANGE_UNRESTRICTED, depth_range_unrestricted) \
|
||||
EXTENSION(EXT, EXTERNAL_MEMORY_HOST, external_memory_host) \
|
||||
EXTENSION(EXT, MEMORY_BUDGET, memory_budget) \
|
||||
EXTENSION(EXT, ROBUSTNESS_2, robustness_2) \
|
||||
EXTENSION(EXT, SAMPLER_FILTER_MINMAX, sampler_filter_minmax) \
|
||||
@@ -113,14 +112,6 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
||||
EXTENSION(IMG, FILTER_CUBIC, filter_cubic_img) \
|
||||
EXTENSION(QCOM, FILTER_CUBIC_WEIGHTS, filter_cubic_weights)
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#define FOR_EACH_VK_PLATFORM_EXTENSION(EXTENSION) \
|
||||
EXTENSION(EXT, QUEUE_FAMILY_FOREIGN, queue_family_foreign) \
|
||||
EXTENSION(ANDROID, EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER, external_memory_ahb)
|
||||
#else
|
||||
#define FOR_EACH_VK_PLATFORM_EXTENSION(EXTENSION)
|
||||
#endif
|
||||
|
||||
// Define extensions which must be supported.
|
||||
#define FOR_EACH_VK_MANDATORY_EXTENSION(EXTENSION_NAME) \
|
||||
EXTENSION_NAME(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME) \
|
||||
@@ -847,30 +838,6 @@ FN_MAX_LIMIT_LIST
|
||||
return extensions.conditional_rendering;
|
||||
}
|
||||
|
||||
bool IsExtExternalMemoryHostSupported() const {
|
||||
return extensions.external_memory_host;
|
||||
}
|
||||
|
||||
bool IsExtExternalMemoryAhbSupported() const {
|
||||
#ifdef __ANDROID__
|
||||
return extensions.external_memory_ahb && extensions.queue_family_foreign;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
u64 GetMinImportedHostPointerAlignment() const {
|
||||
return properties.external_memory_host.minImportedHostPointerAlignment;
|
||||
}
|
||||
|
||||
u64 GetMaxBufferSize() const {
|
||||
return properties.maintenance4.maxBufferSize;
|
||||
}
|
||||
|
||||
u64 GetMaxMemoryAllocationSize() const {
|
||||
return properties.maintenance3.maxMemoryAllocationSize;
|
||||
}
|
||||
|
||||
bool IsExtAstcDecodeModeSupported() const {
|
||||
return extensions.astc_decode_mode;
|
||||
}
|
||||
@@ -1143,7 +1110,6 @@ private:
|
||||
FOR_EACH_VK_FEATURE_1_4(FEATURE);
|
||||
FOR_EACH_VK_FEATURE_EXT(FEATURE);
|
||||
FOR_EACH_VK_EXTENSION(EXTENSION);
|
||||
FOR_EACH_VK_PLATFORM_EXTENSION(EXTENSION);
|
||||
|
||||
#undef EXTENSION
|
||||
#undef FEATURE
|
||||
@@ -1175,10 +1141,7 @@ private:
|
||||
VkPhysicalDeviceDescriptorBufferPropertiesEXT descriptor_buffer{};
|
||||
VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{};
|
||||
VkPhysicalDeviceTransformFeedbackPropertiesEXT transform_feedback{};
|
||||
VkPhysicalDeviceMaintenance3Properties maintenance3{};
|
||||
VkPhysicalDeviceMaintenance4Properties maintenance4{};
|
||||
VkPhysicalDeviceMaintenance5PropertiesKHR maintenance5{};
|
||||
VkPhysicalDeviceExternalMemoryHostPropertiesEXT external_memory_host{};
|
||||
|
||||
VkPhysicalDeviceProperties properties{};
|
||||
};
|
||||
|
||||
@@ -25,34 +25,9 @@
|
||||
#include "video_core/gpu_logging/gpu_logging.h"
|
||||
#include "common/settings.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/hardware_buffer.h>
|
||||
#endif
|
||||
|
||||
namespace Vulkan {
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] std::optional<u32> FindImportMemoryType(
|
||||
const VkPhysicalDeviceMemoryProperties &props, u32 type_mask) {
|
||||
const auto find = [&](VkMemoryPropertyFlags wanted) -> std::optional<u32> {
|
||||
for (u32 i = 0; i < props.memoryTypeCount; ++i) {
|
||||
if (((type_mask >> i) & 1u) != 0 &&
|
||||
(props.memoryTypes[i].propertyFlags & wanted) == wanted) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
};
|
||||
auto type_index = find(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
|
||||
if (!type_index) {
|
||||
type_index = find(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
}
|
||||
return type_index;
|
||||
}
|
||||
|
||||
// Helpers translating MemoryUsage to flags/usage
|
||||
|
||||
[[maybe_unused]] VkMemoryPropertyFlags MemoryUsagePropertyFlags(MemoryUsage usage) {
|
||||
@@ -225,263 +200,6 @@ namespace Vulkan {
|
||||
size = 0;
|
||||
}
|
||||
|
||||
HostMemoryImport::HostMemoryImport(const Device &device_, void *base, size_t size,
|
||||
std::span<AHardwareBuffer *const> hardware_buffers,
|
||||
size_t hardware_buffer_window, size_t hardware_buffer_base)
|
||||
: device{device_} {
|
||||
if (ImportHardwareBuffers(hardware_buffers, hardware_buffer_window, hardware_buffer_base,
|
||||
size)) {
|
||||
return;
|
||||
}
|
||||
if (device.IsTiler()) {
|
||||
return;
|
||||
}
|
||||
if (!hardware_buffers.empty()) {
|
||||
return;
|
||||
}
|
||||
if (ImportHostPointer(base, size)) {
|
||||
return;
|
||||
}
|
||||
LOG_INFO(Render_Vulkan, "Unified memory disabled, no host memory import path");
|
||||
}
|
||||
|
||||
bool HostMemoryImport::ImportHostPointer(void *base, size_t size) {
|
||||
if (!device.IsExtExternalMemoryHostSupported()) {
|
||||
return false;
|
||||
}
|
||||
const u64 alignment = device.GetMinImportedHostPointerAlignment();
|
||||
if (alignment == 0 || !Common::IsAligned(reinterpret_cast<uintptr_t>(base), alignment) ||
|
||||
!Common::IsAligned(size, alignment)) {
|
||||
return false;
|
||||
}
|
||||
using namespace Common::Literals;
|
||||
constexpr VkDeviceSize DesktopWindowSize = 4_GiB;
|
||||
VkDeviceSize candidate_window = DesktopWindowSize;
|
||||
const u64 max_buffer_size = device.GetMaxBufferSize();
|
||||
if (max_buffer_size != 0 && max_buffer_size < candidate_window) {
|
||||
candidate_window = max_buffer_size;
|
||||
}
|
||||
const u64 max_allocation_size = device.GetMaxMemoryAllocationSize();
|
||||
if (max_allocation_size != 0 && max_allocation_size < candidate_window) {
|
||||
candidate_window = max_allocation_size;
|
||||
}
|
||||
candidate_window = Common::AlignDown(candidate_window, alignment);
|
||||
if (candidate_window == 0) {
|
||||
return false;
|
||||
}
|
||||
window_size = candidate_window;
|
||||
|
||||
const auto &logical = device.GetLogical();
|
||||
const auto memory_props = device.GetPhysical().GetMemoryProperties().memoryProperties;
|
||||
|
||||
for (size_t offset = 0; offset < size; offset += window_size) {
|
||||
u8 *const window_base = static_cast<u8 *>(base) + offset;
|
||||
const VkDeviceSize window_len =
|
||||
(std::min)(static_cast<VkDeviceSize>(size - offset), window_size);
|
||||
VkMemoryHostPointerPropertiesEXT host_props{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT,
|
||||
.pNext = nullptr,
|
||||
.memoryTypeBits = 0,
|
||||
};
|
||||
if (logical.GetMemoryHostPointerPropertiesEXT(
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT, window_base,
|
||||
&host_props) != VK_SUCCESS ||
|
||||
host_props.memoryTypeBits == 0) {
|
||||
break;
|
||||
}
|
||||
const VkExternalMemoryBufferCreateInfo external_info{
|
||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
|
||||
};
|
||||
const VkBufferCreateInfo buffer_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.pNext = &external_info,
|
||||
.flags = 0,
|
||||
.size = window_len,
|
||||
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyIndexCount = 0,
|
||||
.pQueueFamilyIndices = nullptr,
|
||||
};
|
||||
VkBuffer new_buffer{};
|
||||
if (logical.CreateBufferRaw(buffer_ci, &new_buffer) != VK_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
const VkMemoryRequirements requirements =
|
||||
logical.GetBufferMemoryRequirements(new_buffer);
|
||||
const u32 type_mask = requirements.memoryTypeBits & host_props.memoryTypeBits;
|
||||
if (type_mask == 0 || requirements.size > window_len) {
|
||||
logical.DestroyBufferRaw(new_buffer);
|
||||
break;
|
||||
}
|
||||
const auto type_index = FindImportMemoryType(memory_props, type_mask);
|
||||
if (!type_index) {
|
||||
logical.DestroyBufferRaw(new_buffer);
|
||||
break;
|
||||
}
|
||||
const u32 heap_index = memory_props.memoryTypes[*type_index].heapIndex;
|
||||
const VkDeviceSize heap_size = memory_props.memoryHeaps[heap_index].size;
|
||||
if (imported_size + window_len > heap_size / 2) {
|
||||
logical.DestroyBufferRaw(new_buffer);
|
||||
break;
|
||||
}
|
||||
const VkImportMemoryHostPointerInfoEXT import_info{
|
||||
.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT,
|
||||
.pNext = nullptr,
|
||||
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT,
|
||||
.pHostPointer = window_base,
|
||||
};
|
||||
const VkMemoryAllocateInfo alloc_info{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.pNext = &import_info,
|
||||
.allocationSize = window_len,
|
||||
.memoryTypeIndex = *type_index,
|
||||
};
|
||||
vk::DeviceMemory memory = logical.TryAllocateMemory(alloc_info);
|
||||
if (!memory) {
|
||||
logical.DestroyBufferRaw(new_buffer);
|
||||
break;
|
||||
}
|
||||
if (logical.BindBufferMemory(new_buffer, *memory, 0) != VK_SUCCESS) {
|
||||
logical.DestroyBufferRaw(new_buffer);
|
||||
break;
|
||||
}
|
||||
windows.push_back(Window{
|
||||
.memory = std::move(memory),
|
||||
.buffer = new_buffer,
|
||||
});
|
||||
imported_size += static_cast<size_t>(window_len);
|
||||
}
|
||||
if (windows.empty()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HostMemoryImport::ImportHardwareBuffers(
|
||||
[[maybe_unused]] std::span<AHardwareBuffer *const> hardware_buffers,
|
||||
[[maybe_unused]] size_t hardware_buffer_window,
|
||||
[[maybe_unused]] size_t hardware_buffer_base, [[maybe_unused]] size_t size) {
|
||||
#ifdef __ANDROID__
|
||||
if (hardware_buffers.empty() || hardware_buffer_window == 0 ||
|
||||
!device.IsExtExternalMemoryAhbSupported()) {
|
||||
return false;
|
||||
}
|
||||
const u64 max_allocation_size = device.GetMaxMemoryAllocationSize();
|
||||
if (max_allocation_size != 0 && hardware_buffer_window > max_allocation_size) {
|
||||
return false;
|
||||
}
|
||||
if (hardware_buffer_base >= size) {
|
||||
return false;
|
||||
}
|
||||
const auto &logical = device.GetLogical();
|
||||
const auto memory_props = device.GetPhysical().GetMemoryProperties().memoryProperties;
|
||||
window_size = hardware_buffer_window;
|
||||
base_offset = hardware_buffer_base;
|
||||
for (size_t i = 0; i < hardware_buffers.size(); ++i) {
|
||||
const size_t offset = hardware_buffer_base + i * hardware_buffer_window;
|
||||
if (offset >= size) {
|
||||
break;
|
||||
}
|
||||
const VkDeviceSize window_len = (std::min)(
|
||||
static_cast<VkDeviceSize>(size - offset),
|
||||
static_cast<VkDeviceSize>(hardware_buffer_window));
|
||||
VkAndroidHardwareBufferPropertiesANDROID ahb_props{
|
||||
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
|
||||
.pNext = nullptr,
|
||||
.allocationSize = 0,
|
||||
.memoryTypeBits = 0,
|
||||
};
|
||||
if (logical.GetAndroidHardwareBufferPropertiesANDROID(hardware_buffers[i],
|
||||
&ahb_props) != VK_SUCCESS ||
|
||||
ahb_props.memoryTypeBits == 0 || ahb_props.allocationSize < window_len) {
|
||||
break;
|
||||
}
|
||||
const VkExternalMemoryBufferCreateInfo external_info{
|
||||
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.handleTypes =
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
|
||||
};
|
||||
const VkBufferCreateInfo buffer_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.pNext = &external_info,
|
||||
.flags = 0,
|
||||
.size = window_len,
|
||||
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyIndexCount = 0,
|
||||
.pQueueFamilyIndices = nullptr,
|
||||
};
|
||||
VkBuffer new_buffer{};
|
||||
if (logical.CreateBufferRaw(buffer_ci, &new_buffer) != VK_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
const VkMemoryRequirements requirements =
|
||||
logical.GetBufferMemoryRequirements(new_buffer);
|
||||
const u32 type_mask = requirements.memoryTypeBits & ahb_props.memoryTypeBits;
|
||||
if (type_mask == 0 || requirements.size > ahb_props.allocationSize) {
|
||||
logical.DestroyBufferRaw(new_buffer);
|
||||
break;
|
||||
}
|
||||
const auto type_index = FindImportMemoryType(memory_props, type_mask);
|
||||
if (!type_index) {
|
||||
logical.DestroyBufferRaw(new_buffer);
|
||||
break;
|
||||
}
|
||||
const VkImportAndroidHardwareBufferInfoANDROID import_info{
|
||||
.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID,
|
||||
.pNext = nullptr,
|
||||
.buffer = hardware_buffers[i],
|
||||
};
|
||||
const VkMemoryDedicatedAllocateInfo dedicated_info{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
|
||||
.pNext = &import_info,
|
||||
.image = VK_NULL_HANDLE,
|
||||
.buffer = new_buffer,
|
||||
};
|
||||
const VkMemoryAllocateInfo alloc_info{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.pNext = &dedicated_info,
|
||||
.allocationSize = ahb_props.allocationSize,
|
||||
.memoryTypeIndex = *type_index,
|
||||
};
|
||||
vk::DeviceMemory memory = logical.TryAllocateMemory(alloc_info);
|
||||
if (!memory) {
|
||||
logical.DestroyBufferRaw(new_buffer);
|
||||
break;
|
||||
}
|
||||
if (logical.BindBufferMemory(new_buffer, *memory, 0) != VK_SUCCESS) {
|
||||
logical.DestroyBufferRaw(new_buffer);
|
||||
break;
|
||||
}
|
||||
windows.push_back(Window{
|
||||
.memory = std::move(memory),
|
||||
.buffer = new_buffer,
|
||||
});
|
||||
imported_size += static_cast<size_t>(window_len);
|
||||
}
|
||||
if (windows.empty()) {
|
||||
window_size = 0;
|
||||
base_offset = 0;
|
||||
return false;
|
||||
}
|
||||
foreign_ownership = true;
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
HostMemoryImport::~HostMemoryImport() {
|
||||
for (Window &window : windows) {
|
||||
if (window.buffer != VK_NULL_HANDLE) {
|
||||
device.GetLogical().DestroyBufferRaw(window.buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MemoryAllocator::MemoryAllocator(const Device &device_)
|
||||
: device{device_}, allocator{device.GetAllocator()},
|
||||
properties{device_.GetPhysical().GetMemoryProperties().memoryProperties},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user