Compare commits
131 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af89f7683d | ||
|
|
279c7bcc1a | ||
|
|
c7235e67ef | ||
|
|
840d5520d2 | ||
|
|
f67605e6aa | ||
|
|
9a0648ff0a | ||
|
|
c9e4acc4e2 | ||
|
|
292dfac25e | ||
|
|
37addf7a94 | ||
|
|
8a48c4ed1c | ||
|
|
cbc0f0a66e | ||
|
|
481b210c0d | ||
|
|
4e7a6639d2 | ||
|
|
a0c7d93b84 | ||
|
|
516325eba8 | ||
|
|
e0193e2be5 | ||
|
|
b85f5b1332 | ||
|
|
648c7b4ed6 | ||
|
|
14fc1bec17 | ||
|
|
fa7abafa5f | ||
|
|
36df305b13 | ||
|
|
f1eff447bb | ||
|
|
49e3c073a5 | ||
|
|
6991d447d4 | ||
|
|
b30a1d49ff | ||
|
|
5e24f7ed31 | ||
|
|
cf221ca92d | ||
|
|
59c6f45e7a | ||
|
|
caf38725ae | ||
|
|
ee6d40d414 | ||
|
|
eb4ea7e5c7 | ||
|
|
3074b2eb93 | ||
|
|
39bb6851e4 | ||
|
|
55650c5b75 | ||
|
|
e57b13ad94 | ||
|
|
1a9576fdff | ||
|
|
8e33cf1c2b | ||
|
|
6fb212784e | ||
|
|
2030522d86 | ||
|
|
1490b49fa9 | ||
|
|
212b497d5c | ||
|
|
7feac8ba46 | ||
|
|
4908a07c20 | ||
|
|
6c00151d17 | ||
|
|
04b4f3b051 | ||
|
|
6ebc972c2b | ||
|
|
94652e122d | ||
|
|
e49184e606 | ||
|
|
14d2c77f91 | ||
|
|
6430fc29a9 | ||
|
|
77d06d5df0 | ||
|
|
c73841500a | ||
|
|
11f4bf8a9a | ||
|
|
9b3611eb8d | ||
|
|
e610485cd2 | ||
|
|
c82e6dc810 | ||
|
|
e242f16986 | ||
|
|
333ccf23f8 | ||
|
|
1cdddd17d2 | ||
|
|
7cf74abbf5 | ||
|
|
476637d143 | ||
|
|
3ae9258efe | ||
|
|
3f765ea9a4 | ||
|
|
b3fc36d989 | ||
|
|
2a24c415c1 | ||
|
|
2f32133ad5 | ||
|
|
44b3abdfc0 | ||
|
|
156215d1fa | ||
|
|
019ae82c94 | ||
|
|
822259a3f2 | ||
|
|
f0ed11e318 | ||
|
|
935fee18ed | ||
|
|
6aac5d4c27 | ||
|
|
5e732e7aec | ||
|
|
ac0c5be7c0 | ||
|
|
7f965172c5 | ||
|
|
dd72e4dce4 | ||
|
|
a2d73eaa10 | ||
|
|
9fa1cf3e01 | ||
|
|
e05d2a70b2 | ||
|
|
4af413623b | ||
|
|
54eafbaf17 | ||
|
|
5e7e38ac72 | ||
|
|
6497fbfa96 | ||
|
|
7783c0aaef | ||
|
|
ad45963b45 | ||
|
|
37f1c76613 | ||
|
|
f91b6fbbcb | ||
|
|
ccc0a1e621 | ||
|
|
7276aaf907 | ||
|
|
54ca48e8b7 | ||
|
|
734fb180bb | ||
|
|
ddda6ae776 | ||
|
|
db9320e754 | ||
|
|
26ef76213c | ||
|
|
a515ede2af | ||
|
|
6be730bdcd | ||
|
|
37a8e2a67e | ||
|
|
d52ad96ce3 | ||
|
|
c126b0718c | ||
|
|
e4de1783e1 | ||
|
|
a9d39b6895 | ||
|
|
4d4a234476 | ||
|
|
e51b852aee | ||
|
|
e826e6715a | ||
|
|
755822ceec | ||
|
|
a92dbec962 | ||
|
|
985599e485 | ||
|
|
38f3442ea5 | ||
|
|
2b92d22bda | ||
|
|
9a104e2b60 | ||
|
|
479369db43 | ||
|
|
3c618a3306 | ||
|
|
316f80af87 | ||
|
|
b64d28492a | ||
|
|
14110230c7 | ||
|
|
1598426493 | ||
|
|
ae4869650a | ||
|
|
60bdedc7dd | ||
|
|
228a381aed | ||
|
|
c22c4f5d59 | ||
|
|
218d790bd6 | ||
|
|
b8f3e5157b | ||
|
|
35d94dcb2b | ||
|
|
4a13f9eecd | ||
|
|
ad99bbf5fe | ||
|
|
b387a26f30 | ||
|
|
75c4aec8ab | ||
|
|
660c6bec22 | ||
|
|
04fa990b0c | ||
|
|
4dd85f86a8 |
@@ -41,12 +41,11 @@ for i in package/*.exe; do
|
||||
done
|
||||
|
||||
pip3 install pefile
|
||||
python3 .ci/scripts/windows/scan_dll.py package/*.exe "package/"
|
||||
python3 .ci/scripts/windows/scan_dll.py package/imageformats/*.dll "package/"
|
||||
python3 .ci/scripts/windows/scan_dll.py package/*.exe package/imageformats/*.dll "package/"
|
||||
|
||||
# copy FFmpeg libraries
|
||||
EXTERNALS_PATH="$(pwd)/build/externals"
|
||||
FFMPEG_DLL_PATH="$(find ${EXTERNALS_PATH} -maxdepth 1 -type d | grep ffmpeg)/bin"
|
||||
FFMPEG_DLL_PATH="$(find "${EXTERNALS_PATH}" -maxdepth 1 -type d | grep 'ffmpeg-')/bin"
|
||||
find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -v {} package/ ';'
|
||||
|
||||
# copy libraries from yuzu.exe path
|
||||
|
||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -34,12 +34,12 @@
|
||||
[submodule "opus"]
|
||||
path = externals/opus/opus
|
||||
url = https://github.com/xiph/opus.git
|
||||
[submodule "ffmpeg"]
|
||||
path = externals/ffmpeg
|
||||
url = https://git.ffmpeg.org/ffmpeg.git
|
||||
[submodule "SDL"]
|
||||
path = externals/SDL
|
||||
url = https://github.com/libsdl-org/SDL.git
|
||||
[submodule "externals/cpp-httplib"]
|
||||
path = externals/cpp-httplib
|
||||
url = https://github.com/yhirose/cpp-httplib.git
|
||||
[submodule "externals/ffmpeg/ffmpeg"]
|
||||
path = externals/ffmpeg/ffmpeg
|
||||
url = https://git.ffmpeg.org/ffmpeg.git
|
||||
|
||||
224
CMakeLists.txt
224
CMakeLists.txt
@@ -229,7 +229,7 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR YUZU_USE_BUNDLED_BOOST)
|
||||
include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
|
||||
else()
|
||||
message(STATUS "Boost 1.73.0 or newer not found, falling back to Conan")
|
||||
list(APPEND CONAN_REQUIRED_LIBS "boost/1.73.0")
|
||||
list(APPEND CONAN_REQUIRED_LIBS "boost/1.78.0")
|
||||
endif()
|
||||
|
||||
# Attempt to locate any packages that are required and report the missing ones in CONAN_REQUIRED_LIBS
|
||||
@@ -249,7 +249,7 @@ if(ENABLE_QT)
|
||||
# Check for system Qt on Linux, fallback to bundled Qt
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
if (NOT YUZU_USE_BUNDLED_QT)
|
||||
find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets)
|
||||
find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets DBus)
|
||||
endif()
|
||||
if (NOT Qt5_FOUND OR YUZU_USE_BUNDLED_QT)
|
||||
# Check for dependencies, then enable bundled Qt download
|
||||
@@ -508,13 +508,13 @@ set(FFmpeg_COMPONENTS
|
||||
avutil
|
||||
swscale)
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
if (UNIX AND NOT APPLE)
|
||||
Include(FindPkgConfig REQUIRED)
|
||||
pkg_check_modules(LIBVA libva)
|
||||
endif()
|
||||
if (NOT YUZU_USE_BUNDLED_FFMPEG)
|
||||
# Use system installed FFmpeg
|
||||
find_package(FFmpeg QUIET COMPONENTS ${FFmpeg_COMPONENTS})
|
||||
find_package(FFmpeg 4.3 QUIET COMPONENTS ${FFmpeg_COMPONENTS})
|
||||
|
||||
if (FFmpeg_FOUND)
|
||||
# Overwrite aggregate defines from FFmpeg module to avoid over-linking libraries.
|
||||
@@ -527,225 +527,11 @@ if (NOT YUZU_USE_BUNDLED_FFMPEG)
|
||||
set(FFmpeg_INCLUDE_DIR ${FFmpeg_INCLUDE_DIR} ${FFmpeg_INCLUDE_${COMPONENT}} CACHE PATH "Path to FFmpeg headers" FORCE)
|
||||
endforeach()
|
||||
else()
|
||||
message(WARNING "FFmpeg not found, falling back to externals")
|
||||
message(WARNING "FFmpeg not found or too old, falling back to externals")
|
||||
set(YUZU_USE_BUNDLED_FFMPEG ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (YUZU_USE_BUNDLED_FFMPEG)
|
||||
if (NOT WIN32)
|
||||
# TODO(lat9nq): Move this to externals/ffmpeg/CMakeLists.txt (and move externals/ffmpeg to
|
||||
# externals/ffmpeg/ffmpeg)
|
||||
|
||||
# Build FFmpeg from externals
|
||||
message(STATUS "Using FFmpeg from externals")
|
||||
|
||||
# FFmpeg has source that requires one of nasm or yasm to assemble it.
|
||||
# REQUIRED throws an error if not found here during configuration rather than during compilation.
|
||||
find_program(ASSEMBLER NAMES nasm yasm)
|
||||
if ("${ASSEMBLER}" STREQUAL "ASSEMBLER-NOTFOUND")
|
||||
message(FATAL_ERROR "One of either `nasm` or `yasm` not found but is required.")
|
||||
endif()
|
||||
|
||||
find_program(AUTOCONF autoconf)
|
||||
if ("${AUTOCONF}" STREQUAL "AUTOCONF-NOTFOUND")
|
||||
message(FATAL_ERROR "Required program `autoconf` not found.")
|
||||
endif()
|
||||
|
||||
set(FFmpeg_PREFIX ${PROJECT_SOURCE_DIR}/externals/ffmpeg)
|
||||
set(FFmpeg_BUILD_DIR ${PROJECT_BINARY_DIR}/externals/ffmpeg)
|
||||
set(FFmpeg_MAKEFILE ${FFmpeg_BUILD_DIR}/Makefile)
|
||||
make_directory(${FFmpeg_BUILD_DIR})
|
||||
|
||||
# Read version string from external
|
||||
file(READ ${FFmpeg_PREFIX}/RELEASE FFmpeg_VERSION)
|
||||
set(FFmpeg_FOUND NO)
|
||||
if (NOT FFmpeg_VERSION STREQUAL "")
|
||||
set(FFmpeg_FOUND YES)
|
||||
endif()
|
||||
|
||||
unset(FFmpeg_LIBRARIES CACHE)
|
||||
foreach(COMPONENT ${FFmpeg_COMPONENTS})
|
||||
set(FFmpeg_${COMPONENT}_PREFIX "${FFmpeg_BUILD_DIR}/lib${COMPONENT}")
|
||||
set(FFmpeg_${COMPONENT}_LIB_NAME "lib${COMPONENT}.a")
|
||||
set(FFmpeg_${COMPONENT}_LIBRARY "${FFmpeg_${COMPONENT}_PREFIX}/${FFmpeg_${COMPONENT}_LIB_NAME}")
|
||||
|
||||
set(FFmpeg_LIBRARIES
|
||||
${FFmpeg_LIBRARIES}
|
||||
${FFmpeg_${COMPONENT}_LIBRARY}
|
||||
CACHE PATH "Paths to FFmpeg libraries" FORCE)
|
||||
endforeach()
|
||||
|
||||
Include(FindPkgConfig REQUIRED)
|
||||
pkg_check_modules(LIBVA libva)
|
||||
pkg_check_modules(CUDA cuda)
|
||||
pkg_check_modules(FFNVCODEC ffnvcodec)
|
||||
pkg_check_modules(VDPAU vdpau)
|
||||
|
||||
set(FFmpeg_HWACCEL_LIBRARIES)
|
||||
set(FFmpeg_HWACCEL_FLAGS)
|
||||
set(FFmpeg_HWACCEL_INCLUDE_DIRS)
|
||||
set(FFmpeg_HWACCEL_LDFLAGS)
|
||||
|
||||
if(LIBVA_FOUND)
|
||||
pkg_check_modules(LIBDRM libdrm REQUIRED)
|
||||
find_package(X11 REQUIRED)
|
||||
pkg_check_modules(LIBVA-DRM libva-drm REQUIRED)
|
||||
pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES
|
||||
${LIBDRM_LIBRARIES}
|
||||
${X11_LIBRARIES}
|
||||
${LIBVA-DRM_LIBRARIES}
|
||||
${LIBVA-X11_LIBRARIES}
|
||||
${LIBVA_LIBRARIES})
|
||||
set(FFmpeg_HWACCEL_FLAGS
|
||||
--enable-hwaccel=h264_vaapi
|
||||
--enable-hwaccel=vp8_vaapi
|
||||
--enable-hwaccel=vp9_vaapi
|
||||
--enable-libdrm)
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
|
||||
${LIBDRM_INCLUDE_DIRS}
|
||||
${X11_INCLUDE_DIRS}
|
||||
${LIBVA-DRM_INCLUDE_DIRS}
|
||||
${LIBVA-X11_INCLUDE_DIRS}
|
||||
${LIBVA_INCLUDE_DIRS}
|
||||
)
|
||||
message(STATUS "VA-API found")
|
||||
else()
|
||||
set(FFmpeg_HWACCEL_FLAGS --disable-vaapi)
|
||||
endif()
|
||||
|
||||
if (FFNVCODEC_FOUND AND CUDA_FOUND)
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS
|
||||
--enable-cuvid
|
||||
--enable-ffnvcodec
|
||||
--enable-nvdec
|
||||
--enable-hwaccel=h264_nvdec
|
||||
--enable-hwaccel=vp8_nvdec
|
||||
--enable-hwaccel=vp9_nvdec
|
||||
--extra-cflags=-I${CUDA_INCLUDE_DIRS}
|
||||
)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES
|
||||
${FFNVCODEC_LIBRARIES}
|
||||
${CUDA_LIBRARIES}
|
||||
)
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
|
||||
${FFNVCODEC_INCLUDE_DIRS}
|
||||
${CUDA_INCLUDE_DIRS}
|
||||
)
|
||||
list(APPEND FFmpeg_HWACCEL_LDFLAGS
|
||||
${FFNVCODEC_LDFLAGS}
|
||||
${CUDA_LDFLAGS}
|
||||
)
|
||||
message(STATUS "ffnvcodec libraries version ${FFNVCODEC_VERSION} found")
|
||||
endif()
|
||||
|
||||
if (VDPAU_FOUND)
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS
|
||||
--enable-vdpau
|
||||
--enable-hwaccel=h264_vdpau
|
||||
--enable-hwaccel=vp9_vdpau
|
||||
)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${VDPAU_LIBRARIES})
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${VDPAU_INCLUDE_DIRS})
|
||||
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${VDPAU_LDFLAGS})
|
||||
message(STATUS "vdpau libraries version ${VDPAU_VERSION} found")
|
||||
else()
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vdpau)
|
||||
endif()
|
||||
|
||||
# `configure` parameters builds only exactly what yuzu needs from FFmpeg
|
||||
# `--disable-vdpau` is needed to avoid linking issues
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${FFmpeg_MAKEFILE}
|
||||
COMMAND
|
||||
/bin/bash ${FFmpeg_PREFIX}/configure
|
||||
--disable-avdevice
|
||||
--disable-avfilter
|
||||
--disable-avformat
|
||||
--disable-doc
|
||||
--disable-everything
|
||||
--disable-ffmpeg
|
||||
--disable-ffprobe
|
||||
--disable-network
|
||||
--disable-postproc
|
||||
--disable-swresample
|
||||
--enable-decoder=h264
|
||||
--enable-decoder=vp8
|
||||
--enable-decoder=vp9
|
||||
--cc="${CMAKE_C_COMPILER}"
|
||||
--cxx="${CMAKE_CXX_COMPILER}"
|
||||
${FFmpeg_HWACCEL_FLAGS}
|
||||
WORKING_DIRECTORY
|
||||
${FFmpeg_BUILD_DIR}
|
||||
)
|
||||
unset(FFmpeg_HWACCEL_FLAGS)
|
||||
|
||||
# Workaround for Ubuntu 18.04's older version of make not being able to call make as a child
|
||||
# with context of the jobserver. Also helps ninja users.
|
||||
execute_process(
|
||||
COMMAND
|
||||
nproc
|
||||
OUTPUT_VARIABLE
|
||||
SYSTEM_THREADS)
|
||||
|
||||
set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES})
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${FFmpeg_BUILD_LIBRARIES}
|
||||
COMMAND
|
||||
make -j${SYSTEM_THREADS}
|
||||
WORKING_DIRECTORY
|
||||
${FFmpeg_BUILD_DIR}
|
||||
)
|
||||
|
||||
set(FFmpeg_INCLUDE_DIR
|
||||
"${FFmpeg_PREFIX};${FFmpeg_BUILD_DIR};${FFmpeg_HWACCEL_INCLUDE_DIRS}"
|
||||
CACHE PATH "Path to FFmpeg headers" FORCE)
|
||||
|
||||
set(FFmpeg_LDFLAGS
|
||||
"${FFmpeg_HWACCEL_LDFLAGS}"
|
||||
CACHE STRING "FFmpeg linker flags" FORCE)
|
||||
|
||||
# ALL makes this custom target build every time
|
||||
# but it won't actually build if the DEPENDS parameter is up to date
|
||||
add_custom_target(ffmpeg-configure ALL DEPENDS ${FFmpeg_MAKEFILE})
|
||||
add_custom_target(ffmpeg-build ALL DEPENDS ${FFmpeg_BUILD_LIBRARIES} ffmpeg-configure)
|
||||
link_libraries(${FFmpeg_LIBVA_LIBRARIES})
|
||||
set(FFmpeg_LIBRARIES ${FFmpeg_BUILD_LIBRARIES} ${FFmpeg_HWACCEL_LIBRARIES}
|
||||
CACHE PATH "Paths to FFmpeg libraries" FORCE)
|
||||
unset(FFmpeg_BUILD_LIBRARIES)
|
||||
unset(FFmpeg_HWACCEL_FLAGS)
|
||||
unset(FFmpeg_HWACCEL_INCLUDE_DIRS)
|
||||
unset(FFmpeg_HWACCEL_LDFLAGS)
|
||||
unset(FFmpeg_HWACCEL_LIBRARIES)
|
||||
|
||||
if (FFmpeg_FOUND)
|
||||
message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}")
|
||||
else()
|
||||
message(FATAL_ERROR "FFmpeg not found")
|
||||
endif()
|
||||
else() # WIN32
|
||||
# Use yuzu FFmpeg binaries
|
||||
set(FFmpeg_EXT_NAME "ffmpeg-4.4")
|
||||
set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}")
|
||||
download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "")
|
||||
set(FFmpeg_FOUND YES)
|
||||
set(FFmpeg_INCLUDE_DIR "${FFmpeg_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE)
|
||||
set(FFmpeg_LIBRARY_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg library directory" FORCE)
|
||||
set(FFmpeg_LDFLAGS "" CACHE STRING "FFmpeg linker flags" FORCE)
|
||||
set(FFmpeg_DLL_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg dll's" FORCE)
|
||||
set(FFmpeg_LIBRARIES
|
||||
${FFmpeg_LIBRARY_DIR}/swscale.lib
|
||||
${FFmpeg_LIBRARY_DIR}/avcodec.lib
|
||||
${FFmpeg_LIBRARY_DIR}/avutil.lib
|
||||
CACHE PATH "Paths to FFmpeg libraries" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
unset(FFmpeg_COMPONENTS)
|
||||
|
||||
# Prefer the -pthread flag on Linux.
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
@@ -11,9 +11,15 @@ find_package(Git QUIET PATHS "${GIT_EXECUTABLE}")
|
||||
|
||||
# generate git/build information
|
||||
include(GetGitRevisionDescription)
|
||||
get_git_head_revision(GIT_REF_SPEC GIT_REV)
|
||||
git_describe(GIT_DESC --always --long --dirty)
|
||||
git_branch_name(GIT_BRANCH)
|
||||
if(NOT GIT_REF_SPEC)
|
||||
get_git_head_revision(GIT_REF_SPEC GIT_REV)
|
||||
endif()
|
||||
if(NOT GIT_DESC)
|
||||
git_describe(GIT_DESC --always --long --dirty)
|
||||
endif()
|
||||
if (NOT GIT_BRANCH)
|
||||
git_branch_name(GIT_BRANCH)
|
||||
endif()
|
||||
get_timestamp(BUILD_DATE)
|
||||
|
||||
# Generate cpp with Git revision from template
|
||||
|
||||
2
dist/yuzu.desktop
vendored
2
dist/yuzu.desktop
vendored
@@ -8,5 +8,5 @@ Icon=yuzu
|
||||
TryExec=yuzu
|
||||
Exec=yuzu %f
|
||||
Categories=Game;Emulator;Qt;
|
||||
MimeType=application/x-nx-nro;application/x-nx-nso;
|
||||
MimeType=application/x-nx-nro;application/x-nx-nso;application/x-nx-nsp;application/x-nx-xci;
|
||||
Keywords=Switch;Nintendo;
|
||||
15
dist/yuzu.xml
vendored
15
dist/yuzu.xml
vendored
@@ -15,4 +15,19 @@
|
||||
<glob pattern="*.nso"/>
|
||||
<magic><match value="NSO" type="string" offset="0"/></magic>
|
||||
</mime-type>
|
||||
|
||||
<mime-type type="application/x-nx-nsp">
|
||||
<comment>Nintendo Switch Package</comment>
|
||||
<acronym>NSP</acronym>
|
||||
<icon name="yuzu"/>
|
||||
<glob pattern="*.nsp"/>
|
||||
<magic><match value="PFS" type="string" offset="0"/></magic>
|
||||
</mime-type>
|
||||
|
||||
<mime-type type="application/x-nx-xci">
|
||||
<comment>Nintendo Switch Card Image</comment>
|
||||
<acronym>XCI</acronym>
|
||||
<icon name="yuzu"/>
|
||||
<glob pattern="*.xci"/>
|
||||
</mime-type>
|
||||
</mime-info>
|
||||
16
externals/CMakeLists.txt
vendored
16
externals/CMakeLists.txt
vendored
@@ -52,11 +52,12 @@ endif()
|
||||
# SDL2
|
||||
if (YUZU_USE_EXTERNAL_SDL2)
|
||||
if (NOT WIN32)
|
||||
# Yuzu itself needs: Events Joystick Haptic Sensor Timers Audio
|
||||
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
|
||||
# Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
|
||||
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
|
||||
set(SDL_UNUSED_SUBSYSTEMS
|
||||
Atomic Render Power Threads
|
||||
File CPUinfo Filesystem Locale)
|
||||
CPUinfo File Filesystem
|
||||
Locale Power Render)
|
||||
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
|
||||
string(TOUPPER ${_SUB} _OPT)
|
||||
option(SDL_${_OPT} "" OFF)
|
||||
@@ -121,3 +122,12 @@ if (NOT opus_FOUND)
|
||||
message(STATUS "opus 1.3 or newer not found, falling back to externals")
|
||||
add_subdirectory(opus EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
# FFMpeg
|
||||
if (YUZU_USE_BUNDLED_FFMPEG)
|
||||
add_subdirectory(ffmpeg)
|
||||
set(FFmpeg_PATH "${FFmpeg_PATH}" PARENT_SCOPE)
|
||||
set(FFmpeg_LDFLAGS "${FFmpeg_LDFLAGS}" PARENT_SCOPE)
|
||||
set(FFmpeg_LIBRARIES "${FFmpeg_LIBRARIES}" PARENT_SCOPE)
|
||||
set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
2
externals/SDL
vendored
2
externals/SDL
vendored
Submodule externals/SDL updated: 2e9821423a...e2ade2bfc4
2
externals/Vulkan-Headers
vendored
2
externals/Vulkan-Headers
vendored
Submodule externals/Vulkan-Headers updated: 07c4a37bcf...e005e1f817
2
externals/dynarmic
vendored
2
externals/dynarmic
vendored
Submodule externals/dynarmic updated: cce7e4ee5d...28714ee75a
1
externals/ffmpeg
vendored
1
externals/ffmpeg
vendored
Submodule externals/ffmpeg deleted from 79e8d17024
214
externals/ffmpeg/CMakeLists.txt
vendored
Normal file
214
externals/ffmpeg/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,214 @@
|
||||
if (NOT WIN32)
|
||||
# Build FFmpeg from externals
|
||||
message(STATUS "Using FFmpeg from externals")
|
||||
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|amd64)")
|
||||
# FFmpeg has source that requires one of nasm or yasm to assemble it.
|
||||
# REQUIRED throws an error if not found here during configuration rather than during compilation.
|
||||
find_program(ASSEMBLER NAMES nasm yasm)
|
||||
if ("${ASSEMBLER}" STREQUAL "ASSEMBLER-NOTFOUND")
|
||||
message(FATAL_ERROR "One of either `nasm` or `yasm` not found but is required.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_program(AUTOCONF autoconf)
|
||||
if ("${AUTOCONF}" STREQUAL "AUTOCONF-NOTFOUND")
|
||||
message(FATAL_ERROR "Required program `autoconf` not found.")
|
||||
endif()
|
||||
|
||||
set(FFmpeg_PREFIX ${PROJECT_SOURCE_DIR}/externals/ffmpeg/ffmpeg)
|
||||
set(FFmpeg_BUILD_DIR ${PROJECT_BINARY_DIR}/externals/ffmpeg-build)
|
||||
set(FFmpeg_MAKEFILE ${FFmpeg_BUILD_DIR}/Makefile)
|
||||
make_directory(${FFmpeg_BUILD_DIR})
|
||||
|
||||
# Read version string from external
|
||||
file(READ ${FFmpeg_PREFIX}/RELEASE FFmpeg_VERSION)
|
||||
set(FFmpeg_FOUND NO)
|
||||
if (NOT FFmpeg_VERSION STREQUAL "")
|
||||
set(FFmpeg_FOUND YES)
|
||||
endif()
|
||||
|
||||
unset(FFmpeg_LIBRARIES CACHE)
|
||||
foreach(COMPONENT ${FFmpeg_COMPONENTS})
|
||||
set(FFmpeg_${COMPONENT}_PREFIX "${FFmpeg_BUILD_DIR}/lib${COMPONENT}")
|
||||
set(FFmpeg_${COMPONENT}_LIB_NAME "lib${COMPONENT}.a")
|
||||
set(FFmpeg_${COMPONENT}_LIBRARY "${FFmpeg_${COMPONENT}_PREFIX}/${FFmpeg_${COMPONENT}_LIB_NAME}")
|
||||
|
||||
set(FFmpeg_LIBRARIES
|
||||
${FFmpeg_LIBRARIES}
|
||||
${FFmpeg_${COMPONENT}_LIBRARY}
|
||||
CACHE PATH "Paths to FFmpeg libraries" FORCE)
|
||||
endforeach()
|
||||
|
||||
Include(FindPkgConfig REQUIRED)
|
||||
pkg_check_modules(LIBVA libva)
|
||||
pkg_check_modules(CUDA cuda)
|
||||
pkg_check_modules(FFNVCODEC ffnvcodec)
|
||||
pkg_check_modules(VDPAU vdpau)
|
||||
|
||||
set(FFmpeg_HWACCEL_LIBRARIES)
|
||||
set(FFmpeg_HWACCEL_FLAGS)
|
||||
set(FFmpeg_HWACCEL_INCLUDE_DIRS)
|
||||
set(FFmpeg_HWACCEL_LDFLAGS)
|
||||
|
||||
if(LIBVA_FOUND)
|
||||
pkg_check_modules(LIBDRM libdrm REQUIRED)
|
||||
find_package(X11 REQUIRED)
|
||||
pkg_check_modules(LIBVA-DRM libva-drm REQUIRED)
|
||||
pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES
|
||||
${LIBDRM_LIBRARIES}
|
||||
${X11_LIBRARIES}
|
||||
${LIBVA-DRM_LIBRARIES}
|
||||
${LIBVA-X11_LIBRARIES}
|
||||
${LIBVA_LIBRARIES})
|
||||
set(FFmpeg_HWACCEL_FLAGS
|
||||
--enable-hwaccel=h264_vaapi
|
||||
--enable-hwaccel=vp8_vaapi
|
||||
--enable-hwaccel=vp9_vaapi
|
||||
--enable-libdrm)
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
|
||||
${LIBDRM_INCLUDE_DIRS}
|
||||
${X11_INCLUDE_DIRS}
|
||||
${LIBVA-DRM_INCLUDE_DIRS}
|
||||
${LIBVA-X11_INCLUDE_DIRS}
|
||||
${LIBVA_INCLUDE_DIRS}
|
||||
)
|
||||
message(STATUS "VA-API found")
|
||||
else()
|
||||
set(FFmpeg_HWACCEL_FLAGS --disable-vaapi)
|
||||
endif()
|
||||
|
||||
if (FFNVCODEC_FOUND)
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS
|
||||
--enable-cuvid
|
||||
--enable-ffnvcodec
|
||||
--enable-nvdec
|
||||
--enable-hwaccel=h264_nvdec
|
||||
--enable-hwaccel=vp8_nvdec
|
||||
--enable-hwaccel=vp9_nvdec
|
||||
)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${FFNVCODEC_LIBRARIES})
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${FFNVCODEC_INCLUDE_DIRS})
|
||||
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${FFNVCODEC_LDFLAGS})
|
||||
message(STATUS "ffnvcodec libraries version ${FFNVCODEC_VERSION} found")
|
||||
# ffnvenc could load CUDA libraries at the runtime using dlopen/dlsym or LoadLibrary/GetProcAddress
|
||||
# here we handle the hard-linking senario where CUDA is linked during compilation
|
||||
if (CUDA_FOUND)
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS --extra-cflags=-I${CUDA_INCLUDE_DIRS})
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${CUDA_LIBRARIES})
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${CUDA_INCLUDE_DIRS})
|
||||
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${CUDA_LDFLAGS})
|
||||
message(STATUS "CUDA libraries found, hard-linking will be performed")
|
||||
endif(CUDA_FOUND)
|
||||
endif()
|
||||
|
||||
if (VDPAU_FOUND)
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS
|
||||
--enable-vdpau
|
||||
--enable-hwaccel=h264_vdpau
|
||||
--enable-hwaccel=vp9_vdpau
|
||||
)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES ${VDPAU_LIBRARIES})
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${VDPAU_INCLUDE_DIRS})
|
||||
list(APPEND FFmpeg_HWACCEL_LDFLAGS ${VDPAU_LDFLAGS})
|
||||
message(STATUS "vdpau libraries version ${VDPAU_VERSION} found")
|
||||
else()
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vdpau)
|
||||
endif()
|
||||
|
||||
# `configure` parameters builds only exactly what yuzu needs from FFmpeg
|
||||
# `--disable-vdpau` is needed to avoid linking issues
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${FFmpeg_MAKEFILE}
|
||||
COMMAND
|
||||
/bin/bash ${FFmpeg_PREFIX}/configure
|
||||
--disable-avdevice
|
||||
--disable-avfilter
|
||||
--disable-avformat
|
||||
--disable-doc
|
||||
--disable-everything
|
||||
--disable-ffmpeg
|
||||
--disable-ffprobe
|
||||
--disable-network
|
||||
--disable-postproc
|
||||
--disable-swresample
|
||||
--enable-decoder=h264
|
||||
--enable-decoder=vp8
|
||||
--enable-decoder=vp9
|
||||
--cc="${CMAKE_C_COMPILER}"
|
||||
--cxx="${CMAKE_CXX_COMPILER}"
|
||||
${FFmpeg_HWACCEL_FLAGS}
|
||||
WORKING_DIRECTORY
|
||||
${FFmpeg_BUILD_DIR}
|
||||
)
|
||||
unset(FFmpeg_HWACCEL_FLAGS)
|
||||
|
||||
# Workaround for Ubuntu 18.04's older version of make not being able to call make as a child
|
||||
# with context of the jobserver. Also helps ninja users.
|
||||
execute_process(
|
||||
COMMAND
|
||||
nproc
|
||||
OUTPUT_VARIABLE
|
||||
SYSTEM_THREADS)
|
||||
|
||||
set(FFmpeg_BUILD_LIBRARIES ${FFmpeg_LIBRARIES})
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${FFmpeg_BUILD_LIBRARIES}
|
||||
COMMAND
|
||||
make -j${SYSTEM_THREADS}
|
||||
WORKING_DIRECTORY
|
||||
${FFmpeg_BUILD_DIR}
|
||||
)
|
||||
|
||||
set(FFmpeg_INCLUDE_DIR
|
||||
"${FFmpeg_PREFIX};${FFmpeg_BUILD_DIR};${FFmpeg_HWACCEL_INCLUDE_DIRS}"
|
||||
CACHE PATH "Path to FFmpeg headers" FORCE)
|
||||
|
||||
set(FFmpeg_LDFLAGS
|
||||
"${FFmpeg_HWACCEL_LDFLAGS}"
|
||||
CACHE STRING "FFmpeg linker flags" FORCE)
|
||||
|
||||
# ALL makes this custom target build every time
|
||||
# but it won't actually build if the DEPENDS parameter is up to date
|
||||
add_custom_target(ffmpeg-configure ALL DEPENDS ${FFmpeg_MAKEFILE})
|
||||
add_custom_target(ffmpeg-build ALL DEPENDS ${FFmpeg_BUILD_LIBRARIES} ffmpeg-configure)
|
||||
link_libraries(${FFmpeg_LIBVA_LIBRARIES})
|
||||
set(FFmpeg_LIBRARIES ${FFmpeg_BUILD_LIBRARIES} ${FFmpeg_HWACCEL_LIBRARIES}
|
||||
CACHE PATH "Paths to FFmpeg libraries" FORCE)
|
||||
unset(FFmpeg_BUILD_LIBRARIES)
|
||||
unset(FFmpeg_HWACCEL_FLAGS)
|
||||
unset(FFmpeg_HWACCEL_INCLUDE_DIRS)
|
||||
unset(FFmpeg_HWACCEL_LDFLAGS)
|
||||
unset(FFmpeg_HWACCEL_LIBRARIES)
|
||||
|
||||
if (FFmpeg_FOUND)
|
||||
message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}")
|
||||
else()
|
||||
message(FATAL_ERROR "FFmpeg not found")
|
||||
endif()
|
||||
else(WIN32)
|
||||
# Use yuzu FFmpeg binaries
|
||||
set(FFmpeg_EXT_NAME "ffmpeg-4.4")
|
||||
set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}")
|
||||
download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "")
|
||||
set(FFmpeg_FOUND YES)
|
||||
set(FFmpeg_INCLUDE_DIR "${FFmpeg_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE)
|
||||
set(FFmpeg_LIBRARY_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg library directory" FORCE)
|
||||
set(FFmpeg_LDFLAGS "" CACHE STRING "FFmpeg linker flags" FORCE)
|
||||
set(FFmpeg_DLL_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg dll's" FORCE)
|
||||
set(FFmpeg_LIBRARIES
|
||||
${FFmpeg_LIBRARY_DIR}/swscale.lib
|
||||
${FFmpeg_LIBRARY_DIR}/avcodec.lib
|
||||
${FFmpeg_LIBRARY_DIR}/avutil.lib
|
||||
CACHE PATH "Paths to FFmpeg libraries" FORCE)
|
||||
# exported variables
|
||||
set(FFmpeg_PATH "${FFmpeg_PATH}" PARENT_SCOPE)
|
||||
set(FFmpeg_LDFLAGS "${FFmpeg_LDFLAGS}" PARENT_SCOPE)
|
||||
set(FFmpeg_LIBRARIES "${FFmpeg_LIBRARIES}" PARENT_SCOPE)
|
||||
set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE)
|
||||
endif(WIN32)
|
||||
|
||||
unset(FFmpeg_COMPONENTS)
|
||||
1
externals/ffmpeg/ffmpeg
vendored
Submodule
1
externals/ffmpeg/ffmpeg
vendored
Submodule
Submodule externals/ffmpeg/ffmpeg added at dc91b913b6
@@ -22,6 +22,11 @@ add_custom_command(OUTPUT scm_rev.cpp
|
||||
-DTITLE_BAR_FORMAT_RUNNING=${TITLE_BAR_FORMAT_RUNNING}
|
||||
-DBUILD_TAG=${BUILD_TAG}
|
||||
-DBUILD_ID=${DISPLAY_VERSION}
|
||||
-DGIT_REF_SPEC=${GIT_REF_SPEC}
|
||||
-DGIT_REV=${GIT_REV}
|
||||
-DGIT_DESC=${GIT_DESC}
|
||||
-DGIT_BRANCH=${GIT_BRANCH}
|
||||
-DBUILD_FULLNAME=${BUILD_FULLNAME}
|
||||
-DGIT_EXECUTABLE=${GIT_EXECUTABLE}
|
||||
-P ${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake
|
||||
DEPENDS
|
||||
|
||||
@@ -227,7 +227,7 @@ struct CallbackStatus {
|
||||
|
||||
// Triggered once every input change
|
||||
struct InputCallback {
|
||||
std::function<void(CallbackStatus)> on_change;
|
||||
std::function<void(const CallbackStatus&)> on_change;
|
||||
};
|
||||
|
||||
/// An abstract class template for an input device (a button, an analog input, etc.).
|
||||
@@ -236,14 +236,10 @@ public:
|
||||
virtual ~InputDevice() = default;
|
||||
|
||||
// Request input device to update if necessary
|
||||
virtual void SoftUpdate() {
|
||||
return;
|
||||
}
|
||||
virtual void SoftUpdate() {}
|
||||
|
||||
// Force input device to update data regardless of the current state
|
||||
virtual void ForceUpdate() {
|
||||
return;
|
||||
}
|
||||
virtual void ForceUpdate() {}
|
||||
|
||||
// Sets the function to be triggered when input changes
|
||||
void SetCallback(InputCallback callback_) {
|
||||
@@ -251,7 +247,7 @@ public:
|
||||
}
|
||||
|
||||
// Triggers the function set in the callback
|
||||
void TriggerOnChange(CallbackStatus status) {
|
||||
void TriggerOnChange(const CallbackStatus& status) {
|
||||
if (callback.on_change) {
|
||||
callback.on_change(status);
|
||||
}
|
||||
@@ -266,11 +262,9 @@ class OutputDevice {
|
||||
public:
|
||||
virtual ~OutputDevice() = default;
|
||||
|
||||
virtual void SetLED([[maybe_unused]] LedStatus led_status) {
|
||||
return;
|
||||
}
|
||||
virtual void SetLED([[maybe_unused]] const LedStatus& led_status) {}
|
||||
|
||||
virtual VibrationError SetVibration([[maybe_unused]] VibrationStatus vibration_status) {
|
||||
virtual VibrationError SetVibration([[maybe_unused]] const VibrationStatus& vibration_status) {
|
||||
return VibrationError::NotSupported;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,9 +71,6 @@ static CPUCaps Detect() {
|
||||
else
|
||||
caps.manufacturer = Manufacturer::Unknown;
|
||||
|
||||
u32 family = {};
|
||||
u32 model = {};
|
||||
|
||||
__cpuid(cpu_id, 0x80000000);
|
||||
|
||||
u32 max_ex_fn = cpu_id[0];
|
||||
@@ -84,15 +81,6 @@ static CPUCaps Detect() {
|
||||
// Detect family and other miscellaneous features
|
||||
if (max_std_fn >= 1) {
|
||||
__cpuid(cpu_id, 0x00000001);
|
||||
family = (cpu_id[0] >> 8) & 0xf;
|
||||
model = (cpu_id[0] >> 4) & 0xf;
|
||||
if (family == 0xf) {
|
||||
family += (cpu_id[0] >> 20) & 0xff;
|
||||
}
|
||||
if (family >= 6) {
|
||||
model += ((cpu_id[0] >> 16) & 0xf) << 4;
|
||||
}
|
||||
|
||||
if ((cpu_id[3] >> 25) & 1)
|
||||
caps.sse = true;
|
||||
if ((cpu_id[3] >> 26) & 1)
|
||||
|
||||
@@ -265,8 +265,6 @@ add_library(core STATIC
|
||||
hle/kernel/svc_wrap.h
|
||||
hle/kernel/time_manager.cpp
|
||||
hle/kernel/time_manager.h
|
||||
hle/lock.cpp
|
||||
hle/lock.h
|
||||
hle/result.h
|
||||
hle/service/acc/acc.cpp
|
||||
hle/service/acc/acc.h
|
||||
|
||||
@@ -66,9 +66,10 @@ void EmulatedConsole::ReloadInput() {
|
||||
|
||||
motion_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(motion_params);
|
||||
if (motion_devices) {
|
||||
Common::Input::InputCallback motion_callback{
|
||||
[this](Common::Input::CallbackStatus callback) { SetMotion(callback); }};
|
||||
motion_devices->SetCallback(motion_callback);
|
||||
motion_devices->SetCallback({
|
||||
.on_change =
|
||||
[this](const Common::Input::CallbackStatus& callback) { SetMotion(callback); },
|
||||
});
|
||||
}
|
||||
|
||||
// Unique index for identifying touch device source
|
||||
@@ -78,9 +79,12 @@ void EmulatedConsole::ReloadInput() {
|
||||
if (!touch_device) {
|
||||
continue;
|
||||
}
|
||||
Common::Input::InputCallback touch_callback{
|
||||
[this, index](Common::Input::CallbackStatus callback) { SetTouch(callback, index); }};
|
||||
touch_device->SetCallback(touch_callback);
|
||||
touch_device->SetCallback({
|
||||
.on_change =
|
||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
||||
SetTouch(callback, index);
|
||||
},
|
||||
});
|
||||
index++;
|
||||
}
|
||||
}
|
||||
@@ -127,7 +131,7 @@ void EmulatedConsole::SetMotionParam(Common::ParamPackage param) {
|
||||
ReloadInput();
|
||||
}
|
||||
|
||||
void EmulatedConsole::SetMotion(Common::Input::CallbackStatus callback) {
|
||||
void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
|
||||
std::lock_guard lock{mutex};
|
||||
auto& raw_status = console.motion_values.raw_status;
|
||||
auto& emulated = console.motion_values.emulated;
|
||||
@@ -157,13 +161,15 @@ void EmulatedConsole::SetMotion(Common::Input::CallbackStatus callback) {
|
||||
motion.rotation = emulated.GetGyroscope();
|
||||
motion.orientation = emulated.GetOrientation();
|
||||
motion.quaternion = emulated.GetQuaternion();
|
||||
motion.gyro_bias = emulated.GetGyroBias();
|
||||
motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
|
||||
// Find what is this value
|
||||
motion.verticalization_error = 0.0f;
|
||||
|
||||
TriggerOnChange(ConsoleTriggerType::Motion);
|
||||
}
|
||||
|
||||
void EmulatedConsole::SetTouch(Common::Input::CallbackStatus callback,
|
||||
[[maybe_unused]] std::size_t index) {
|
||||
void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) {
|
||||
if (index >= console.touch_values.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -50,6 +50,8 @@ struct ConsoleMotion {
|
||||
Common::Vec3f rotation{};
|
||||
std::array<Common::Vec3f, 3> orientation{};
|
||||
Common::Quaternion<f32> quaternion{};
|
||||
Common::Vec3f gyro_bias{};
|
||||
f32 verticalization_error{};
|
||||
bool is_at_rest{};
|
||||
};
|
||||
|
||||
@@ -155,14 +157,14 @@ private:
|
||||
* Updates the motion status of the console
|
||||
* @param callback A CallbackStatus containing gyro and accelerometer data
|
||||
*/
|
||||
void SetMotion(Common::Input::CallbackStatus callback);
|
||||
void SetMotion(const Common::Input::CallbackStatus& callback);
|
||||
|
||||
/**
|
||||
* Updates the touch status of the console
|
||||
* @param callback A CallbackStatus containing the touch position
|
||||
* @param index Finger ID to be updated
|
||||
*/
|
||||
void SetTouch(Common::Input::CallbackStatus callback, std::size_t index);
|
||||
void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index);
|
||||
|
||||
/**
|
||||
* Triggers a callback that something has changed on the console status
|
||||
|
||||
@@ -205,11 +205,12 @@ void EmulatedController::ReloadInput() {
|
||||
continue;
|
||||
}
|
||||
const auto uuid = Common::UUID{button_params[index].Get("guid", "")};
|
||||
Common::Input::InputCallback button_callback{
|
||||
[this, index, uuid](Common::Input::CallbackStatus callback) {
|
||||
SetButton(callback, index, uuid);
|
||||
}};
|
||||
button_devices[index]->SetCallback(button_callback);
|
||||
button_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index, uuid](const Common::Input::CallbackStatus& callback) {
|
||||
SetButton(callback, index, uuid);
|
||||
},
|
||||
});
|
||||
button_devices[index]->ForceUpdate();
|
||||
}
|
||||
|
||||
@@ -218,11 +219,12 @@ void EmulatedController::ReloadInput() {
|
||||
continue;
|
||||
}
|
||||
const auto uuid = Common::UUID{stick_params[index].Get("guid", "")};
|
||||
Common::Input::InputCallback stick_callback{
|
||||
[this, index, uuid](Common::Input::CallbackStatus callback) {
|
||||
SetStick(callback, index, uuid);
|
||||
}};
|
||||
stick_devices[index]->SetCallback(stick_callback);
|
||||
stick_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index, uuid](const Common::Input::CallbackStatus& callback) {
|
||||
SetStick(callback, index, uuid);
|
||||
},
|
||||
});
|
||||
stick_devices[index]->ForceUpdate();
|
||||
}
|
||||
|
||||
@@ -231,11 +233,12 @@ void EmulatedController::ReloadInput() {
|
||||
continue;
|
||||
}
|
||||
const auto uuid = Common::UUID{trigger_params[index].Get("guid", "")};
|
||||
Common::Input::InputCallback trigger_callback{
|
||||
[this, index, uuid](Common::Input::CallbackStatus callback) {
|
||||
SetTrigger(callback, index, uuid);
|
||||
}};
|
||||
trigger_devices[index]->SetCallback(trigger_callback);
|
||||
trigger_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index, uuid](const Common::Input::CallbackStatus& callback) {
|
||||
SetTrigger(callback, index, uuid);
|
||||
},
|
||||
});
|
||||
trigger_devices[index]->ForceUpdate();
|
||||
}
|
||||
|
||||
@@ -243,9 +246,12 @@ void EmulatedController::ReloadInput() {
|
||||
if (!battery_devices[index]) {
|
||||
continue;
|
||||
}
|
||||
Common::Input::InputCallback battery_callback{
|
||||
[this, index](Common::Input::CallbackStatus callback) { SetBattery(callback, index); }};
|
||||
battery_devices[index]->SetCallback(battery_callback);
|
||||
battery_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
||||
SetBattery(callback, index);
|
||||
},
|
||||
});
|
||||
battery_devices[index]->ForceUpdate();
|
||||
}
|
||||
|
||||
@@ -253,9 +259,12 @@ void EmulatedController::ReloadInput() {
|
||||
if (!motion_devices[index]) {
|
||||
continue;
|
||||
}
|
||||
Common::Input::InputCallback motion_callback{
|
||||
[this, index](Common::Input::CallbackStatus callback) { SetMotion(callback, index); }};
|
||||
motion_devices[index]->SetCallback(motion_callback);
|
||||
motion_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
||||
SetMotion(callback, index);
|
||||
},
|
||||
});
|
||||
motion_devices[index]->ForceUpdate();
|
||||
}
|
||||
|
||||
@@ -267,22 +276,24 @@ void EmulatedController::ReloadInput() {
|
||||
if (!tas_button_devices[index]) {
|
||||
continue;
|
||||
}
|
||||
Common::Input::InputCallback button_callback{
|
||||
[this, index, tas_uuid](Common::Input::CallbackStatus callback) {
|
||||
SetButton(callback, index, tas_uuid);
|
||||
}};
|
||||
tas_button_devices[index]->SetCallback(button_callback);
|
||||
tas_button_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index, tas_uuid](const Common::Input::CallbackStatus& callback) {
|
||||
SetButton(callback, index, tas_uuid);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < tas_stick_devices.size(); ++index) {
|
||||
if (!tas_stick_devices[index]) {
|
||||
continue;
|
||||
}
|
||||
Common::Input::InputCallback stick_callback{
|
||||
[this, index, tas_uuid](Common::Input::CallbackStatus callback) {
|
||||
SetStick(callback, index, tas_uuid);
|
||||
}};
|
||||
tas_stick_devices[index]->SetCallback(stick_callback);
|
||||
tas_stick_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index, tas_uuid](const Common::Input::CallbackStatus& callback) {
|
||||
SetStick(callback, index, tas_uuid);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,7 +451,7 @@ void EmulatedController::SetButtonParam(std::size_t index, Common::ParamPackage
|
||||
if (index >= button_params.size()) {
|
||||
return;
|
||||
}
|
||||
button_params[index] = param;
|
||||
button_params[index] = std::move(param);
|
||||
ReloadInput();
|
||||
}
|
||||
|
||||
@@ -448,7 +459,7 @@ void EmulatedController::SetStickParam(std::size_t index, Common::ParamPackage p
|
||||
if (index >= stick_params.size()) {
|
||||
return;
|
||||
}
|
||||
stick_params[index] = param;
|
||||
stick_params[index] = std::move(param);
|
||||
ReloadInput();
|
||||
}
|
||||
|
||||
@@ -456,11 +467,11 @@ void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage
|
||||
if (index >= motion_params.size()) {
|
||||
return;
|
||||
}
|
||||
motion_params[index] = param;
|
||||
motion_params[index] = std::move(param);
|
||||
ReloadInput();
|
||||
}
|
||||
|
||||
void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std::size_t index,
|
||||
void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index,
|
||||
Common::UUID uuid) {
|
||||
if (index >= controller.button_values.size()) {
|
||||
return;
|
||||
@@ -600,7 +611,7 @@ void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std::
|
||||
TriggerOnChange(ControllerTriggerType::Button, true);
|
||||
}
|
||||
|
||||
void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::size_t index,
|
||||
void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, std::size_t index,
|
||||
Common::UUID uuid) {
|
||||
if (index >= controller.stick_values.size()) {
|
||||
return;
|
||||
@@ -650,8 +661,8 @@ void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::s
|
||||
TriggerOnChange(ControllerTriggerType::Stick, true);
|
||||
}
|
||||
|
||||
void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std::size_t index,
|
||||
Common::UUID uuid) {
|
||||
void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callback,
|
||||
std::size_t index, Common::UUID uuid) {
|
||||
if (index >= controller.trigger_values.size()) {
|
||||
return;
|
||||
}
|
||||
@@ -659,7 +670,7 @@ void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std:
|
||||
const auto trigger_value = TransformToTrigger(callback);
|
||||
|
||||
// Only read trigger values that have the same uuid or are pressed once
|
||||
if (controller.stick_values[index].uuid != uuid) {
|
||||
if (controller.trigger_values[index].uuid != uuid) {
|
||||
if (!trigger_value.pressed.value) {
|
||||
return;
|
||||
}
|
||||
@@ -675,7 +686,7 @@ void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std:
|
||||
return;
|
||||
}
|
||||
|
||||
const auto trigger = controller.trigger_values[index];
|
||||
const auto& trigger = controller.trigger_values[index];
|
||||
|
||||
switch (index) {
|
||||
case Settings::NativeTrigger::LTrigger:
|
||||
@@ -692,7 +703,8 @@ void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std:
|
||||
TriggerOnChange(ControllerTriggerType::Trigger, true);
|
||||
}
|
||||
|
||||
void EmulatedController::SetMotion(Common::Input::CallbackStatus callback, std::size_t index) {
|
||||
void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback,
|
||||
std::size_t index) {
|
||||
if (index >= controller.motion_values.size()) {
|
||||
return;
|
||||
}
|
||||
@@ -730,7 +742,8 @@ void EmulatedController::SetMotion(Common::Input::CallbackStatus callback, std::
|
||||
TriggerOnChange(ControllerTriggerType::Motion, true);
|
||||
}
|
||||
|
||||
void EmulatedController::SetBattery(Common::Input::CallbackStatus callback, std::size_t index) {
|
||||
void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callback,
|
||||
std::size_t index) {
|
||||
if (index >= controller.battery_values.size()) {
|
||||
return;
|
||||
}
|
||||
@@ -830,23 +843,18 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v
|
||||
}
|
||||
|
||||
bool EmulatedController::TestVibration(std::size_t device_index) {
|
||||
if (device_index >= output_devices.size()) {
|
||||
return false;
|
||||
}
|
||||
if (!output_devices[device_index]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send a slight vibration to test for rumble support
|
||||
constexpr Common::Input::VibrationStatus status = {
|
||||
static constexpr VibrationValue test_vibration = {
|
||||
.low_amplitude = 0.001f,
|
||||
.low_frequency = 160.0f,
|
||||
.high_amplitude = 0.001f,
|
||||
.high_frequency = 320.0f,
|
||||
.type = Common::Input::VibrationAmplificationType::Linear,
|
||||
};
|
||||
return output_devices[device_index]->SetVibration(status) ==
|
||||
Common::Input::VibrationError::None;
|
||||
|
||||
// Send a slight vibration to test for rumble support
|
||||
SetVibration(device_index, test_vibration);
|
||||
|
||||
// Stop any vibration and return the result
|
||||
return SetVibration(device_index, DEFAULT_VIBRATION_VALUE);
|
||||
}
|
||||
|
||||
void EmulatedController::SetLedPattern() {
|
||||
@@ -1110,7 +1118,7 @@ void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npa
|
||||
|
||||
int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) {
|
||||
std::lock_guard lock{mutex};
|
||||
callback_list.insert_or_assign(last_callback_key, update_callback);
|
||||
callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
|
||||
return last_callback_key++;
|
||||
}
|
||||
|
||||
|
||||
@@ -328,35 +328,38 @@ private:
|
||||
* @param callback A CallbackStatus containing the button status
|
||||
* @param index Button ID of the to be updated
|
||||
*/
|
||||
void SetButton(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid);
|
||||
void SetButton(const Common::Input::CallbackStatus& callback, std::size_t index,
|
||||
Common::UUID uuid);
|
||||
|
||||
/**
|
||||
* Updates the analog stick status of the controller
|
||||
* @param callback A CallbackStatus containing the analog stick status
|
||||
* @param index stick ID of the to be updated
|
||||
*/
|
||||
void SetStick(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid);
|
||||
void SetStick(const Common::Input::CallbackStatus& callback, std::size_t index,
|
||||
Common::UUID uuid);
|
||||
|
||||
/**
|
||||
* Updates the trigger status of the controller
|
||||
* @param callback A CallbackStatus containing the trigger status
|
||||
* @param index trigger ID of the to be updated
|
||||
*/
|
||||
void SetTrigger(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid);
|
||||
void SetTrigger(const Common::Input::CallbackStatus& callback, std::size_t index,
|
||||
Common::UUID uuid);
|
||||
|
||||
/**
|
||||
* Updates the motion status of the controller
|
||||
* @param callback A CallbackStatus containing gyro and accelerometer data
|
||||
* @param index motion ID of the to be updated
|
||||
*/
|
||||
void SetMotion(Common::Input::CallbackStatus callback, std::size_t index);
|
||||
void SetMotion(const Common::Input::CallbackStatus& callback, std::size_t index);
|
||||
|
||||
/**
|
||||
* Updates the battery status of the controller
|
||||
* @param callback A CallbackStatus containing the battery status
|
||||
* @param index Button ID of the to be updated
|
||||
*/
|
||||
void SetBattery(Common::Input::CallbackStatus callback, std::size_t index);
|
||||
void SetBattery(const Common::Input::CallbackStatus& callback, std::size_t index);
|
||||
|
||||
/**
|
||||
* Triggers a callback that something has changed on the controller status
|
||||
|
||||
@@ -70,50 +70,55 @@ void EmulatedDevices::ReloadInput() {
|
||||
if (!mouse_button_devices[index]) {
|
||||
continue;
|
||||
}
|
||||
Common::Input::InputCallback button_callback{
|
||||
[this, index](Common::Input::CallbackStatus callback) {
|
||||
SetMouseButton(callback, index);
|
||||
}};
|
||||
mouse_button_devices[index]->SetCallback(button_callback);
|
||||
mouse_button_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
||||
SetMouseButton(callback, index);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < mouse_analog_devices.size(); ++index) {
|
||||
if (!mouse_analog_devices[index]) {
|
||||
continue;
|
||||
}
|
||||
Common::Input::InputCallback button_callback{
|
||||
[this, index](Common::Input::CallbackStatus callback) {
|
||||
SetMouseAnalog(callback, index);
|
||||
}};
|
||||
mouse_analog_devices[index]->SetCallback(button_callback);
|
||||
mouse_analog_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
||||
SetMouseAnalog(callback, index);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (mouse_stick_device) {
|
||||
Common::Input::InputCallback button_callback{
|
||||
[this](Common::Input::CallbackStatus callback) { SetMouseStick(callback); }};
|
||||
mouse_stick_device->SetCallback(button_callback);
|
||||
mouse_stick_device->SetCallback({
|
||||
.on_change =
|
||||
[this](const Common::Input::CallbackStatus& callback) { SetMouseStick(callback); },
|
||||
});
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < keyboard_devices.size(); ++index) {
|
||||
if (!keyboard_devices[index]) {
|
||||
continue;
|
||||
}
|
||||
Common::Input::InputCallback button_callback{
|
||||
[this, index](Common::Input::CallbackStatus callback) {
|
||||
SetKeyboardButton(callback, index);
|
||||
}};
|
||||
keyboard_devices[index]->SetCallback(button_callback);
|
||||
keyboard_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
||||
SetKeyboardButton(callback, index);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < keyboard_modifier_devices.size(); ++index) {
|
||||
if (!keyboard_modifier_devices[index]) {
|
||||
continue;
|
||||
}
|
||||
Common::Input::InputCallback button_callback{
|
||||
[this, index](Common::Input::CallbackStatus callback) {
|
||||
SetKeyboardModifier(callback, index);
|
||||
}};
|
||||
keyboard_modifier_devices[index]->SetCallback(button_callback);
|
||||
keyboard_modifier_devices[index]->SetCallback({
|
||||
.on_change =
|
||||
[this, index](const Common::Input::CallbackStatus& callback) {
|
||||
SetKeyboardModifier(callback, index);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,7 +164,8 @@ void EmulatedDevices::RestoreConfig() {
|
||||
ReloadFromSettings();
|
||||
}
|
||||
|
||||
void EmulatedDevices::SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index) {
|
||||
void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& callback,
|
||||
std::size_t index) {
|
||||
if (index >= device_status.keyboard_values.size()) {
|
||||
return;
|
||||
}
|
||||
@@ -216,7 +222,7 @@ void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) {
|
||||
}
|
||||
}
|
||||
|
||||
void EmulatedDevices::SetKeyboardModifier(Common::Input::CallbackStatus callback,
|
||||
void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& callback,
|
||||
std::size_t index) {
|
||||
if (index >= device_status.keyboard_moddifier_values.size()) {
|
||||
return;
|
||||
@@ -286,7 +292,8 @@ void EmulatedDevices::SetKeyboardModifier(Common::Input::CallbackStatus callback
|
||||
TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
|
||||
}
|
||||
|
||||
void EmulatedDevices::SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index) {
|
||||
void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callback,
|
||||
std::size_t index) {
|
||||
if (index >= device_status.mouse_button_values.size()) {
|
||||
return;
|
||||
}
|
||||
@@ -347,7 +354,8 @@ void EmulatedDevices::SetMouseButton(Common::Input::CallbackStatus callback, std
|
||||
TriggerOnChange(DeviceTriggerType::Mouse);
|
||||
}
|
||||
|
||||
void EmulatedDevices::SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index) {
|
||||
void EmulatedDevices::SetMouseAnalog(const Common::Input::CallbackStatus& callback,
|
||||
std::size_t index) {
|
||||
if (index >= device_status.mouse_analog_values.size()) {
|
||||
return;
|
||||
}
|
||||
@@ -374,7 +382,7 @@ void EmulatedDevices::SetMouseAnalog(Common::Input::CallbackStatus callback, std
|
||||
TriggerOnChange(DeviceTriggerType::Mouse);
|
||||
}
|
||||
|
||||
void EmulatedDevices::SetMouseStick(Common::Input::CallbackStatus callback) {
|
||||
void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callback) {
|
||||
std::lock_guard lock{mutex};
|
||||
const auto touch_value = TransformToTouch(callback);
|
||||
|
||||
@@ -435,7 +443,7 @@ void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
|
||||
|
||||
int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) {
|
||||
std::lock_guard lock{mutex};
|
||||
callback_list.insert_or_assign(last_callback_key, update_callback);
|
||||
callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
|
||||
return last_callback_key++;
|
||||
}
|
||||
|
||||
|
||||
@@ -156,35 +156,34 @@ private:
|
||||
* @param callback A CallbackStatus containing the key status
|
||||
* @param index key ID to be updated
|
||||
*/
|
||||
void SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index);
|
||||
void SetKeyboardButton(const Common::Input::CallbackStatus& callback, std::size_t index);
|
||||
|
||||
/**
|
||||
* Updates the keyboard status of the keyboard device
|
||||
* @param callback A CallbackStatus containing the modifier key status
|
||||
* @param index modifier key ID to be updated
|
||||
*/
|
||||
void SetKeyboardModifier(Common::Input::CallbackStatus callback, std::size_t index);
|
||||
void SetKeyboardModifier(const Common::Input::CallbackStatus& callback, std::size_t index);
|
||||
|
||||
/**
|
||||
* Updates the mouse button status of the mouse device
|
||||
* @param callback A CallbackStatus containing the button status
|
||||
* @param index Button ID to be updated
|
||||
*/
|
||||
void SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index);
|
||||
void SetMouseButton(const Common::Input::CallbackStatus& callback, std::size_t index);
|
||||
|
||||
/**
|
||||
* Updates the mouse wheel status of the mouse device
|
||||
* @param callback A CallbackStatus containing the wheel status
|
||||
* @param index wheel ID to be updated
|
||||
*/
|
||||
void SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index);
|
||||
void SetMouseAnalog(const Common::Input::CallbackStatus& callback, std::size_t index);
|
||||
|
||||
/**
|
||||
* Updates the mouse position status of the mouse device
|
||||
* @param callback A CallbackStatus containing the position status
|
||||
* @param index stick ID to be updated
|
||||
*/
|
||||
void SetMouseStick(Common::Input::CallbackStatus callback);
|
||||
void SetMouseStick(const Common::Input::CallbackStatus& callback);
|
||||
|
||||
/**
|
||||
* Triggers a callback that something has changed on the device status
|
||||
|
||||
@@ -496,6 +496,13 @@ struct VibrationValue {
|
||||
};
|
||||
static_assert(sizeof(VibrationValue) == 0x10, "VibrationValue has incorrect size.");
|
||||
|
||||
constexpr VibrationValue DEFAULT_VIBRATION_VALUE{
|
||||
.low_amplitude = 0.0f,
|
||||
.low_frequency = 160.0f,
|
||||
.high_amplitude = 0.0f,
|
||||
.high_frequency = 320.0f,
|
||||
};
|
||||
|
||||
// This is nn::hid::VibrationDeviceInfo
|
||||
struct VibrationDeviceInfo {
|
||||
VibrationDeviceType type{};
|
||||
|
||||
@@ -23,11 +23,11 @@ void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) {
|
||||
}
|
||||
|
||||
void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) {
|
||||
gyro = gyroscope - gyro_drift;
|
||||
gyro = gyroscope - gyro_bias;
|
||||
|
||||
// Auto adjust drift to minimize drift
|
||||
if (!IsMoving(0.1f)) {
|
||||
gyro_drift = (gyro_drift * 0.9999f) + (gyroscope * 0.0001f);
|
||||
gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f);
|
||||
}
|
||||
|
||||
if (gyro.Length2() < gyro_threshold) {
|
||||
@@ -41,8 +41,8 @@ void MotionInput::SetQuaternion(const Common::Quaternion<f32>& quaternion) {
|
||||
quat = quaternion;
|
||||
}
|
||||
|
||||
void MotionInput::SetGyroDrift(const Common::Vec3f& drift) {
|
||||
gyro_drift = drift;
|
||||
void MotionInput::SetGyroBias(const Common::Vec3f& bias) {
|
||||
gyro_bias = bias;
|
||||
}
|
||||
|
||||
void MotionInput::SetGyroThreshold(f32 threshold) {
|
||||
@@ -192,6 +192,10 @@ Common::Vec3f MotionInput::GetGyroscope() const {
|
||||
return gyro;
|
||||
}
|
||||
|
||||
Common::Vec3f MotionInput::GetGyroBias() const {
|
||||
return gyro_bias;
|
||||
}
|
||||
|
||||
Common::Quaternion<f32> MotionInput::GetQuaternion() const {
|
||||
return quat;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public:
|
||||
void SetAcceleration(const Common::Vec3f& acceleration);
|
||||
void SetGyroscope(const Common::Vec3f& gyroscope);
|
||||
void SetQuaternion(const Common::Quaternion<f32>& quaternion);
|
||||
void SetGyroDrift(const Common::Vec3f& drift);
|
||||
void SetGyroBias(const Common::Vec3f& bias);
|
||||
void SetGyroThreshold(f32 threshold);
|
||||
|
||||
void EnableReset(bool reset);
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
[[nodiscard]] std::array<Common::Vec3f, 3> GetOrientation() const;
|
||||
[[nodiscard]] Common::Vec3f GetAcceleration() const;
|
||||
[[nodiscard]] Common::Vec3f GetGyroscope() const;
|
||||
[[nodiscard]] Common::Vec3f GetGyroBias() const;
|
||||
[[nodiscard]] Common::Vec3f GetRotations() const;
|
||||
[[nodiscard]] Common::Quaternion<f32> GetQuaternion() const;
|
||||
|
||||
@@ -69,7 +70,7 @@ private:
|
||||
Common::Vec3f gyro;
|
||||
|
||||
// Vector to be substracted from gyro measurements
|
||||
Common::Vec3f gyro_drift;
|
||||
Common::Vec3f gyro_bias;
|
||||
|
||||
// Minimum gyro amplitude to detect if the device is moving
|
||||
f32 gyro_threshold = 0.0f;
|
||||
|
||||
@@ -806,6 +806,33 @@ ResultCode KPageTable::ResetTransferMemory(VAddr addr, std::size_t size) {
|
||||
KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped));
|
||||
|
||||
block_manager->Update(addr, size / PageSize, state, KMemoryPermission::ReadAndWrite);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KPageTable::SetMemoryPermission(VAddr addr, std::size_t size,
|
||||
Svc::MemoryPermission svc_perm) {
|
||||
const size_t num_pages = size / PageSize;
|
||||
|
||||
// Lock the table.
|
||||
std::lock_guard lock{page_table_lock};
|
||||
|
||||
// Verify we can change the memory permission.
|
||||
KMemoryState old_state;
|
||||
KMemoryPermission old_perm;
|
||||
R_TRY(this->CheckMemoryState(
|
||||
std::addressof(old_state), std::addressof(old_perm), nullptr, addr, size,
|
||||
KMemoryState::FlagCanReprotect, KMemoryState::FlagCanReprotect, KMemoryPermission::None,
|
||||
KMemoryPermission::None, KMemoryAttribute::All, KMemoryAttribute::None));
|
||||
|
||||
// Determine new perm.
|
||||
const KMemoryPermission new_perm = ConvertToKMemoryPermission(svc_perm);
|
||||
R_SUCCEED_IF(old_perm == new_perm);
|
||||
|
||||
// Perform mapping operation.
|
||||
R_TRY(Operate(addr, num_pages, new_perm, OperationType::ChangePermissions));
|
||||
|
||||
// Update the blocks.
|
||||
block_manager->Update(addr, num_pages, old_state, new_perm, KMemoryAttribute::None);
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ public:
|
||||
KMemoryInfo QueryInfo(VAddr addr);
|
||||
ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm);
|
||||
ResultCode ResetTransferMemory(VAddr addr, std::size_t size);
|
||||
ResultCode SetMemoryPermission(VAddr addr, std::size_t size, Svc::MemoryPermission perm);
|
||||
ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask,
|
||||
KMemoryAttribute value);
|
||||
ResultCode SetHeapCapacity(std::size_t new_heap_capacity);
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/svc_results.h"
|
||||
#include "core/hle/lock.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Kernel {
|
||||
@@ -543,7 +542,6 @@ void KProcess::FreeTLSRegion(VAddr tls_address) {
|
||||
}
|
||||
|
||||
void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) {
|
||||
std::lock_guard lock{HLE::g_hle_lock};
|
||||
const auto ReprotectSegment = [&](const CodeSet::Segment& segment,
|
||||
KMemoryPermission permission) {
|
||||
page_table->SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "core/hle/kernel/k_resource_limit.h"
|
||||
#include "core/hle/kernel/k_scheduler.h"
|
||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||
#include "core/hle/kernel/k_system_control.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/k_thread_queue.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
@@ -50,6 +51,7 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context,
|
||||
VAddr entry_point, u64 arg) {
|
||||
context = {};
|
||||
context.cpu_registers[0] = arg;
|
||||
context.cpu_registers[18] = Kernel::KSystemControl::GenerateRandomU64() | 1;
|
||||
context.pc = entry_point;
|
||||
context.sp = stack_top;
|
||||
// TODO(merry): Perform a hardware test to determine the below value.
|
||||
|
||||
@@ -182,7 +182,10 @@ struct KernelCore::Impl {
|
||||
// Shutdown all processes.
|
||||
if (current_process) {
|
||||
current_process->Finalize();
|
||||
current_process->Close();
|
||||
// current_process->Close();
|
||||
// TODO: The current process should be destroyed based on accurate ref counting after
|
||||
// calling Close(). Adding a manual Destroy() call instead to avoid a memory leak.
|
||||
current_process->Destroy();
|
||||
current_process = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#include "core/hle/kernel/svc_results.h"
|
||||
#include "core/hle/kernel/svc_types.h"
|
||||
#include "core/hle/kernel/svc_wrap.h"
|
||||
#include "core/hle/lock.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/reporter.h"
|
||||
@@ -137,7 +136,6 @@ enum class ResourceLimitValueType {
|
||||
|
||||
/// Set the process heap to a given Size. It can both extend and shrink the heap.
|
||||
static ResultCode SetHeapSize(Core::System& system, VAddr* heap_addr, u64 heap_size) {
|
||||
std::lock_guard lock{HLE::g_hle_lock};
|
||||
LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size);
|
||||
|
||||
// Size must be a multiple of 0x200000 (2MB) and be equal to or less than 8GB.
|
||||
@@ -166,9 +164,38 @@ static ResultCode SetHeapSize32(Core::System& system, u32* heap_addr, u32 heap_s
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) {
|
||||
switch (perm) {
|
||||
case MemoryPermission::None:
|
||||
case MemoryPermission::Read:
|
||||
case MemoryPermission::ReadWrite:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static ResultCode SetMemoryPermission(Core::System& system, VAddr address, u64 size,
|
||||
MemoryPermission perm) {
|
||||
// Validate address / size.
|
||||
R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
|
||||
R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
|
||||
R_UNLESS(size > 0, ResultInvalidSize);
|
||||
R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
|
||||
|
||||
// Validate the permission.
|
||||
R_UNLESS(IsValidSetMemoryPermission(perm), ResultInvalidNewMemoryPermission);
|
||||
|
||||
// Validate that the region is in range for the current process.
|
||||
auto& page_table = system.Kernel().CurrentProcess()->PageTable();
|
||||
R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
|
||||
|
||||
// Set the memory attribute.
|
||||
return page_table.SetMemoryPermission(address, size, perm);
|
||||
}
|
||||
|
||||
static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask,
|
||||
u32 attribute) {
|
||||
std::lock_guard lock{HLE::g_hle_lock};
|
||||
LOG_DEBUG(Kernel_SVC,
|
||||
"called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address,
|
||||
size, mask, attribute);
|
||||
@@ -212,7 +239,6 @@ static ResultCode SetMemoryAttribute32(Core::System& system, u32 address, u32 si
|
||||
|
||||
/// Maps a memory range into a different range.
|
||||
static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) {
|
||||
std::lock_guard lock{HLE::g_hle_lock};
|
||||
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
|
||||
src_addr, size);
|
||||
|
||||
@@ -232,7 +258,6 @@ static ResultCode MapMemory32(Core::System& system, u32 dst_addr, u32 src_addr,
|
||||
|
||||
/// Unmaps a region that was previously mapped with svcMapMemory
|
||||
static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) {
|
||||
std::lock_guard lock{HLE::g_hle_lock};
|
||||
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
|
||||
src_addr, size);
|
||||
|
||||
@@ -642,7 +667,6 @@ static void OutputDebugString(Core::System& system, VAddr address, u64 len) {
|
||||
/// Gets system/memory information for the current process
|
||||
static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle handle,
|
||||
u64 info_sub_id) {
|
||||
std::lock_guard lock{HLE::g_hle_lock};
|
||||
LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
|
||||
info_sub_id, handle);
|
||||
|
||||
@@ -886,22 +910,17 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle
|
||||
return ResultSuccess;
|
||||
}
|
||||
case GetInfoType::IdleTickCount: {
|
||||
if (handle == 0) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
|
||||
static_cast<Handle>(handle));
|
||||
return ResultInvalidHandle;
|
||||
}
|
||||
// Verify the input handle is invalid.
|
||||
R_UNLESS(handle == InvalidHandle, ResultInvalidHandle);
|
||||
|
||||
if (info_sub_id != 0xFFFFFFFFFFFFFFFF &&
|
||||
info_sub_id != system.Kernel().CurrentPhysicalCoreIndex()) {
|
||||
LOG_ERROR(Kernel_SVC, "Core is not the current core, got {}", info_sub_id);
|
||||
return ResultInvalidCombination;
|
||||
}
|
||||
// Verify the requested core is valid.
|
||||
const bool core_valid =
|
||||
(info_sub_id == static_cast<u64>(-1ULL)) ||
|
||||
(info_sub_id == static_cast<u64>(system.Kernel().CurrentPhysicalCoreIndex()));
|
||||
R_UNLESS(core_valid, ResultInvalidCombination);
|
||||
|
||||
const auto& scheduler = *system.Kernel().CurrentScheduler();
|
||||
const auto* const idle_thread = scheduler.GetIdleThread();
|
||||
|
||||
*result = idle_thread->GetCpuTime();
|
||||
// Get the idle tick count.
|
||||
*result = system.Kernel().CurrentScheduler()->GetIdleThread()->GetCpuTime();
|
||||
return ResultSuccess;
|
||||
}
|
||||
default:
|
||||
@@ -924,7 +943,6 @@ static ResultCode GetInfo32(Core::System& system, u32* result_low, u32* result_h
|
||||
|
||||
/// Maps memory at a desired address
|
||||
static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) {
|
||||
std::lock_guard lock{HLE::g_hle_lock};
|
||||
LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size);
|
||||
|
||||
if (!Common::Is4KBAligned(addr)) {
|
||||
@@ -978,7 +996,6 @@ static ResultCode MapPhysicalMemory32(Core::System& system, u32 addr, u32 size)
|
||||
|
||||
/// Unmaps memory previously mapped via MapPhysicalMemory
|
||||
static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size) {
|
||||
std::lock_guard lock{HLE::g_hle_lock};
|
||||
LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size);
|
||||
|
||||
if (!Common::Is4KBAligned(addr)) {
|
||||
@@ -1520,7 +1537,6 @@ static ResultCode ControlCodeMemory(Core::System& system, Handle code_memory_han
|
||||
static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address,
|
||||
VAddr page_info_address, Handle process_handle,
|
||||
VAddr address) {
|
||||
std::lock_guard lock{HLE::g_hle_lock};
|
||||
LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address);
|
||||
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
|
||||
KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
|
||||
@@ -2738,7 +2754,7 @@ static const FunctionDef SVC_Table_32[] = {
|
||||
static const FunctionDef SVC_Table_64[] = {
|
||||
{0x00, nullptr, "Unknown"},
|
||||
{0x01, SvcWrap64<SetHeapSize>, "SetHeapSize"},
|
||||
{0x02, nullptr, "SetMemoryPermission"},
|
||||
{0x02, SvcWrap64<SetMemoryPermission>, "SetMemoryPermission"},
|
||||
{0x03, SvcWrap64<SetMemoryAttribute>, "SetMemoryAttribute"},
|
||||
{0x04, SvcWrap64<MapMemory>, "MapMemory"},
|
||||
{0x05, SvcWrap64<UnmapMemory>, "UnmapMemory"},
|
||||
|
||||
@@ -249,6 +249,14 @@ void SvcWrap64(Core::System& system) {
|
||||
func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw);
|
||||
}
|
||||
|
||||
// Used by SetMemoryPermission
|
||||
template <ResultCode func(Core::System&, u64, u64, Svc::MemoryPermission)>
|
||||
void SvcWrap64(Core::System& system) {
|
||||
FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
|
||||
static_cast<Svc::MemoryPermission>(Param(system, 2)))
|
||||
.raw);
|
||||
}
|
||||
|
||||
// Used by MapSharedMemory
|
||||
template <ResultCode func(Core::System&, Handle, u64, u64, Svc::MemoryPermission)>
|
||||
void SvcWrap64(Core::System& system) {
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
// Copyright 2017 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <core/hle/lock.h>
|
||||
|
||||
namespace HLE {
|
||||
std::recursive_mutex g_hle_lock;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
// Copyright 2017 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace HLE {
|
||||
/*
|
||||
* Synchronizes access to the internal HLE kernel structures, it is acquired when a guest
|
||||
* application thread performs a syscall. It should be acquired by any host threads that read or
|
||||
* modify the HLE kernel state. Note: Any operation that directly or indirectly reads from or writes
|
||||
* to the emulated memory is not protected by this mutex, and should be avoided in any threads other
|
||||
* than the CPU thread.
|
||||
*/
|
||||
extern std::recursive_mutex g_hle_lock;
|
||||
} // namespace HLE
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/lock.h"
|
||||
#include "core/hle/service/bcat/backend/backend.h"
|
||||
|
||||
namespace Service::BCAT {
|
||||
@@ -29,10 +28,6 @@ DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() {
|
||||
return impl;
|
||||
}
|
||||
|
||||
void ProgressServiceBackend::SetNeedHLELock(bool need) {
|
||||
need_hle_lock = need;
|
||||
}
|
||||
|
||||
void ProgressServiceBackend::SetTotalSize(u64 size) {
|
||||
impl.total_bytes = size;
|
||||
SignalUpdate();
|
||||
@@ -88,12 +83,7 @@ void ProgressServiceBackend::FinishDownload(ResultCode result) {
|
||||
}
|
||||
|
||||
void ProgressServiceBackend::SignalUpdate() {
|
||||
if (need_hle_lock) {
|
||||
std::lock_guard lock(HLE::g_hle_lock);
|
||||
update_event->GetWritableEvent().Signal();
|
||||
} else {
|
||||
update_event->GetWritableEvent().Signal();
|
||||
}
|
||||
update_event->GetWritableEvent().Signal();
|
||||
}
|
||||
|
||||
Backend::Backend(DirectoryGetter getter) : dir_getter(std::move(getter)) {}
|
||||
|
||||
@@ -71,10 +71,6 @@ class ProgressServiceBackend {
|
||||
public:
|
||||
~ProgressServiceBackend();
|
||||
|
||||
// Clients should call this with true if any of the functions are going to be called from a
|
||||
// non-HLE thread and this class need to lock the hle mutex. (default is false)
|
||||
void SetNeedHLELock(bool need);
|
||||
|
||||
// Sets the number of bytes total in the entire download.
|
||||
void SetTotalSize(u64 size);
|
||||
|
||||
@@ -109,7 +105,6 @@ private:
|
||||
|
||||
DeliveryCacheProgressImpl impl{};
|
||||
Kernel::KEvent* update_event;
|
||||
bool need_hle_lock = false;
|
||||
};
|
||||
|
||||
// A class representing an abstract backend for BCAT functionality.
|
||||
|
||||
@@ -33,15 +33,14 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti
|
||||
const auto& last_entry = seven_sixaxis_lifo.ReadCurrentEntry().state;
|
||||
next_seven_sixaxis_state.sampling_number = last_entry.sampling_number + 1;
|
||||
|
||||
// Try to read sixaxis sensor states
|
||||
const auto motion_status = console->GetMotion();
|
||||
last_global_timestamp = core_timing.GetGlobalTimeNs().count();
|
||||
|
||||
console_six_axis.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
|
||||
|
||||
// This value increments every time the switch goes to sleep
|
||||
next_seven_sixaxis_state.unknown = 1;
|
||||
next_seven_sixaxis_state.timestamp = last_global_timestamp - last_saved_timestamp;
|
||||
next_seven_sixaxis_state.accel = motion_status.accel;
|
||||
// Zero gyro values as they just mess up with the camera
|
||||
// Note: Probably a correct sensivity setting must be set
|
||||
next_seven_sixaxis_state.gyro = {};
|
||||
next_seven_sixaxis_state.gyro = motion_status.gyro;
|
||||
next_seven_sixaxis_state.quaternion = {
|
||||
{
|
||||
motion_status.quaternion.xyz.y,
|
||||
@@ -52,9 +51,9 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti
|
||||
};
|
||||
|
||||
console_six_axis.sampling_number++;
|
||||
// TODO(German77): Find the purpose of those values
|
||||
console_six_axis.verticalization_error = 0.0f;
|
||||
console_six_axis.gyro_bias = {0.0f, 0.0f, 0.0f};
|
||||
console_six_axis.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
|
||||
console_six_axis.verticalization_error = motion_status.verticalization_error;
|
||||
console_six_axis.gyro_bias = motion_status.gyro_bias;
|
||||
|
||||
// Update console six axis shared memory
|
||||
std::memcpy(data + SHARED_MEMORY_OFFSET, &console_six_axis, sizeof(console_six_axis));
|
||||
@@ -69,7 +68,6 @@ void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) {
|
||||
}
|
||||
|
||||
void Controller_ConsoleSixAxis::ResetTimestamp() {
|
||||
seven_sixaxis_lifo.buffer_count = 0;
|
||||
seven_sixaxis_lifo.buffer_tail = 0;
|
||||
last_saved_timestamp = last_global_timestamp;
|
||||
}
|
||||
} // namespace Service::HID
|
||||
|
||||
@@ -39,8 +39,9 @@ public:
|
||||
|
||||
private:
|
||||
struct SevenSixAxisState {
|
||||
INSERT_PADDING_WORDS(4); // unused
|
||||
s64 sampling_number{};
|
||||
INSERT_PADDING_WORDS(2); // unused
|
||||
u64 timestamp{};
|
||||
u64 sampling_number{};
|
||||
u64 unknown{};
|
||||
Common::Vec3f accel{};
|
||||
Common::Vec3f gyro{};
|
||||
@@ -52,9 +53,10 @@ private:
|
||||
struct ConsoleSharedMemory {
|
||||
u64 sampling_number{};
|
||||
bool is_seven_six_axis_sensor_at_rest{};
|
||||
INSERT_PADDING_BYTES(4); // padding
|
||||
INSERT_PADDING_BYTES(3); // padding
|
||||
f32 verticalization_error{};
|
||||
Common::Vec3f gyro_bias{};
|
||||
INSERT_PADDING_BYTES(4); // padding
|
||||
};
|
||||
static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size");
|
||||
|
||||
@@ -64,6 +66,8 @@ private:
|
||||
Core::HID::EmulatedConsole* console;
|
||||
u8* transfer_memory = nullptr;
|
||||
bool is_transfer_memory_set = false;
|
||||
u64 last_saved_timestamp{};
|
||||
u64 last_global_timestamp{};
|
||||
ConsoleSharedMemory console_six_axis{};
|
||||
SevenSixAxisState next_seven_sixaxis_state{};
|
||||
};
|
||||
|
||||
@@ -66,9 +66,9 @@ Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_,
|
||||
auto& controller = controller_data[i];
|
||||
controller.device = hid_core.GetEmulatedControllerByIndex(i);
|
||||
controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value =
|
||||
DEFAULT_VIBRATION_VALUE;
|
||||
Core::HID::DEFAULT_VIBRATION_VALUE;
|
||||
controller.vibration[Core::HID::EmulatedDeviceIndex::RightIndex].latest_vibration_value =
|
||||
DEFAULT_VIBRATION_VALUE;
|
||||
Core::HID::DEFAULT_VIBRATION_VALUE;
|
||||
Core::HID::ControllerUpdateCallback engine_callback{
|
||||
.on_change = [this,
|
||||
i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); },
|
||||
@@ -781,7 +781,8 @@ bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id,
|
||||
Core::HID::VibrationValue vibration{0.0f, 160.0f, 0.0f, 320.0f};
|
||||
controller.device->SetVibration(device_index, vibration);
|
||||
// Then reset the vibration value to its default value.
|
||||
controller.vibration[device_index].latest_vibration_value = DEFAULT_VIBRATION_VALUE;
|
||||
controller.vibration[device_index].latest_vibration_value =
|
||||
Core::HID::DEFAULT_VIBRATION_VALUE;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -90,13 +90,6 @@ public:
|
||||
Default = 3,
|
||||
};
|
||||
|
||||
static constexpr Core::HID::VibrationValue DEFAULT_VIBRATION_VALUE{
|
||||
.low_amplitude = 0.0f,
|
||||
.low_frequency = 160.0f,
|
||||
.high_amplitude = 0.0f,
|
||||
.high_frequency = 320.0f,
|
||||
};
|
||||
|
||||
void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
|
||||
Core::HID::NpadStyleTag GetSupportedStyleSet() const;
|
||||
|
||||
|
||||
@@ -1404,7 +1404,7 @@ void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
|
||||
.high_frequency = 0.0f,
|
||||
};
|
||||
default:
|
||||
return Controller_NPad::DEFAULT_VIBRATION_VALUE;
|
||||
return Core::HID::DEFAULT_VIBRATION_VALUE;
|
||||
}
|
||||
}();
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/lock.h"
|
||||
#include "core/hle/service/nfp/nfp.h"
|
||||
#include "core/hle/service/nfp/nfp_user.h"
|
||||
|
||||
@@ -337,7 +336,6 @@ void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
|
||||
std::lock_guard lock{HLE::g_hle_lock};
|
||||
if (buffer.size() < sizeof(AmiiboFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,6 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
|
||||
kip->GetTitleID(), 0xFFFFFFFFFFFFFFFF, 0x1FE00000,
|
||||
kip->GetKernelCapabilities());
|
||||
|
||||
const VAddr base_address = process.PageTable().GetCodeRegionStart();
|
||||
Kernel::CodeSet codeset;
|
||||
Kernel::PhysicalMemory program_image;
|
||||
|
||||
@@ -91,7 +90,14 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
|
||||
program_image.resize(PageAlignSize(kip->GetBSSOffset()) + kip->GetBSSSize());
|
||||
codeset.DataSegment().size += kip->GetBSSSize();
|
||||
|
||||
// Setup the process code layout
|
||||
if (process.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), program_image.size())
|
||||
.IsError()) {
|
||||
return {ResultStatus::ErrorNotInitialized, {}};
|
||||
}
|
||||
|
||||
codeset.memory = std::move(program_image);
|
||||
const VAddr base_address = process.PageTable().GetCodeRegionStart();
|
||||
process.LoadModule(std::move(codeset), base_address);
|
||||
|
||||
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", kip->GetName(), base_address);
|
||||
|
||||
@@ -69,7 +69,7 @@ private:
|
||||
libusb_device_handle* handle{};
|
||||
};
|
||||
|
||||
GCAdapter::GCAdapter(const std::string& input_engine_) : InputEngine(input_engine_) {
|
||||
GCAdapter::GCAdapter(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
|
||||
if (usb_adapter_handle) {
|
||||
return;
|
||||
}
|
||||
@@ -325,8 +325,8 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier,
|
||||
const Common::Input::VibrationStatus vibration) {
|
||||
Common::Input::VibrationError GCAdapter::SetRumble(
|
||||
const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) {
|
||||
const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f;
|
||||
const auto processed_amplitude =
|
||||
static_cast<u8>((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8);
|
||||
|
||||
@@ -22,13 +22,13 @@ namespace InputCommon {
|
||||
class LibUSBContext;
|
||||
class LibUSBDeviceHandle;
|
||||
|
||||
class GCAdapter : public InputCommon::InputEngine {
|
||||
class GCAdapter : public InputEngine {
|
||||
public:
|
||||
explicit GCAdapter(const std::string& input_engine_);
|
||||
~GCAdapter();
|
||||
explicit GCAdapter(std::string input_engine_);
|
||||
~GCAdapter() override;
|
||||
|
||||
Common::Input::VibrationError SetRumble(
|
||||
const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override;
|
||||
const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;
|
||||
|
||||
/// Used for automapping features
|
||||
std::vector<Common::ParamPackage> GetInputDevices() const override;
|
||||
|
||||
@@ -24,7 +24,7 @@ constexpr PadIdentifier keyboard_modifier_identifier = {
|
||||
.pad = 1,
|
||||
};
|
||||
|
||||
Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) {
|
||||
Keyboard::Keyboard(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
|
||||
// Keyboard is broken into 3 diferent sets:
|
||||
// key: Unfiltered intended for controllers.
|
||||
// keyboard_key: Allows only Settings::NativeKeyboard::Keys intended for keyboard emulation.
|
||||
|
||||
@@ -12,9 +12,9 @@ namespace InputCommon {
|
||||
* A button device factory representing a keyboard. It receives keyboard events and forward them
|
||||
* to all button devices it created.
|
||||
*/
|
||||
class Keyboard final : public InputCommon::InputEngine {
|
||||
class Keyboard final : public InputEngine {
|
||||
public:
|
||||
explicit Keyboard(const std::string& input_engine_);
|
||||
explicit Keyboard(std::string input_engine_);
|
||||
|
||||
/**
|
||||
* Sets the status of all buttons bound with the key to pressed
|
||||
|
||||
@@ -24,7 +24,7 @@ constexpr PadIdentifier identifier = {
|
||||
.pad = 0,
|
||||
};
|
||||
|
||||
Mouse::Mouse(const std::string& input_engine_) : InputEngine(input_engine_) {
|
||||
Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
|
||||
PreSetController(identifier);
|
||||
PreSetAxis(identifier, mouse_axis_x);
|
||||
PreSetAxis(identifier, mouse_axis_y);
|
||||
|
||||
@@ -27,9 +27,9 @@ enum class MouseButton {
|
||||
* A button device factory representing a keyboard. It receives keyboard events and forward them
|
||||
* to all button devices it created.
|
||||
*/
|
||||
class Mouse final : public InputCommon::InputEngine {
|
||||
class Mouse final : public InputEngine {
|
||||
public:
|
||||
explicit Mouse(const std::string& input_engine_);
|
||||
explicit Mouse(std::string input_engine_);
|
||||
|
||||
/**
|
||||
* Signals that mouse has moved.
|
||||
|
||||
@@ -88,7 +88,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
BasicMotion GetMotion() {
|
||||
const BasicMotion& GetMotion() const {
|
||||
return motion;
|
||||
}
|
||||
|
||||
@@ -367,7 +367,7 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) {
|
||||
if (joystick->UpdateMotion(event.csensor)) {
|
||||
const PadIdentifier identifier = joystick->GetPadIdentifier();
|
||||
SetMotion(identifier, 0, joystick->GetMotion());
|
||||
};
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -387,7 +387,7 @@ void SDLDriver::CloseJoysticks() {
|
||||
joystick_map.clear();
|
||||
}
|
||||
|
||||
SDLDriver::SDLDriver(const std::string& input_engine_) : InputEngine(input_engine_) {
|
||||
SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
|
||||
if (!Settings::values.enable_raw_input) {
|
||||
// Disable raw input. When enabled this setting causes SDL to die when a web applet opens
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0");
|
||||
@@ -403,10 +403,11 @@ SDLDriver::SDLDriver(const std::string& input_engine_) : InputEngine(input_engin
|
||||
|
||||
// Use hidapi driver for joycons. This will allow joycons to be detected as a GameController and
|
||||
// not a generic one
|
||||
SDL_SetHint("SDL_JOYSTICK_HIDAPI_JOY_CONS", "1");
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
|
||||
|
||||
// Turn off Pro controller home led
|
||||
SDL_SetHint("SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED", "0");
|
||||
// Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native
|
||||
// driver on Linux.
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0");
|
||||
|
||||
// If the frontend is going to manage the event loop, then we don't start one here
|
||||
start_thread = SDL_WasInit(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) == 0;
|
||||
@@ -491,8 +492,9 @@ std::vector<Common::ParamPackage> SDLDriver::GetInputDevices() const {
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
Common::Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier,
|
||||
const Common::Input::VibrationStatus vibration) {
|
||||
|
||||
Common::Input::VibrationError SDLDriver::SetRumble(
|
||||
const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) {
|
||||
const auto joystick =
|
||||
GetSDLJoystickByGUID(identifier.guid.Format(), static_cast<int>(identifier.port));
|
||||
const auto process_amplitude_exp = [](f32 amplitude, f32 factor) {
|
||||
@@ -526,6 +528,7 @@ Common::Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifi
|
||||
|
||||
return Common::Input::VibrationError::None;
|
||||
}
|
||||
|
||||
Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid,
|
||||
s32 axis, float value) const {
|
||||
Common::ParamPackage params{};
|
||||
|
||||
@@ -19,19 +19,19 @@ using SDL_GameController = struct _SDL_GameController;
|
||||
using SDL_Joystick = struct _SDL_Joystick;
|
||||
using SDL_JoystickID = s32;
|
||||
|
||||
namespace InputCommon {
|
||||
|
||||
class SDLJoystick;
|
||||
|
||||
using ButtonBindings =
|
||||
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>;
|
||||
using ZButtonBindings =
|
||||
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;
|
||||
|
||||
namespace InputCommon {
|
||||
|
||||
class SDLJoystick;
|
||||
|
||||
class SDLDriver : public InputCommon::InputEngine {
|
||||
class SDLDriver : public InputEngine {
|
||||
public:
|
||||
/// Initializes and registers SDL device factories
|
||||
SDLDriver(const std::string& input_engine_);
|
||||
explicit SDLDriver(std::string input_engine_);
|
||||
|
||||
/// Unregisters SDL device factories and shut them down.
|
||||
~SDLDriver() override;
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
u8 GetHatButtonId(const std::string& direction_name) const override;
|
||||
|
||||
Common::Input::VibrationError SetRumble(
|
||||
const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override;
|
||||
const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;
|
||||
|
||||
private:
|
||||
void InitJoystick(int joystick_index);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstring>
|
||||
#include <regex>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "common/fs/file.h"
|
||||
@@ -15,7 +14,7 @@
|
||||
|
||||
namespace InputCommon::TasInput {
|
||||
|
||||
enum TasAxes : u8 {
|
||||
enum class Tas::TasAxis : u8 {
|
||||
StickX,
|
||||
StickY,
|
||||
SubstickX,
|
||||
@@ -47,7 +46,7 @@ constexpr std::array<std::pair<std::string_view, TasButton>, 20> text_to_tas_but
|
||||
{"KEY_ZR", TasButton::TRIGGER_ZR},
|
||||
};
|
||||
|
||||
Tas::Tas(const std::string& input_engine_) : InputCommon::InputEngine(input_engine_) {
|
||||
Tas::Tas(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
|
||||
for (size_t player_index = 0; player_index < PLAYER_NUMBER; player_index++) {
|
||||
PadIdentifier identifier{
|
||||
.guid = Common::UUID{},
|
||||
@@ -66,7 +65,7 @@ Tas::Tas(const std::string& input_engine_) : InputCommon::InputEngine(input_engi
|
||||
|
||||
Tas::~Tas() {
|
||||
Stop();
|
||||
};
|
||||
}
|
||||
|
||||
void Tas::LoadTasFiles() {
|
||||
script_length = 0;
|
||||
@@ -79,43 +78,43 @@ void Tas::LoadTasFiles() {
|
||||
}
|
||||
|
||||
void Tas::LoadTasFile(size_t player_index, size_t file_index) {
|
||||
if (!commands[player_index].empty()) {
|
||||
commands[player_index].clear();
|
||||
}
|
||||
commands[player_index].clear();
|
||||
|
||||
std::string file = Common::FS::ReadStringFromFile(
|
||||
Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) /
|
||||
fmt::format("script{}-{}.txt", file_index, player_index + 1),
|
||||
Common::FS::FileType::BinaryFile);
|
||||
std::stringstream command_line(file);
|
||||
std::istringstream command_line(file);
|
||||
std::string line;
|
||||
int frame_no = 0;
|
||||
while (std::getline(command_line, line, '\n')) {
|
||||
if (line.empty()) {
|
||||
continue;
|
||||
}
|
||||
std::smatch m;
|
||||
|
||||
std::stringstream linestream(line);
|
||||
std::string segment;
|
||||
std::vector<std::string> seglist;
|
||||
|
||||
while (std::getline(linestream, segment, ' ')) {
|
||||
seglist.push_back(segment);
|
||||
std::vector<std::string> seg_list;
|
||||
{
|
||||
std::istringstream line_stream(line);
|
||||
std::string segment;
|
||||
while (std::getline(line_stream, segment, ' ')) {
|
||||
seg_list.push_back(std::move(segment));
|
||||
}
|
||||
}
|
||||
|
||||
if (seglist.size() < 4) {
|
||||
if (seg_list.size() < 4) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while (frame_no < std::stoi(seglist.at(0))) {
|
||||
commands[player_index].push_back({});
|
||||
const auto num_frames = std::stoi(seg_list[0]);
|
||||
while (frame_no < num_frames) {
|
||||
commands[player_index].emplace_back();
|
||||
frame_no++;
|
||||
}
|
||||
|
||||
TASCommand command = {
|
||||
.buttons = ReadCommandButtons(seglist.at(1)),
|
||||
.l_axis = ReadCommandAxis(seglist.at(2)),
|
||||
.r_axis = ReadCommandAxis(seglist.at(3)),
|
||||
.buttons = ReadCommandButtons(seg_list[1]),
|
||||
.l_axis = ReadCommandAxis(seg_list[2]),
|
||||
.r_axis = ReadCommandAxis(seg_list[3]),
|
||||
};
|
||||
commands[player_index].push_back(command);
|
||||
frame_no++;
|
||||
@@ -123,16 +122,17 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) {
|
||||
LOG_INFO(Input, "TAS file loaded! {} frames", frame_no);
|
||||
}
|
||||
|
||||
void Tas::WriteTasFile(std::u8string file_name) {
|
||||
void Tas::WriteTasFile(std::u8string_view file_name) {
|
||||
std::string output_text;
|
||||
for (size_t frame = 0; frame < record_commands.size(); frame++) {
|
||||
const TASCommand& line = record_commands[frame];
|
||||
output_text += fmt::format("{} {} {} {}\n", frame, WriteCommandButtons(line.buttons),
|
||||
WriteCommandAxis(line.l_axis), WriteCommandAxis(line.r_axis));
|
||||
}
|
||||
const auto bytes_written = Common::FS::WriteStringToFile(
|
||||
Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name,
|
||||
Common::FS::FileType::TextFile, output_text);
|
||||
|
||||
const auto tas_file_name = Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name;
|
||||
const auto bytes_written =
|
||||
Common::FS::WriteStringToFile(tas_file_name, Common::FS::FileType::TextFile, output_text);
|
||||
if (bytes_written == output_text.size()) {
|
||||
LOG_INFO(Input, "TAS file written to file!");
|
||||
} else {
|
||||
@@ -205,10 +205,10 @@ void Tas::UpdateThread() {
|
||||
const int button = static_cast<int>(i);
|
||||
SetButton(identifier, button, button_status);
|
||||
}
|
||||
SetAxis(identifier, TasAxes::StickX, command.l_axis.x);
|
||||
SetAxis(identifier, TasAxes::StickY, command.l_axis.y);
|
||||
SetAxis(identifier, TasAxes::SubstickX, command.r_axis.x);
|
||||
SetAxis(identifier, TasAxes::SubstickY, command.r_axis.y);
|
||||
SetTasAxis(identifier, TasAxis::StickX, command.l_axis.x);
|
||||
SetTasAxis(identifier, TasAxis::StickY, command.l_axis.y);
|
||||
SetTasAxis(identifier, TasAxis::SubstickX, command.r_axis.x);
|
||||
SetTasAxis(identifier, TasAxis::SubstickY, command.r_axis.y);
|
||||
}
|
||||
} else {
|
||||
is_running = Settings::values.tas_loop.GetValue();
|
||||
@@ -224,27 +224,28 @@ void Tas::ClearInput() {
|
||||
}
|
||||
|
||||
TasAnalog Tas::ReadCommandAxis(const std::string& line) const {
|
||||
std::stringstream linestream(line);
|
||||
std::string segment;
|
||||
std::vector<std::string> seglist;
|
||||
|
||||
while (std::getline(linestream, segment, ';')) {
|
||||
seglist.push_back(segment);
|
||||
std::vector<std::string> seg_list;
|
||||
{
|
||||
std::istringstream line_stream(line);
|
||||
std::string segment;
|
||||
while (std::getline(line_stream, segment, ';')) {
|
||||
seg_list.push_back(std::move(segment));
|
||||
}
|
||||
}
|
||||
|
||||
const float x = std::stof(seglist.at(0)) / 32767.0f;
|
||||
const float y = std::stof(seglist.at(1)) / 32767.0f;
|
||||
const float x = std::stof(seg_list.at(0)) / 32767.0f;
|
||||
const float y = std::stof(seg_list.at(1)) / 32767.0f;
|
||||
|
||||
return {x, y};
|
||||
}
|
||||
|
||||
u64 Tas::ReadCommandButtons(const std::string& data) const {
|
||||
std::stringstream button_text(data);
|
||||
std::string line;
|
||||
u64 Tas::ReadCommandButtons(const std::string& line) const {
|
||||
std::istringstream button_text(line);
|
||||
std::string button_line;
|
||||
u64 buttons = 0;
|
||||
while (std::getline(button_text, line, ';')) {
|
||||
for (auto [text, tas_button] : text_to_tas_button) {
|
||||
if (text == line) {
|
||||
while (std::getline(button_text, button_line, ';')) {
|
||||
for (const auto& [text, tas_button] : text_to_tas_button) {
|
||||
if (text == button_line) {
|
||||
buttons |= static_cast<u64>(tas_button);
|
||||
break;
|
||||
}
|
||||
@@ -254,8 +255,8 @@ u64 Tas::ReadCommandButtons(const std::string& data) const {
|
||||
}
|
||||
|
||||
std::string Tas::WriteCommandButtons(u64 buttons) const {
|
||||
std::string returns = "";
|
||||
for (auto [text_button, tas_button] : text_to_tas_button) {
|
||||
std::string returns;
|
||||
for (const auto& [text_button, tas_button] : text_to_tas_button) {
|
||||
if ((buttons & static_cast<u64>(tas_button)) != 0) {
|
||||
returns += fmt::format("{};", text_button);
|
||||
}
|
||||
@@ -267,6 +268,10 @@ std::string Tas::WriteCommandAxis(TasAnalog analog) const {
|
||||
return fmt::format("{};{}", analog.x * 32767, analog.y * 32767);
|
||||
}
|
||||
|
||||
void Tas::SetTasAxis(const PadIdentifier& identifier, TasAxis axis, f32 value) {
|
||||
SetAxis(identifier, static_cast<int>(axis), value);
|
||||
}
|
||||
|
||||
void Tas::StartStop() {
|
||||
if (!Settings::values.tas_enable) {
|
||||
return;
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/settings_input.h"
|
||||
#include "input_common/input_engine.h"
|
||||
#include "input_common/main.h"
|
||||
|
||||
/*
|
||||
To play back TAS scripts on Yuzu, select the folder with scripts in the configuration menu below
|
||||
@@ -81,46 +81,46 @@ enum class TasState {
|
||||
Stopped,
|
||||
};
|
||||
|
||||
class Tas final : public InputCommon::InputEngine {
|
||||
class Tas final : public InputEngine {
|
||||
public:
|
||||
explicit Tas(const std::string& input_engine_);
|
||||
~Tas();
|
||||
explicit Tas(std::string input_engine_);
|
||||
~Tas() override;
|
||||
|
||||
/**
|
||||
* Changes the input status that will be stored in each frame
|
||||
* @param buttons: bitfield with the status of the buttons
|
||||
* @param left_axis: value of the left axis
|
||||
* @param right_axis: value of the right axis
|
||||
* @param buttons Bitfield with the status of the buttons
|
||||
* @param left_axis Value of the left axis
|
||||
* @param right_axis Value of the right axis
|
||||
*/
|
||||
void RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis);
|
||||
|
||||
// Main loop that records or executes input
|
||||
void UpdateThread();
|
||||
|
||||
// Sets the flag to start or stop the TAS command excecution and swaps controllers profiles
|
||||
// Sets the flag to start or stop the TAS command execution and swaps controllers profiles
|
||||
void StartStop();
|
||||
|
||||
// Stop the TAS and reverts any controller profile
|
||||
// Stop the TAS and reverts any controller profile
|
||||
void Stop();
|
||||
|
||||
// Sets the flag to reload the file and start from the begining in the next update
|
||||
// Sets the flag to reload the file and start from the beginning in the next update
|
||||
void Reset();
|
||||
|
||||
/**
|
||||
* Sets the flag to enable or disable recording of inputs
|
||||
* @return Returns true if the current recording status is enabled
|
||||
* @returns true if the current recording status is enabled
|
||||
*/
|
||||
bool Record();
|
||||
|
||||
/**
|
||||
* Saves contents of record_commands on a file
|
||||
* @param overwrite_file: Indicates if player 1 should be overwritten
|
||||
* @param overwrite_file Indicates if player 1 should be overwritten
|
||||
*/
|
||||
void SaveRecording(bool overwrite_file);
|
||||
|
||||
/**
|
||||
* Returns the current status values of TAS playback/recording
|
||||
* @return Tuple of
|
||||
* @returns A Tuple of
|
||||
* TasState indicating the current state out of Running ;
|
||||
* Current playback progress ;
|
||||
* Total length of script file currently loaded or being recorded
|
||||
@@ -128,6 +128,8 @@ public:
|
||||
std::tuple<TasState, size_t, size_t> GetStatus() const;
|
||||
|
||||
private:
|
||||
enum class TasAxis : u8;
|
||||
|
||||
struct TASCommand {
|
||||
u64 buttons{};
|
||||
TasAnalog l_axis{};
|
||||
@@ -137,29 +139,31 @@ private:
|
||||
/// Loads TAS files from all players
|
||||
void LoadTasFiles();
|
||||
|
||||
/** Loads TAS file from the specified player
|
||||
* @param player_index: player number to save the script
|
||||
* @param file_index: script number of the file
|
||||
/**
|
||||
* Loads TAS file from the specified player
|
||||
* @param player_index Player number to save the script
|
||||
* @param file_index Script number of the file
|
||||
*/
|
||||
void LoadTasFile(size_t player_index, size_t file_index);
|
||||
|
||||
/** Writes a TAS file from the recorded commands
|
||||
* @param file_name: name of the file to be written
|
||||
/**
|
||||
* Writes a TAS file from the recorded commands
|
||||
* @param file_name Name of the file to be written
|
||||
*/
|
||||
void WriteTasFile(std::u8string file_name);
|
||||
void WriteTasFile(std::u8string_view file_name);
|
||||
|
||||
/**
|
||||
* Parses a string containing the axis values. X and Y have a range from -32767 to 32767
|
||||
* @param line: string containing axis values with the following format "x;y"
|
||||
* @return Returns a TAS analog object with axis values with range from -1.0 to 1.0
|
||||
* @param line String containing axis values with the following format "x;y"
|
||||
* @returns A TAS analog object with axis values with range from -1.0 to 1.0
|
||||
*/
|
||||
TasAnalog ReadCommandAxis(const std::string& line) const;
|
||||
|
||||
/**
|
||||
* Parses a string containing the button values. Each button is represented by it's text format
|
||||
* specified in text_to_tas_button array
|
||||
* @param line: string containing button name with the following format "a;b;c;d..."
|
||||
* @return Returns a u64 with each bit representing the status of a button
|
||||
* @param line string containing button name with the following format "a;b;c;d..."
|
||||
* @returns A u64 with each bit representing the status of a button
|
||||
*/
|
||||
u64 ReadCommandButtons(const std::string& line) const;
|
||||
|
||||
@@ -170,17 +174,20 @@ private:
|
||||
|
||||
/**
|
||||
* Converts an u64 containing the button status into the text equivalent
|
||||
* @param buttons: bitfield with the status of the buttons
|
||||
* @return Returns a string with the name of the buttons to be written to the file
|
||||
* @param buttons Bitfield with the status of the buttons
|
||||
* @returns A string with the name of the buttons to be written to the file
|
||||
*/
|
||||
std::string WriteCommandButtons(u64 buttons) const;
|
||||
|
||||
/**
|
||||
* Converts an TAS analog object containing the axis status into the text equivalent
|
||||
* @param data: value of the axis
|
||||
* @return A string with the value of the axis to be written to the file
|
||||
* @param analog Value of the axis
|
||||
* @returns A string with the value of the axis to be written to the file
|
||||
*/
|
||||
std::string WriteCommandAxis(TasAnalog data) const;
|
||||
std::string WriteCommandAxis(TasAnalog analog) const;
|
||||
|
||||
/// Sets an axis for a particular pad to the given value.
|
||||
void SetTasAxis(const PadIdentifier& identifier, TasAxis axis, f32 value);
|
||||
|
||||
size_t script_length{0};
|
||||
bool is_recording{false};
|
||||
|
||||
@@ -13,7 +13,7 @@ constexpr PadIdentifier identifier = {
|
||||
.pad = 0,
|
||||
};
|
||||
|
||||
TouchScreen::TouchScreen(const std::string& input_engine_) : InputEngine(input_engine_) {
|
||||
TouchScreen::TouchScreen(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
|
||||
PreSetController(identifier);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ namespace InputCommon {
|
||||
* A button device factory representing a keyboard. It receives keyboard events and forward them
|
||||
* to all button devices it created.
|
||||
*/
|
||||
class TouchScreen final : public InputCommon::InputEngine {
|
||||
class TouchScreen final : public InputEngine {
|
||||
public:
|
||||
explicit TouchScreen(const std::string& input_engine_);
|
||||
explicit TouchScreen(std::string input_engine_);
|
||||
|
||||
/**
|
||||
* Signals that mouse has moved.
|
||||
|
||||
@@ -136,7 +136,7 @@ static void SocketLoop(Socket* socket) {
|
||||
socket->Loop();
|
||||
}
|
||||
|
||||
UDPClient::UDPClient(const std::string& input_engine_) : InputEngine(input_engine_) {
|
||||
UDPClient::UDPClient(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
|
||||
LOG_INFO(Input, "Udp Initialization started");
|
||||
ReloadSockets();
|
||||
}
|
||||
@@ -536,42 +536,46 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
|
||||
std::function<void(u16, u16, u16, u16)> data_callback) {
|
||||
|
||||
std::thread([=, this] {
|
||||
u16 min_x{UINT16_MAX};
|
||||
u16 min_y{UINT16_MAX};
|
||||
u16 max_x{};
|
||||
u16 max_y{};
|
||||
|
||||
Status current_status{Status::Initialized};
|
||||
SocketCallback callback{
|
||||
[](Response::Version) {}, [](Response::PortInfo) {},
|
||||
[&](Response::PadData data) {
|
||||
static constexpr u16 CALIBRATION_THRESHOLD = 100;
|
||||
static constexpr u16 MAX_VALUE = UINT16_MAX;
|
||||
SocketCallback callback{[](Response::Version) {}, [](Response::PortInfo) {},
|
||||
[&](Response::PadData data) {
|
||||
constexpr u16 CALIBRATION_THRESHOLD = 100;
|
||||
|
||||
if (current_status == Status::Initialized) {
|
||||
// Receiving data means the communication is ready now
|
||||
current_status = Status::Ready;
|
||||
status_callback(current_status);
|
||||
}
|
||||
const auto& touchpad_0 = data.touch[0];
|
||||
if (touchpad_0.is_active == 0) {
|
||||
return;
|
||||
}
|
||||
LOG_DEBUG(Input, "Current touch: {} {}", touchpad_0.x, touchpad_0.y);
|
||||
const u16 min_x = std::min(MAX_VALUE, static_cast<u16>(touchpad_0.x));
|
||||
const u16 min_y = std::min(MAX_VALUE, static_cast<u16>(touchpad_0.y));
|
||||
if (current_status == Status::Ready) {
|
||||
// First touch - min data (min_x/min_y)
|
||||
current_status = Status::Stage1Completed;
|
||||
status_callback(current_status);
|
||||
}
|
||||
if (touchpad_0.x - min_x > CALIBRATION_THRESHOLD &&
|
||||
touchpad_0.y - min_y > CALIBRATION_THRESHOLD) {
|
||||
// Set the current position as max value and finishes configuration
|
||||
const u16 max_x = touchpad_0.x;
|
||||
const u16 max_y = touchpad_0.y;
|
||||
current_status = Status::Completed;
|
||||
data_callback(min_x, min_y, max_x, max_y);
|
||||
status_callback(current_status);
|
||||
if (current_status == Status::Initialized) {
|
||||
// Receiving data means the communication is ready now
|
||||
current_status = Status::Ready;
|
||||
status_callback(current_status);
|
||||
}
|
||||
if (data.touch[0].is_active == 0) {
|
||||
return;
|
||||
}
|
||||
LOG_DEBUG(Input, "Current touch: {} {}", data.touch[0].x,
|
||||
data.touch[0].y);
|
||||
min_x = std::min(min_x, static_cast<u16>(data.touch[0].x));
|
||||
min_y = std::min(min_y, static_cast<u16>(data.touch[0].y));
|
||||
if (current_status == Status::Ready) {
|
||||
// First touch - min data (min_x/min_y)
|
||||
current_status = Status::Stage1Completed;
|
||||
status_callback(current_status);
|
||||
}
|
||||
if (data.touch[0].x - min_x > CALIBRATION_THRESHOLD &&
|
||||
data.touch[0].y - min_y > CALIBRATION_THRESHOLD) {
|
||||
// Set the current position as max value and finishes
|
||||
// configuration
|
||||
max_x = data.touch[0].x;
|
||||
max_y = data.touch[0].y;
|
||||
current_status = Status::Completed;
|
||||
data_callback(min_x, min_y, max_x, max_y);
|
||||
status_callback(current_status);
|
||||
|
||||
complete_event.Set();
|
||||
}
|
||||
}};
|
||||
complete_event.Set();
|
||||
}
|
||||
}};
|
||||
Socket socket{host, port, std::move(callback)};
|
||||
std::thread worker_thread{SocketLoop, &socket};
|
||||
complete_event.Wait();
|
||||
|
||||
@@ -49,10 +49,10 @@ struct DeviceStatus {
|
||||
* A button device factory representing a keyboard. It receives keyboard events and forward them
|
||||
* to all button devices it created.
|
||||
*/
|
||||
class UDPClient final : public InputCommon::InputEngine {
|
||||
class UDPClient final : public InputEngine {
|
||||
public:
|
||||
explicit UDPClient(const std::string& input_engine_);
|
||||
~UDPClient();
|
||||
explicit UDPClient(std::string input_engine_);
|
||||
~UDPClient() override;
|
||||
|
||||
void ReloadSockets();
|
||||
|
||||
|
||||
@@ -19,23 +19,36 @@ public:
|
||||
: up(std::move(up_)), down(std::move(down_)), left(std::move(left_)),
|
||||
right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_),
|
||||
modifier_angle(modifier_angle_) {
|
||||
Common::Input::InputCallback button_up_callback{
|
||||
[this](Common::Input::CallbackStatus callback_) { UpdateUpButtonStatus(callback_); }};
|
||||
Common::Input::InputCallback button_down_callback{
|
||||
[this](Common::Input::CallbackStatus callback_) { UpdateDownButtonStatus(callback_); }};
|
||||
Common::Input::InputCallback button_left_callback{
|
||||
[this](Common::Input::CallbackStatus callback_) { UpdateLeftButtonStatus(callback_); }};
|
||||
Common::Input::InputCallback button_right_callback{
|
||||
[this](Common::Input::CallbackStatus callback_) {
|
||||
UpdateRightButtonStatus(callback_);
|
||||
}};
|
||||
Common::Input::InputCallback button_modifier_callback{
|
||||
[this](Common::Input::CallbackStatus callback_) { UpdateModButtonStatus(callback_); }};
|
||||
up->SetCallback(button_up_callback);
|
||||
down->SetCallback(button_down_callback);
|
||||
left->SetCallback(button_left_callback);
|
||||
right->SetCallback(button_right_callback);
|
||||
modifier->SetCallback(button_modifier_callback);
|
||||
up->SetCallback({
|
||||
.on_change =
|
||||
[this](const Common::Input::CallbackStatus& callback_) {
|
||||
UpdateUpButtonStatus(callback_);
|
||||
},
|
||||
});
|
||||
down->SetCallback({
|
||||
.on_change =
|
||||
[this](const Common::Input::CallbackStatus& callback_) {
|
||||
UpdateDownButtonStatus(callback_);
|
||||
},
|
||||
});
|
||||
left->SetCallback({
|
||||
.on_change =
|
||||
[this](const Common::Input::CallbackStatus& callback_) {
|
||||
UpdateLeftButtonStatus(callback_);
|
||||
},
|
||||
});
|
||||
right->SetCallback({
|
||||
.on_change =
|
||||
[this](const Common::Input::CallbackStatus& callback_) {
|
||||
UpdateRightButtonStatus(callback_);
|
||||
},
|
||||
});
|
||||
modifier->SetCallback({
|
||||
.on_change =
|
||||
[this](const Common::Input::CallbackStatus& callback_) {
|
||||
UpdateModButtonStatus(callback_);
|
||||
},
|
||||
});
|
||||
last_x_axis_value = 0.0f;
|
||||
last_y_axis_value = 0.0f;
|
||||
}
|
||||
@@ -133,27 +146,27 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateUpButtonStatus(Common::Input::CallbackStatus button_callback) {
|
||||
void UpdateUpButtonStatus(const Common::Input::CallbackStatus& button_callback) {
|
||||
up_status = button_callback.button_status.value;
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
void UpdateDownButtonStatus(Common::Input::CallbackStatus button_callback) {
|
||||
void UpdateDownButtonStatus(const Common::Input::CallbackStatus& button_callback) {
|
||||
down_status = button_callback.button_status.value;
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
void UpdateLeftButtonStatus(Common::Input::CallbackStatus button_callback) {
|
||||
void UpdateLeftButtonStatus(const Common::Input::CallbackStatus& button_callback) {
|
||||
left_status = button_callback.button_status.value;
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
void UpdateRightButtonStatus(Common::Input::CallbackStatus button_callback) {
|
||||
void UpdateRightButtonStatus(const Common::Input::CallbackStatus& button_callback) {
|
||||
right_status = button_callback.button_status.value;
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
void UpdateModButtonStatus(Common::Input::CallbackStatus button_callback) {
|
||||
void UpdateModButtonStatus(const Common::Input::CallbackStatus& button_callback) {
|
||||
modifier_status = button_callback.button_status.value;
|
||||
UpdateStatus();
|
||||
}
|
||||
@@ -265,18 +278,18 @@ private:
|
||||
Button left;
|
||||
Button right;
|
||||
Button modifier;
|
||||
float modifier_scale;
|
||||
float modifier_angle;
|
||||
float modifier_scale{};
|
||||
float modifier_angle{};
|
||||
float angle{};
|
||||
float goal_angle{};
|
||||
float amplitude{};
|
||||
bool up_status;
|
||||
bool down_status;
|
||||
bool left_status;
|
||||
bool right_status;
|
||||
bool modifier_status;
|
||||
float last_x_axis_value;
|
||||
float last_y_axis_value;
|
||||
bool up_status{};
|
||||
bool down_status{};
|
||||
bool left_status{};
|
||||
bool right_status{};
|
||||
bool modifier_status{};
|
||||
float last_x_axis_value{};
|
||||
float last_y_axis_value{};
|
||||
const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false};
|
||||
std::chrono::time_point<std::chrono::steady_clock> last_update;
|
||||
};
|
||||
|
||||
@@ -14,10 +14,13 @@ public:
|
||||
using Button = std::unique_ptr<Common::Input::InputDevice>;
|
||||
TouchFromButtonDevice(Button button_, int touch_id_, float x_, float y_)
|
||||
: button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) {
|
||||
Common::Input::InputCallback button_up_callback{
|
||||
[this](Common::Input::CallbackStatus callback_) { UpdateButtonStatus(callback_); }};
|
||||
last_button_value = false;
|
||||
button->SetCallback(button_up_callback);
|
||||
button->SetCallback({
|
||||
.on_change =
|
||||
[this](const Common::Input::CallbackStatus& callback_) {
|
||||
UpdateButtonStatus(callback_);
|
||||
},
|
||||
});
|
||||
button->ForceUpdate();
|
||||
}
|
||||
|
||||
@@ -47,7 +50,7 @@ public:
|
||||
return status;
|
||||
}
|
||||
|
||||
void UpdateButtonStatus(Common::Input::CallbackStatus button_callback) {
|
||||
void UpdateButtonStatus(const Common::Input::CallbackStatus& button_callback) {
|
||||
const Common::Input::CallbackStatus status{
|
||||
.type = Common::Input::InputType::Touch,
|
||||
.touch_status = GetStatus(button_callback.button_status.value),
|
||||
|
||||
@@ -54,6 +54,18 @@ struct Message {
|
||||
template <typename T>
|
||||
constexpr Type GetMessageType();
|
||||
|
||||
template <typename T>
|
||||
Message<T> CreateMessage(const u32 magic, const T data, const u32 sender_id) {
|
||||
boost::crc_32_type crc;
|
||||
Header header{
|
||||
magic, PROTOCOL_VERSION, sizeof(T) + sizeof(Type), 0, sender_id, GetMessageType<T>(),
|
||||
};
|
||||
Message<T> message{header, data};
|
||||
crc.process_bytes(&message, sizeof(Message<T>));
|
||||
message.header.crc = crc.checksum();
|
||||
return message;
|
||||
}
|
||||
|
||||
namespace Request {
|
||||
|
||||
enum RegisterFlags : u8 {
|
||||
@@ -101,14 +113,7 @@ static_assert(std::is_trivially_copyable_v<PadData>,
|
||||
*/
|
||||
template <typename T>
|
||||
Message<T> Create(const T data, const u32 client_id = 0) {
|
||||
boost::crc_32_type crc;
|
||||
Header header{
|
||||
CLIENT_MAGIC, PROTOCOL_VERSION, sizeof(T) + sizeof(Type), 0, client_id, GetMessageType<T>(),
|
||||
};
|
||||
Message<T> message{header, data};
|
||||
crc.process_bytes(&message, sizeof(Message<T>));
|
||||
message.header.crc = crc.checksum();
|
||||
return message;
|
||||
return CreateMessage(CLIENT_MAGIC, data, client_id);
|
||||
}
|
||||
} // namespace Request
|
||||
|
||||
|
||||
@@ -10,41 +10,31 @@ namespace InputCommon {
|
||||
|
||||
void InputEngine::PreSetController(const PadIdentifier& identifier) {
|
||||
std::lock_guard lock{mutex};
|
||||
if (!controller_list.contains(identifier)) {
|
||||
controller_list.insert_or_assign(identifier, ControllerData{});
|
||||
}
|
||||
controller_list.try_emplace(identifier);
|
||||
}
|
||||
|
||||
void InputEngine::PreSetButton(const PadIdentifier& identifier, int button) {
|
||||
std::lock_guard lock{mutex};
|
||||
ControllerData& controller = controller_list.at(identifier);
|
||||
if (!controller.buttons.contains(button)) {
|
||||
controller.buttons.insert_or_assign(button, false);
|
||||
}
|
||||
controller.buttons.try_emplace(button, false);
|
||||
}
|
||||
|
||||
void InputEngine::PreSetHatButton(const PadIdentifier& identifier, int button) {
|
||||
std::lock_guard lock{mutex};
|
||||
ControllerData& controller = controller_list.at(identifier);
|
||||
if (!controller.hat_buttons.contains(button)) {
|
||||
controller.hat_buttons.insert_or_assign(button, u8{0});
|
||||
}
|
||||
controller.hat_buttons.try_emplace(button, u8{0});
|
||||
}
|
||||
|
||||
void InputEngine::PreSetAxis(const PadIdentifier& identifier, int axis) {
|
||||
std::lock_guard lock{mutex};
|
||||
ControllerData& controller = controller_list.at(identifier);
|
||||
if (!controller.axes.contains(axis)) {
|
||||
controller.axes.insert_or_assign(axis, 0.0f);
|
||||
}
|
||||
controller.axes.try_emplace(axis, 0.0f);
|
||||
}
|
||||
|
||||
void InputEngine::PreSetMotion(const PadIdentifier& identifier, int motion) {
|
||||
std::lock_guard lock{mutex};
|
||||
ControllerData& controller = controller_list.at(identifier);
|
||||
if (!controller.motions.contains(motion)) {
|
||||
controller.motions.insert_or_assign(motion, BasicMotion{});
|
||||
}
|
||||
controller.motions.try_emplace(motion);
|
||||
}
|
||||
|
||||
void InputEngine::SetButton(const PadIdentifier& identifier, int button, bool value) {
|
||||
@@ -91,7 +81,7 @@ void InputEngine::SetBattery(const PadIdentifier& identifier, BatteryLevel value
|
||||
TriggerOnBatteryChange(identifier, value);
|
||||
}
|
||||
|
||||
void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, BasicMotion value) {
|
||||
void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value) {
|
||||
{
|
||||
std::lock_guard lock{mutex};
|
||||
ControllerData& controller = controller_list.at(identifier);
|
||||
@@ -104,85 +94,93 @@ void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, BasicMo
|
||||
|
||||
bool InputEngine::GetButton(const PadIdentifier& identifier, int button) const {
|
||||
std::lock_guard lock{mutex};
|
||||
if (!controller_list.contains(identifier)) {
|
||||
const auto controller_iter = controller_list.find(identifier);
|
||||
if (controller_iter == controller_list.cend()) {
|
||||
LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
|
||||
identifier.pad, identifier.port);
|
||||
return false;
|
||||
}
|
||||
ControllerData controller = controller_list.at(identifier);
|
||||
if (!controller.buttons.contains(button)) {
|
||||
const ControllerData& controller = controller_iter->second;
|
||||
const auto button_iter = controller.buttons.find(button);
|
||||
if (button_iter == controller.buttons.cend()) {
|
||||
LOG_ERROR(Input, "Invalid button {}", button);
|
||||
return false;
|
||||
}
|
||||
return controller.buttons.at(button);
|
||||
return button_iter->second;
|
||||
}
|
||||
|
||||
bool InputEngine::GetHatButton(const PadIdentifier& identifier, int button, u8 direction) const {
|
||||
std::lock_guard lock{mutex};
|
||||
if (!controller_list.contains(identifier)) {
|
||||
const auto controller_iter = controller_list.find(identifier);
|
||||
if (controller_iter == controller_list.cend()) {
|
||||
LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
|
||||
identifier.pad, identifier.port);
|
||||
return false;
|
||||
}
|
||||
ControllerData controller = controller_list.at(identifier);
|
||||
if (!controller.hat_buttons.contains(button)) {
|
||||
const ControllerData& controller = controller_iter->second;
|
||||
const auto hat_iter = controller.hat_buttons.find(button);
|
||||
if (hat_iter == controller.hat_buttons.cend()) {
|
||||
LOG_ERROR(Input, "Invalid hat button {}", button);
|
||||
return false;
|
||||
}
|
||||
return (controller.hat_buttons.at(button) & direction) != 0;
|
||||
return (hat_iter->second & direction) != 0;
|
||||
}
|
||||
|
||||
f32 InputEngine::GetAxis(const PadIdentifier& identifier, int axis) const {
|
||||
std::lock_guard lock{mutex};
|
||||
if (!controller_list.contains(identifier)) {
|
||||
const auto controller_iter = controller_list.find(identifier);
|
||||
if (controller_iter == controller_list.cend()) {
|
||||
LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
|
||||
identifier.pad, identifier.port);
|
||||
return 0.0f;
|
||||
}
|
||||
ControllerData controller = controller_list.at(identifier);
|
||||
if (!controller.axes.contains(axis)) {
|
||||
const ControllerData& controller = controller_iter->second;
|
||||
const auto axis_iter = controller.axes.find(axis);
|
||||
if (axis_iter == controller.axes.cend()) {
|
||||
LOG_ERROR(Input, "Invalid axis {}", axis);
|
||||
return 0.0f;
|
||||
}
|
||||
return controller.axes.at(axis);
|
||||
return axis_iter->second;
|
||||
}
|
||||
|
||||
BatteryLevel InputEngine::GetBattery(const PadIdentifier& identifier) const {
|
||||
std::lock_guard lock{mutex};
|
||||
if (!controller_list.contains(identifier)) {
|
||||
const auto controller_iter = controller_list.find(identifier);
|
||||
if (controller_iter == controller_list.cend()) {
|
||||
LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
|
||||
identifier.pad, identifier.port);
|
||||
return BatteryLevel::Charging;
|
||||
}
|
||||
ControllerData controller = controller_list.at(identifier);
|
||||
const ControllerData& controller = controller_iter->second;
|
||||
return controller.battery;
|
||||
}
|
||||
|
||||
BasicMotion InputEngine::GetMotion(const PadIdentifier& identifier, int motion) const {
|
||||
std::lock_guard lock{mutex};
|
||||
if (!controller_list.contains(identifier)) {
|
||||
const auto controller_iter = controller_list.find(identifier);
|
||||
if (controller_iter == controller_list.cend()) {
|
||||
LOG_ERROR(Input, "Invalid identifier guid={}, pad={}, port={}", identifier.guid.Format(),
|
||||
identifier.pad, identifier.port);
|
||||
return {};
|
||||
}
|
||||
ControllerData controller = controller_list.at(identifier);
|
||||
const ControllerData& controller = controller_iter->second;
|
||||
return controller.motions.at(motion);
|
||||
}
|
||||
|
||||
void InputEngine::ResetButtonState() {
|
||||
for (std::pair<PadIdentifier, ControllerData> controller : controller_list) {
|
||||
for (std::pair<int, bool> button : controller.second.buttons) {
|
||||
for (const auto& controller : controller_list) {
|
||||
for (const auto& button : controller.second.buttons) {
|
||||
SetButton(controller.first, button.first, false);
|
||||
}
|
||||
for (std::pair<int, bool> button : controller.second.hat_buttons) {
|
||||
for (const auto& button : controller.second.hat_buttons) {
|
||||
SetHatButton(controller.first, button.first, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputEngine::ResetAnalogState() {
|
||||
for (std::pair<PadIdentifier, ControllerData> controller : controller_list) {
|
||||
for (std::pair<int, float> axis : controller.second.axes) {
|
||||
for (const auto& controller : controller_list) {
|
||||
for (const auto& axis : controller.second.axes) {
|
||||
SetAxis(controller.first, axis.first, 0.0);
|
||||
}
|
||||
}
|
||||
@@ -190,7 +188,7 @@ void InputEngine::ResetAnalogState() {
|
||||
|
||||
void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value) {
|
||||
std::lock_guard lock{mutex_callback};
|
||||
for (const std::pair<int, InputIdentifier> poller_pair : callback_list) {
|
||||
for (const auto& poller_pair : callback_list) {
|
||||
const InputIdentifier& poller = poller_pair.second;
|
||||
if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Button, button)) {
|
||||
continue;
|
||||
@@ -218,7 +216,7 @@ void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int but
|
||||
|
||||
void InputEngine::TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value) {
|
||||
std::lock_guard lock{mutex_callback};
|
||||
for (const std::pair<int, InputIdentifier> poller_pair : callback_list) {
|
||||
for (const auto& poller_pair : callback_list) {
|
||||
const InputIdentifier& poller = poller_pair.second;
|
||||
if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::HatButton, button)) {
|
||||
continue;
|
||||
@@ -247,7 +245,7 @@ void InputEngine::TriggerOnHatButtonChange(const PadIdentifier& identifier, int
|
||||
|
||||
void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value) {
|
||||
std::lock_guard lock{mutex_callback};
|
||||
for (const std::pair<int, InputIdentifier> poller_pair : callback_list) {
|
||||
for (const auto& poller_pair : callback_list) {
|
||||
const InputIdentifier& poller = poller_pair.second;
|
||||
if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Analog, axis)) {
|
||||
continue;
|
||||
@@ -274,7 +272,7 @@ void InputEngine::TriggerOnAxisChange(const PadIdentifier& identifier, int axis,
|
||||
void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier,
|
||||
[[maybe_unused]] BatteryLevel value) {
|
||||
std::lock_guard lock{mutex_callback};
|
||||
for (const std::pair<int, InputIdentifier> poller_pair : callback_list) {
|
||||
for (const auto& poller_pair : callback_list) {
|
||||
const InputIdentifier& poller = poller_pair.second;
|
||||
if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Battery, 0)) {
|
||||
continue;
|
||||
@@ -286,9 +284,9 @@ void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier,
|
||||
}
|
||||
|
||||
void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int motion,
|
||||
BasicMotion value) {
|
||||
const BasicMotion& value) {
|
||||
std::lock_guard lock{mutex_callback};
|
||||
for (const std::pair<int, InputIdentifier> poller_pair : callback_list) {
|
||||
for (const auto& poller_pair : callback_list) {
|
||||
const InputIdentifier& poller = poller_pair.second;
|
||||
if (!IsInputIdentifierEqual(poller, identifier, EngineInputType::Motion, motion)) {
|
||||
continue;
|
||||
@@ -342,7 +340,7 @@ const std::string& InputEngine::GetEngineName() const {
|
||||
|
||||
int InputEngine::SetCallback(InputIdentifier input_identifier) {
|
||||
std::lock_guard lock{mutex_callback};
|
||||
callback_list.insert_or_assign(last_callback_key, input_identifier);
|
||||
callback_list.insert_or_assign(last_callback_key, std::move(input_identifier));
|
||||
return last_callback_key++;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,15 +23,15 @@ struct PadIdentifier {
|
||||
friend constexpr bool operator==(const PadIdentifier&, const PadIdentifier&) = default;
|
||||
};
|
||||
|
||||
// Basic motion data containing data from the sensors and a timestamp in microsecons
|
||||
// Basic motion data containing data from the sensors and a timestamp in microseconds
|
||||
struct BasicMotion {
|
||||
float gyro_x;
|
||||
float gyro_y;
|
||||
float gyro_z;
|
||||
float accel_x;
|
||||
float accel_y;
|
||||
float accel_z;
|
||||
u64 delta_timestamp;
|
||||
float gyro_x{};
|
||||
float gyro_y{};
|
||||
float gyro_z{};
|
||||
float accel_x{};
|
||||
float accel_y{};
|
||||
float accel_z{};
|
||||
u64 delta_timestamp{};
|
||||
};
|
||||
|
||||
// Stages of a battery charge
|
||||
@@ -102,9 +102,7 @@ struct InputIdentifier {
|
||||
|
||||
class InputEngine {
|
||||
public:
|
||||
explicit InputEngine(const std::string& input_engine_) : input_engine(input_engine_) {
|
||||
callback_list.clear();
|
||||
}
|
||||
explicit InputEngine(std::string input_engine_) : input_engine{std::move(input_engine_)} {}
|
||||
|
||||
virtual ~InputEngine() = default;
|
||||
|
||||
@@ -116,14 +114,12 @@ public:
|
||||
|
||||
// Sets a led pattern for a controller
|
||||
virtual void SetLeds([[maybe_unused]] const PadIdentifier& identifier,
|
||||
[[maybe_unused]] const Common::Input::LedStatus led_status) {
|
||||
return;
|
||||
}
|
||||
[[maybe_unused]] const Common::Input::LedStatus& led_status) {}
|
||||
|
||||
// Sets rumble to a controller
|
||||
virtual Common::Input::VibrationError SetRumble(
|
||||
[[maybe_unused]] const PadIdentifier& identifier,
|
||||
[[maybe_unused]] const Common::Input::VibrationStatus vibration) {
|
||||
[[maybe_unused]] const Common::Input::VibrationStatus& vibration) {
|
||||
return Common::Input::VibrationError::NotSupported;
|
||||
}
|
||||
|
||||
@@ -140,36 +136,36 @@ public:
|
||||
/// Used for automapping features
|
||||
virtual std::vector<Common::ParamPackage> GetInputDevices() const {
|
||||
return {};
|
||||
};
|
||||
}
|
||||
|
||||
/// Retrieves the button mappings for the given device
|
||||
virtual InputCommon::ButtonMapping GetButtonMappingForDevice(
|
||||
virtual ButtonMapping GetButtonMappingForDevice(
|
||||
[[maybe_unused]] const Common::ParamPackage& params) {
|
||||
return {};
|
||||
};
|
||||
}
|
||||
|
||||
/// Retrieves the analog mappings for the given device
|
||||
virtual InputCommon::AnalogMapping GetAnalogMappingForDevice(
|
||||
virtual AnalogMapping GetAnalogMappingForDevice(
|
||||
[[maybe_unused]] const Common::ParamPackage& params) {
|
||||
return {};
|
||||
};
|
||||
}
|
||||
|
||||
/// Retrieves the motion mappings for the given device
|
||||
virtual InputCommon::MotionMapping GetMotionMappingForDevice(
|
||||
virtual MotionMapping GetMotionMappingForDevice(
|
||||
[[maybe_unused]] const Common::ParamPackage& params) {
|
||||
return {};
|
||||
};
|
||||
}
|
||||
|
||||
/// Retrieves the name of the given input.
|
||||
virtual Common::Input::ButtonNames GetUIName(
|
||||
[[maybe_unused]] const Common::ParamPackage& params) const {
|
||||
return Common::Input::ButtonNames::Engine;
|
||||
};
|
||||
}
|
||||
|
||||
/// Retrieves the index number of the given hat button direction
|
||||
virtual u8 GetHatButtonId([[maybe_unused]] const std::string& direction_name) const {
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
void PreSetController(const PadIdentifier& identifier);
|
||||
void PreSetButton(const PadIdentifier& identifier, int button);
|
||||
@@ -194,7 +190,7 @@ protected:
|
||||
void SetHatButton(const PadIdentifier& identifier, int button, u8 value);
|
||||
void SetAxis(const PadIdentifier& identifier, int axis, f32 value);
|
||||
void SetBattery(const PadIdentifier& identifier, BatteryLevel value);
|
||||
void SetMotion(const PadIdentifier& identifier, int motion, BasicMotion value);
|
||||
void SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value);
|
||||
|
||||
virtual std::string GetHatButtonName([[maybe_unused]] u8 direction_value) const {
|
||||
return "Unknown";
|
||||
@@ -206,14 +202,15 @@ private:
|
||||
std::unordered_map<int, u8> hat_buttons;
|
||||
std::unordered_map<int, float> axes;
|
||||
std::unordered_map<int, BasicMotion> motions;
|
||||
BatteryLevel battery;
|
||||
BatteryLevel battery{};
|
||||
};
|
||||
|
||||
void TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value);
|
||||
void TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value);
|
||||
void TriggerOnAxisChange(const PadIdentifier& identifier, int button, f32 value);
|
||||
void TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value);
|
||||
void TriggerOnBatteryChange(const PadIdentifier& identifier, BatteryLevel value);
|
||||
void TriggerOnMotionChange(const PadIdentifier& identifier, int motion, BasicMotion value);
|
||||
void TriggerOnMotionChange(const PadIdentifier& identifier, int motion,
|
||||
const BasicMotion& value);
|
||||
|
||||
bool IsInputIdentifierEqual(const InputIdentifier& input_identifier,
|
||||
const PadIdentifier& identifier, EngineInputType type,
|
||||
|
||||
@@ -14,8 +14,8 @@ public:
|
||||
MappingFactory();
|
||||
|
||||
/**
|
||||
* Resets all varables to beggin the mapping process
|
||||
* @param "type": type of input desired to be returned
|
||||
* Resets all variables to begin the mapping process
|
||||
* @param type type of input desired to be returned
|
||||
*/
|
||||
void BeginMapping(Polling::InputType type);
|
||||
|
||||
@@ -24,8 +24,8 @@ public:
|
||||
|
||||
/**
|
||||
* Registers mapping input data from the driver
|
||||
* @param "data": An struct containing all the information needed to create a proper
|
||||
* ParamPackage
|
||||
* @param data A struct containing all the information needed to create a proper
|
||||
* ParamPackage
|
||||
*/
|
||||
void RegisterInput(const MappingData& data);
|
||||
|
||||
@@ -34,42 +34,42 @@ public:
|
||||
|
||||
private:
|
||||
/**
|
||||
* If provided data satisfies the requeriments it will push an element to the input_queue
|
||||
* If provided data satisfies the requirements it will push an element to the input_queue
|
||||
* Supported input:
|
||||
* - Button: Creates a basic button ParamPackage
|
||||
* - HatButton: Creates a basic hat button ParamPackage
|
||||
* - Analog: Creates a basic analog ParamPackage
|
||||
* @param "data": An struct containing all the information needed to create a proper
|
||||
* @param data A struct containing all the information needed to create a proper
|
||||
* ParamPackage
|
||||
*/
|
||||
void RegisterButton(const MappingData& data);
|
||||
|
||||
/**
|
||||
* If provided data satisfies the requeriments it will push an element to the input_queue
|
||||
* If provided data satisfies the requirements it will push an element to the input_queue
|
||||
* Supported input:
|
||||
* - Button, HatButton: Pass the data to RegisterButton
|
||||
* - Analog: Stores the first axis and on the second axis creates a basic stick ParamPackage
|
||||
* @param "data": An struct containing all the information needed to create a proper
|
||||
* ParamPackage
|
||||
* @param data A struct containing all the information needed to create a proper
|
||||
* ParamPackage
|
||||
*/
|
||||
void RegisterStick(const MappingData& data);
|
||||
|
||||
/**
|
||||
* If provided data satisfies the requeriments it will push an element to the input_queue
|
||||
* If provided data satisfies the requirements it will push an element to the input_queue
|
||||
* Supported input:
|
||||
* - Button, HatButton: Pass the data to RegisterButton
|
||||
* - Analog: Stores the first two axis and on the third axis creates a basic Motion
|
||||
* ParamPackage
|
||||
* - Motion: Creates a basic Motion ParamPackage
|
||||
* @param "data": An struct containing all the information needed to create a proper
|
||||
* ParamPackage
|
||||
* @param data A struct containing all the information needed to create a proper
|
||||
* ParamPackage
|
||||
*/
|
||||
void RegisterMotion(const MappingData& data);
|
||||
|
||||
/**
|
||||
* Returns true if driver can be mapped
|
||||
* @param "data": An struct containing all the information needed to create a proper
|
||||
* ParamPackage
|
||||
* @param data A struct containing all the information needed to create a proper
|
||||
* ParamPackage
|
||||
*/
|
||||
bool IsDriverValid(const MappingData& data) const;
|
||||
|
||||
|
||||
@@ -12,8 +12,7 @@ namespace InputCommon {
|
||||
|
||||
class DummyInput final : public Common::Input::InputDevice {
|
||||
public:
|
||||
explicit DummyInput() {}
|
||||
~DummyInput() {}
|
||||
explicit DummyInput() = default;
|
||||
};
|
||||
|
||||
class InputFromButton final : public Common::Input::InputDevice {
|
||||
@@ -33,7 +32,7 @@ public:
|
||||
callback_key = input_engine->SetCallback(input_identifier);
|
||||
}
|
||||
|
||||
~InputFromButton() {
|
||||
~InputFromButton() override {
|
||||
input_engine->DeleteCallback(callback_key);
|
||||
}
|
||||
|
||||
@@ -45,7 +44,7 @@ public:
|
||||
};
|
||||
}
|
||||
|
||||
void ForceUpdate() {
|
||||
void ForceUpdate() override {
|
||||
const Common::Input::CallbackStatus status{
|
||||
.type = Common::Input::InputType::Button,
|
||||
.button_status = GetStatus(),
|
||||
@@ -94,7 +93,7 @@ public:
|
||||
callback_key = input_engine->SetCallback(input_identifier);
|
||||
}
|
||||
|
||||
~InputFromHatButton() {
|
||||
~InputFromHatButton() override {
|
||||
input_engine->DeleteCallback(callback_key);
|
||||
}
|
||||
|
||||
@@ -106,7 +105,7 @@ public:
|
||||
};
|
||||
}
|
||||
|
||||
void ForceUpdate() {
|
||||
void ForceUpdate() override {
|
||||
const Common::Input::CallbackStatus status{
|
||||
.type = Common::Input::InputType::Button,
|
||||
.button_status = GetStatus(),
|
||||
@@ -167,7 +166,7 @@ public:
|
||||
callback_key_y = input_engine->SetCallback(y_input_identifier);
|
||||
}
|
||||
|
||||
~InputFromStick() {
|
||||
~InputFromStick() override {
|
||||
input_engine->DeleteCallback(callback_key_x);
|
||||
input_engine->DeleteCallback(callback_key_y);
|
||||
}
|
||||
@@ -190,7 +189,7 @@ public:
|
||||
return status;
|
||||
}
|
||||
|
||||
void ForceUpdate() {
|
||||
void ForceUpdate() override {
|
||||
const Common::Input::CallbackStatus status{
|
||||
.type = Common::Input::InputType::Stick,
|
||||
.stick_status = GetStatus(),
|
||||
@@ -266,7 +265,7 @@ public:
|
||||
callback_key_y = input_engine->SetCallback(y_input_identifier);
|
||||
}
|
||||
|
||||
~InputFromTouch() {
|
||||
~InputFromTouch() override {
|
||||
input_engine->DeleteCallback(callback_key_button);
|
||||
input_engine->DeleteCallback(callback_key_x);
|
||||
input_engine->DeleteCallback(callback_key_y);
|
||||
@@ -352,7 +351,7 @@ public:
|
||||
axis_callback_key = input_engine->SetCallback(axis_input_identifier);
|
||||
}
|
||||
|
||||
~InputFromTrigger() {
|
||||
~InputFromTrigger() override {
|
||||
input_engine->DeleteCallback(callback_key_button);
|
||||
input_engine->DeleteCallback(axis_callback_key);
|
||||
}
|
||||
@@ -419,7 +418,7 @@ public:
|
||||
callback_key = input_engine->SetCallback(input_identifier);
|
||||
}
|
||||
|
||||
~InputFromAnalog() {
|
||||
~InputFromAnalog() override {
|
||||
input_engine->DeleteCallback(callback_key);
|
||||
}
|
||||
|
||||
@@ -466,7 +465,7 @@ public:
|
||||
callback_key = input_engine->SetCallback(input_identifier);
|
||||
}
|
||||
|
||||
~InputFromBattery() {
|
||||
~InputFromBattery() override {
|
||||
input_engine->DeleteCallback(callback_key);
|
||||
}
|
||||
|
||||
@@ -474,7 +473,7 @@ public:
|
||||
return static_cast<Common::Input::BatteryLevel>(input_engine->GetBattery(identifier));
|
||||
}
|
||||
|
||||
void ForceUpdate() {
|
||||
void ForceUpdate() override {
|
||||
const Common::Input::CallbackStatus status{
|
||||
.type = Common::Input::InputType::Battery,
|
||||
.battery_status = GetStatus(),
|
||||
@@ -518,7 +517,7 @@ public:
|
||||
callback_key = input_engine->SetCallback(input_identifier);
|
||||
}
|
||||
|
||||
~InputFromMotion() {
|
||||
~InputFromMotion() override {
|
||||
input_engine->DeleteCallback(callback_key);
|
||||
}
|
||||
|
||||
@@ -593,7 +592,7 @@ public:
|
||||
callback_key_z = input_engine->SetCallback(z_input_identifier);
|
||||
}
|
||||
|
||||
~InputFromAxisMotion() {
|
||||
~InputFromAxisMotion() override {
|
||||
input_engine->DeleteCallback(callback_key_x);
|
||||
input_engine->DeleteCallback(callback_key_y);
|
||||
input_engine->DeleteCallback(callback_key_z);
|
||||
@@ -618,7 +617,7 @@ public:
|
||||
return status;
|
||||
}
|
||||
|
||||
void ForceUpdate() {
|
||||
void ForceUpdate() override {
|
||||
const Common::Input::CallbackStatus status{
|
||||
.type = Common::Input::InputType::Motion,
|
||||
.motion_status = GetStatus(),
|
||||
@@ -668,16 +667,16 @@ public:
|
||||
explicit OutputFromIdentifier(PadIdentifier identifier_, InputEngine* input_engine_)
|
||||
: identifier(identifier_), input_engine(input_engine_) {}
|
||||
|
||||
virtual void SetLED(Common::Input::LedStatus led_status) {
|
||||
void SetLED(const Common::Input::LedStatus& led_status) override {
|
||||
input_engine->SetLeds(identifier, led_status);
|
||||
}
|
||||
|
||||
virtual Common::Input::VibrationError SetVibration(
|
||||
Common::Input::VibrationStatus vibration_status) {
|
||||
Common::Input::VibrationError SetVibration(
|
||||
const Common::Input::VibrationStatus& vibration_status) override {
|
||||
return input_engine->SetRumble(identifier, vibration_status);
|
||||
}
|
||||
|
||||
virtual Common::Input::PollingError SetPollingMode(Common::Input::PollingMode polling_mode) {
|
||||
Common::Input::PollingError SetPollingMode(Common::Input::PollingMode polling_mode) override {
|
||||
return input_engine->SetPollingMode(identifier, polling_mode);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,6 @@ class Factory;
|
||||
|
||||
namespace InputCommon {
|
||||
class InputEngine;
|
||||
/**
|
||||
* An Input factory. It receives input events and forward them to all input devices it created.
|
||||
*/
|
||||
|
||||
class OutputFactory final : public Common::Input::Factory<Common::Input::OutputDevice> {
|
||||
public:
|
||||
@@ -24,10 +21,10 @@ public:
|
||||
/**
|
||||
* Creates an output device from the parameters given.
|
||||
* @param params contains parameters for creating the device:
|
||||
* @param - "guid": text string for identifing controllers
|
||||
* @param - "port": port of the connected device
|
||||
* @param - "pad": slot of the connected controller
|
||||
* @return an unique ouput device with the parameters specified
|
||||
* - "guid" text string for identifying controllers
|
||||
* - "port": port of the connected device
|
||||
* - "pad": slot of the connected controller
|
||||
* @returns a unique output device with the parameters specified
|
||||
*/
|
||||
std::unique_ptr<Common::Input::OutputDevice> Create(
|
||||
const Common::ParamPackage& params) override;
|
||||
@@ -36,6 +33,9 @@ private:
|
||||
std::shared_ptr<InputEngine> input_engine;
|
||||
};
|
||||
|
||||
/**
|
||||
* An Input factory. It receives input events and forward them to all input devices it created.
|
||||
*/
|
||||
class InputFactory final : public Common::Input::Factory<Common::Input::InputDevice> {
|
||||
public:
|
||||
explicit InputFactory(std::shared_ptr<InputEngine> input_engine_);
|
||||
@@ -54,16 +54,16 @@ public:
|
||||
* - battery: Contains "battery"
|
||||
* - output: Contains "output"
|
||||
* @param params contains parameters for creating the device:
|
||||
* @param - "code": the code of the keyboard key to bind with the input
|
||||
* @param - "button": same as "code" but for controller buttons
|
||||
* @param - "hat": similar as "button" but it's a group of hat buttons from SDL
|
||||
* @param - "axis": the axis number of the axis to bind with the input
|
||||
* @param - "motion": the motion number of the motion to bind with the input
|
||||
* @param - "axis_x": same as axis but specifing horizontal direction
|
||||
* @param - "axis_y": same as axis but specifing vertical direction
|
||||
* @param - "axis_z": same as axis but specifing forward direction
|
||||
* @param - "battery": Only used as a placeholder to set the input type
|
||||
* @return an unique input device with the parameters specified
|
||||
* - "code": the code of the keyboard key to bind with the input
|
||||
* - "button": same as "code" but for controller buttons
|
||||
* - "hat": similar as "button" but it's a group of hat buttons from SDL
|
||||
* - "axis": the axis number of the axis to bind with the input
|
||||
* - "motion": the motion number of the motion to bind with the input
|
||||
* - "axis_x": same as axis but specifying horizontal direction
|
||||
* - "axis_y": same as axis but specifying vertical direction
|
||||
* - "axis_z": same as axis but specifying forward direction
|
||||
* - "battery": Only used as a placeholder to set the input type
|
||||
* @returns a unique input device with the parameters specified
|
||||
*/
|
||||
std::unique_ptr<Common::Input::InputDevice> Create(const Common::ParamPackage& params) override;
|
||||
|
||||
@@ -71,14 +71,14 @@ private:
|
||||
/**
|
||||
* Creates a button device from the parameters given.
|
||||
* @param params contains parameters for creating the device:
|
||||
* @param - "code": the code of the keyboard key to bind with the input
|
||||
* @param - "button": same as "code" but for controller buttons
|
||||
* @param - "toggle": press once to enable, press again to disable
|
||||
* @param - "inverted": inverts the output of the button
|
||||
* @param - "guid": text string for identifing controllers
|
||||
* @param - "port": port of the connected device
|
||||
* @param - "pad": slot of the connected controller
|
||||
* @return an unique input device with the parameters specified
|
||||
* - "code": the code of the keyboard key to bind with the input
|
||||
* - "button": same as "code" but for controller buttons
|
||||
* - "toggle": press once to enable, press again to disable
|
||||
* - "inverted": inverts the output of the button
|
||||
* - "guid": text string for identifying controllers
|
||||
* - "port": port of the connected device
|
||||
* - "pad": slot of the connected controller
|
||||
* @returns a unique input device with the parameters specified
|
||||
*/
|
||||
std::unique_ptr<Common::Input::InputDevice> CreateButtonDevice(
|
||||
const Common::ParamPackage& params);
|
||||
@@ -86,14 +86,14 @@ private:
|
||||
/**
|
||||
* Creates a hat button device from the parameters given.
|
||||
* @param params contains parameters for creating the device:
|
||||
* @param - "button": the controller hat id to bind with the input
|
||||
* @param - "direction": the direction id to be detected
|
||||
* @param - "toggle": press once to enable, press again to disable
|
||||
* @param - "inverted": inverts the output of the button
|
||||
* @param - "guid": text string for identifing controllers
|
||||
* @param - "port": port of the connected device
|
||||
* @param - "pad": slot of the connected controller
|
||||
* @return an unique input device with the parameters specified
|
||||
* - "button": the controller hat id to bind with the input
|
||||
* - "direction": the direction id to be detected
|
||||
* - "toggle": press once to enable, press again to disable
|
||||
* - "inverted": inverts the output of the button
|
||||
* - "guid": text string for identifying controllers
|
||||
* - "port": port of the connected device
|
||||
* - "pad": slot of the connected controller
|
||||
* @returns a unique input device with the parameters specified
|
||||
*/
|
||||
std::unique_ptr<Common::Input::InputDevice> CreateHatButtonDevice(
|
||||
const Common::ParamPackage& params);
|
||||
@@ -101,19 +101,19 @@ private:
|
||||
/**
|
||||
* Creates a stick device from the parameters given.
|
||||
* @param params contains parameters for creating the device:
|
||||
* @param - "axis_x": the controller horizontal axis id to bind with the input
|
||||
* @param - "axis_y": the controller vertical axis id to bind with the input
|
||||
* @param - "deadzone": the mimimum required value to be detected
|
||||
* @param - "range": the maximum value required to reach 100%
|
||||
* @param - "threshold": the mimimum required value to considered pressed
|
||||
* @param - "offset_x": the amount of offset in the x axis
|
||||
* @param - "offset_y": the amount of offset in the y axis
|
||||
* @param - "invert_x": inverts the sign of the horizontal axis
|
||||
* @param - "invert_y": inverts the sign of the vertical axis
|
||||
* @param - "guid": text string for identifing controllers
|
||||
* @param - "port": port of the connected device
|
||||
* @param - "pad": slot of the connected controller
|
||||
* @return an unique input device with the parameters specified
|
||||
* - "axis_x": the controller horizontal axis id to bind with the input
|
||||
* - "axis_y": the controller vertical axis id to bind with the input
|
||||
* - "deadzone": the minimum required value to be detected
|
||||
* - "range": the maximum value required to reach 100%
|
||||
* - "threshold": the minimum required value to considered pressed
|
||||
* - "offset_x": the amount of offset in the x axis
|
||||
* - "offset_y": the amount of offset in the y axis
|
||||
* - "invert_x": inverts the sign of the horizontal axis
|
||||
* - "invert_y": inverts the sign of the vertical axis
|
||||
* - "guid": text string for identifying controllers
|
||||
* - "port": port of the connected device
|
||||
* - "pad": slot of the connected controller
|
||||
* @returns a unique input device with the parameters specified
|
||||
*/
|
||||
std::unique_ptr<Common::Input::InputDevice> CreateStickDevice(
|
||||
const Common::ParamPackage& params);
|
||||
@@ -121,16 +121,16 @@ private:
|
||||
/**
|
||||
* Creates an analog device from the parameters given.
|
||||
* @param params contains parameters for creating the device:
|
||||
* @param - "axis": the controller axis id to bind with the input
|
||||
* @param - "deadzone": the mimimum required value to be detected
|
||||
* @param - "range": the maximum value required to reach 100%
|
||||
* @param - "threshold": the mimimum required value to considered pressed
|
||||
* @param - "offset": the amount of offset in the axis
|
||||
* @param - "invert": inverts the sign of the axis
|
||||
* @param - "guid": text string for identifing controllers
|
||||
* @param - "port": port of the connected device
|
||||
* @param - "pad": slot of the connected controller
|
||||
* @return an unique input device with the parameters specified
|
||||
* - "axis": the controller axis id to bind with the input
|
||||
* - "deadzone": the minimum required value to be detected
|
||||
* - "range": the maximum value required to reach 100%
|
||||
* - "threshold": the minimum required value to considered pressed
|
||||
* - "offset": the amount of offset in the axis
|
||||
* - "invert": inverts the sign of the axis
|
||||
* - "guid": text string for identifying controllers
|
||||
* - "port": port of the connected device
|
||||
* - "pad": slot of the connected controller
|
||||
* @returns a unique input device with the parameters specified
|
||||
*/
|
||||
std::unique_ptr<Common::Input::InputDevice> CreateAnalogDevice(
|
||||
const Common::ParamPackage& params);
|
||||
@@ -138,20 +138,20 @@ private:
|
||||
/**
|
||||
* Creates a trigger device from the parameters given.
|
||||
* @param params contains parameters for creating the device:
|
||||
* @param - "button": the controller hat id to bind with the input
|
||||
* @param - "direction": the direction id to be detected
|
||||
* @param - "toggle": press once to enable, press again to disable
|
||||
* @param - "inverted": inverts the output of the button
|
||||
* @param - "axis": the controller axis id to bind with the input
|
||||
* @param - "deadzone": the mimimum required value to be detected
|
||||
* @param - "range": the maximum value required to reach 100%
|
||||
* @param - "threshold": the mimimum required value to considered pressed
|
||||
* @param - "offset": the amount of offset in the axis
|
||||
* @param - "invert": inverts the sign of the axis
|
||||
* @param - "guid": text string for identifing controllers
|
||||
* @param - "port": port of the connected device
|
||||
* @param - "pad": slot of the connected controller
|
||||
* @return an unique input device with the parameters specified
|
||||
* - "button": the controller hat id to bind with the input
|
||||
* - "direction": the direction id to be detected
|
||||
* - "toggle": press once to enable, press again to disable
|
||||
* - "inverted": inverts the output of the button
|
||||
* - "axis": the controller axis id to bind with the input
|
||||
* - "deadzone": the minimum required value to be detected
|
||||
* - "range": the maximum value required to reach 100%
|
||||
* - "threshold": the minimum required value to considered pressed
|
||||
* - "offset": the amount of offset in the axis
|
||||
* - "invert": inverts the sign of the axis
|
||||
* - "guid": text string for identifying controllers
|
||||
* - "port": port of the connected device
|
||||
* - "pad": slot of the connected controller
|
||||
* @returns a unique input device with the parameters specified
|
||||
*/
|
||||
std::unique_ptr<Common::Input::InputDevice> CreateTriggerDevice(
|
||||
const Common::ParamPackage& params);
|
||||
@@ -159,23 +159,23 @@ private:
|
||||
/**
|
||||
* Creates a touch device from the parameters given.
|
||||
* @param params contains parameters for creating the device:
|
||||
* @param - "button": the controller hat id to bind with the input
|
||||
* @param - "direction": the direction id to be detected
|
||||
* @param - "toggle": press once to enable, press again to disable
|
||||
* @param - "inverted": inverts the output of the button
|
||||
* @param - "axis_x": the controller horizontal axis id to bind with the input
|
||||
* @param - "axis_y": the controller vertical axis id to bind with the input
|
||||
* @param - "deadzone": the mimimum required value to be detected
|
||||
* @param - "range": the maximum value required to reach 100%
|
||||
* @param - "threshold": the mimimum required value to considered pressed
|
||||
* @param - "offset_x": the amount of offset in the x axis
|
||||
* @param - "offset_y": the amount of offset in the y axis
|
||||
* @param - "invert_x": inverts the sign of the horizontal axis
|
||||
* @param - "invert_y": inverts the sign of the vertical axis
|
||||
* @param - "guid": text string for identifing controllers
|
||||
* @param - "port": port of the connected device
|
||||
* @param - "pad": slot of the connected controller
|
||||
* @return an unique input device with the parameters specified
|
||||
* - "button": the controller hat id to bind with the input
|
||||
* - "direction": the direction id to be detected
|
||||
* - "toggle": press once to enable, press again to disable
|
||||
* - "inverted": inverts the output of the button
|
||||
* - "axis_x": the controller horizontal axis id to bind with the input
|
||||
* - "axis_y": the controller vertical axis id to bind with the input
|
||||
* - "deadzone": the minimum required value to be detected
|
||||
* - "range": the maximum value required to reach 100%
|
||||
* - "threshold": the minimum required value to considered pressed
|
||||
* - "offset_x": the amount of offset in the x axis
|
||||
* - "offset_y": the amount of offset in the y axis
|
||||
* - "invert_x": inverts the sign of the horizontal axis
|
||||
* - "invert_y": inverts the sign of the vertical axis
|
||||
* - "guid": text string for identifying controllers
|
||||
* - "port": port of the connected device
|
||||
* - "pad": slot of the connected controller
|
||||
* @returns a unique input device with the parameters specified
|
||||
*/
|
||||
std::unique_ptr<Common::Input::InputDevice> CreateTouchDevice(
|
||||
const Common::ParamPackage& params);
|
||||
@@ -183,10 +183,10 @@ private:
|
||||
/**
|
||||
* Creates a battery device from the parameters given.
|
||||
* @param params contains parameters for creating the device:
|
||||
* @param - "guid": text string for identifing controllers
|
||||
* @param - "port": port of the connected device
|
||||
* @param - "pad": slot of the connected controller
|
||||
* @return an unique input device with the parameters specified
|
||||
* - "guid": text string for identifying controllers
|
||||
* - "port": port of the connected device
|
||||
* - "pad": slot of the connected controller
|
||||
* @returns a unique input device with the parameters specified
|
||||
*/
|
||||
std::unique_ptr<Common::Input::InputDevice> CreateBatteryDevice(
|
||||
const Common::ParamPackage& params);
|
||||
@@ -194,21 +194,21 @@ private:
|
||||
/**
|
||||
* Creates a motion device from the parameters given.
|
||||
* @param params contains parameters for creating the device:
|
||||
* @param - "axis_x": the controller horizontal axis id to bind with the input
|
||||
* @param - "axis_y": the controller vertical axis id to bind with the input
|
||||
* @param - "axis_z": the controller fordward axis id to bind with the input
|
||||
* @param - "deadzone": the mimimum required value to be detected
|
||||
* @param - "range": the maximum value required to reach 100%
|
||||
* @param - "offset_x": the amount of offset in the x axis
|
||||
* @param - "offset_y": the amount of offset in the y axis
|
||||
* @param - "offset_z": the amount of offset in the z axis
|
||||
* @param - "invert_x": inverts the sign of the horizontal axis
|
||||
* @param - "invert_y": inverts the sign of the vertical axis
|
||||
* @param - "invert_z": inverts the sign of the fordward axis
|
||||
* @param - "guid": text string for identifing controllers
|
||||
* @param - "port": port of the connected device
|
||||
* @param - "pad": slot of the connected controller
|
||||
* @return an unique input device with the parameters specified
|
||||
* - "axis_x": the controller horizontal axis id to bind with the input
|
||||
* - "axis_y": the controller vertical axis id to bind with the input
|
||||
* - "axis_z": the controller forward axis id to bind with the input
|
||||
* - "deadzone": the minimum required value to be detected
|
||||
* - "range": the maximum value required to reach 100%
|
||||
* - "offset_x": the amount of offset in the x axis
|
||||
* - "offset_y": the amount of offset in the y axis
|
||||
* - "offset_z": the amount of offset in the z axis
|
||||
* - "invert_x": inverts the sign of the horizontal axis
|
||||
* - "invert_y": inverts the sign of the vertical axis
|
||||
* - "invert_z": inverts the sign of the forward axis
|
||||
* - "guid": text string for identifying controllers
|
||||
* - "port": port of the connected device
|
||||
* - "pad": slot of the connected controller
|
||||
* @returns a unique input device with the parameters specified
|
||||
*/
|
||||
std::unique_ptr<Common::Input::InputDevice> CreateMotionDevice(Common::ParamPackage params);
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, Scal
|
||||
}
|
||||
switch (attr) {
|
||||
case IR::Attribute::PrimitiveId:
|
||||
ctx.Add("MOV.S {}.x,primitive.id;", inst);
|
||||
ctx.Add("MOV.F {}.x,primitive.id;", inst);
|
||||
break;
|
||||
case IR::Attribute::PositionX:
|
||||
case IR::Attribute::PositionY:
|
||||
@@ -113,13 +113,13 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, Scal
|
||||
ctx.Add("MOV.F {}.x,vertex.tesscoord.{};", inst, swizzle);
|
||||
break;
|
||||
case IR::Attribute::InstanceId:
|
||||
ctx.Add("MOV.S {}.x,{}.instance;", inst, ctx.attrib_name);
|
||||
ctx.Add("MOV.F {}.x,{}.instance;", inst, ctx.attrib_name);
|
||||
break;
|
||||
case IR::Attribute::VertexId:
|
||||
ctx.Add("MOV.S {}.x,{}.id;", inst, ctx.attrib_name);
|
||||
ctx.Add("MOV.F {}.x,{}.id;", inst, ctx.attrib_name);
|
||||
break;
|
||||
case IR::Attribute::FrontFace:
|
||||
ctx.Add("CMP.S {}.x,{}.facing.x,0,-1;", inst, ctx.attrib_name);
|
||||
ctx.Add("CMP.F {}.x,{}.facing.x,0,-1;", inst, ctx.attrib_name);
|
||||
break;
|
||||
default:
|
||||
throw NotImplementedException("Get attribute {}", attr);
|
||||
|
||||
@@ -176,7 +176,7 @@ void EmitCode(EmitContext& ctx, const IR::Program& program) {
|
||||
}
|
||||
|
||||
std::string GlslVersionSpecifier(const EmitContext& ctx) {
|
||||
if (ctx.uses_y_direction || ctx.info.stores.Legacy() || ctx.info.loads.Legacy()) {
|
||||
if (ctx.uses_y_direction) {
|
||||
return " compatibility";
|
||||
}
|
||||
return "";
|
||||
|
||||
@@ -98,10 +98,6 @@ void GetCbuf16(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding, const
|
||||
GetCbuf(ctx, ret, binding, offset, 16, cast, bit_offset);
|
||||
}
|
||||
}
|
||||
|
||||
u32 TexCoordIndex(IR::Attribute attr) {
|
||||
return (static_cast<u32>(attr) - static_cast<u32>(IR::Attribute::FixedFncTexture0S)) / 4;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void EmitGetCbufU8(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding,
|
||||
@@ -190,18 +186,6 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
|
||||
ctx.AddF32("{}=in_attr{}{}.{};", inst, index, InputVertexIndex(ctx, vertex), swizzle);
|
||||
return;
|
||||
}
|
||||
// GLSL only exposes 8 legacy texcoords
|
||||
if (attr >= IR::Attribute::FixedFncTexture8S && attr <= IR::Attribute::FixedFncTexture9Q) {
|
||||
LOG_WARNING(Shader_GLSL, "GLSL does not allow access to gl_TexCoord[{}]",
|
||||
TexCoordIndex(attr));
|
||||
ctx.AddF32("{}=0.f;", inst);
|
||||
return;
|
||||
}
|
||||
if (attr >= IR::Attribute::FixedFncTexture0S && attr <= IR::Attribute::FixedFncTexture7Q) {
|
||||
const u32 index{TexCoordIndex(attr)};
|
||||
ctx.AddF32("{}=gl_TexCoord[{}].{};", inst, index, swizzle);
|
||||
return;
|
||||
}
|
||||
switch (attr) {
|
||||
case IR::Attribute::PrimitiveId:
|
||||
ctx.AddF32("{}=itof(gl_PrimitiveID);", inst);
|
||||
@@ -215,16 +199,6 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
|
||||
ctx.AddF32("{}={}{}.{};", inst, input_decorator, ctx.position_name, swizzle);
|
||||
break;
|
||||
}
|
||||
case IR::Attribute::ColorFrontDiffuseR:
|
||||
case IR::Attribute::ColorFrontDiffuseG:
|
||||
case IR::Attribute::ColorFrontDiffuseB:
|
||||
case IR::Attribute::ColorFrontDiffuseA:
|
||||
if (ctx.stage == Stage::Fragment) {
|
||||
ctx.AddF32("{}=gl_Color.{};", inst, swizzle);
|
||||
} else {
|
||||
ctx.AddF32("{}=gl_FrontColor.{};", inst, swizzle);
|
||||
}
|
||||
break;
|
||||
case IR::Attribute::PointSpriteS:
|
||||
case IR::Attribute::PointSpriteT:
|
||||
ctx.AddF32("{}=gl_PointCoord.{};", inst, swizzle);
|
||||
@@ -264,17 +238,6 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view val
|
||||
}
|
||||
const u32 element{static_cast<u32>(attr) % 4};
|
||||
const char swizzle{"xyzw"[element]};
|
||||
// GLSL only exposes 8 legacy texcoords
|
||||
if (attr >= IR::Attribute::FixedFncTexture8S && attr <= IR::Attribute::FixedFncTexture9Q) {
|
||||
LOG_WARNING(Shader_GLSL, "GLSL does not allow access to gl_TexCoord[{}]",
|
||||
TexCoordIndex(attr));
|
||||
return;
|
||||
}
|
||||
if (attr >= IR::Attribute::FixedFncTexture0S && attr <= IR::Attribute::FixedFncTexture7Q) {
|
||||
const u32 index{TexCoordIndex(attr)};
|
||||
ctx.Add("gl_TexCoord[{}].{}={};", index, swizzle, value);
|
||||
return;
|
||||
}
|
||||
switch (attr) {
|
||||
case IR::Attribute::Layer:
|
||||
if (ctx.stage != Stage::Geometry &&
|
||||
@@ -312,33 +275,6 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view val
|
||||
case IR::Attribute::PositionW:
|
||||
ctx.Add("gl_Position.{}={};", swizzle, value);
|
||||
break;
|
||||
case IR::Attribute::ColorFrontDiffuseR:
|
||||
case IR::Attribute::ColorFrontDiffuseG:
|
||||
case IR::Attribute::ColorFrontDiffuseB:
|
||||
case IR::Attribute::ColorFrontDiffuseA:
|
||||
ctx.Add("gl_FrontColor.{}={};", swizzle, value);
|
||||
break;
|
||||
case IR::Attribute::ColorFrontSpecularR:
|
||||
case IR::Attribute::ColorFrontSpecularG:
|
||||
case IR::Attribute::ColorFrontSpecularB:
|
||||
case IR::Attribute::ColorFrontSpecularA:
|
||||
ctx.Add("gl_FrontSecondaryColor.{}={};", swizzle, value);
|
||||
break;
|
||||
case IR::Attribute::ColorBackDiffuseR:
|
||||
case IR::Attribute::ColorBackDiffuseG:
|
||||
case IR::Attribute::ColorBackDiffuseB:
|
||||
case IR::Attribute::ColorBackDiffuseA:
|
||||
ctx.Add("gl_BackColor.{}={};", swizzle, value);
|
||||
break;
|
||||
case IR::Attribute::ColorBackSpecularR:
|
||||
case IR::Attribute::ColorBackSpecularG:
|
||||
case IR::Attribute::ColorBackSpecularB:
|
||||
case IR::Attribute::ColorBackSpecularA:
|
||||
ctx.Add("gl_BackSecondaryColor.{}={};", swizzle, value);
|
||||
break;
|
||||
case IR::Attribute::FogCoordinate:
|
||||
ctx.Add("gl_FogFragCoord={};", value);
|
||||
break;
|
||||
case IR::Attribute::ClipDistance0:
|
||||
case IR::Attribute::ClipDistance1:
|
||||
case IR::Attribute::ClipDistance2:
|
||||
|
||||
@@ -211,27 +211,6 @@ std::string_view OutputPrimitive(OutputTopology topology) {
|
||||
throw InvalidArgument("Invalid output topology {}", topology);
|
||||
}
|
||||
|
||||
void SetupLegacyOutPerVertex(EmitContext& ctx, std::string& header) {
|
||||
if (!ctx.info.stores.Legacy()) {
|
||||
return;
|
||||
}
|
||||
if (ctx.info.stores.FixedFunctionTexture()) {
|
||||
header += "vec4 gl_TexCoord[8];";
|
||||
}
|
||||
if (ctx.info.stores.AnyComponent(IR::Attribute::ColorFrontDiffuseR)) {
|
||||
header += "vec4 gl_FrontColor;";
|
||||
}
|
||||
if (ctx.info.stores.AnyComponent(IR::Attribute::ColorFrontSpecularR)) {
|
||||
header += "vec4 gl_FrontSecondaryColor;";
|
||||
}
|
||||
if (ctx.info.stores.AnyComponent(IR::Attribute::ColorBackDiffuseR)) {
|
||||
header += "vec4 gl_BackColor;";
|
||||
}
|
||||
if (ctx.info.stores.AnyComponent(IR::Attribute::ColorBackSpecularR)) {
|
||||
header += "vec4 gl_BackSecondaryColor;";
|
||||
}
|
||||
}
|
||||
|
||||
void SetupOutPerVertex(EmitContext& ctx, std::string& header) {
|
||||
if (!StoresPerVertexAttributes(ctx.stage)) {
|
||||
return;
|
||||
@@ -250,7 +229,6 @@ void SetupOutPerVertex(EmitContext& ctx, std::string& header) {
|
||||
ctx.profile.support_viewport_index_layer_non_geometry && ctx.stage != Stage::Geometry) {
|
||||
header += "int gl_ViewportIndex;";
|
||||
}
|
||||
SetupLegacyOutPerVertex(ctx, header);
|
||||
header += "};";
|
||||
if (ctx.info.stores[IR::Attribute::ViewportIndex] && ctx.stage == Stage::Geometry) {
|
||||
header += "out int gl_ViewportIndex;";
|
||||
@@ -282,21 +260,6 @@ void SetupInPerVertex(EmitContext& ctx, std::string& header) {
|
||||
}
|
||||
header += "}gl_in[gl_MaxPatchVertices];";
|
||||
}
|
||||
|
||||
void SetupLegacyInPerFragment(EmitContext& ctx, std::string& header) {
|
||||
if (!ctx.info.loads.Legacy()) {
|
||||
return;
|
||||
}
|
||||
header += "in gl_PerFragment{";
|
||||
if (ctx.info.loads.FixedFunctionTexture()) {
|
||||
header += "vec4 gl_TexCoord[8];";
|
||||
}
|
||||
if (ctx.info.loads.AnyComponent(IR::Attribute::ColorFrontDiffuseR)) {
|
||||
header += "vec4 gl_Color;";
|
||||
}
|
||||
header += "};";
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_,
|
||||
@@ -361,7 +324,6 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
|
||||
}
|
||||
SetupOutPerVertex(*this, header);
|
||||
SetupInPerVertex(*this, header);
|
||||
SetupLegacyInPerFragment(*this, header);
|
||||
|
||||
for (size_t index = 0; index < IR::NUM_GENERICS; ++index) {
|
||||
if (!info.loads.Generic(index) || !runtime_info.previous_stage_stores.Generic(index)) {
|
||||
|
||||
@@ -30,11 +30,20 @@ struct FuncTraits<ReturnType_ (*)(Args...)> {
|
||||
using ArgType = std::tuple_element_t<I, std::tuple<Args...>>;
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4702) // Ignore unreachable code warning
|
||||
#endif
|
||||
|
||||
template <auto func, typename... Args>
|
||||
void SetDefinition(EmitContext& ctx, IR::Inst* inst, Args... args) {
|
||||
inst->SetDefinition<Id>(func(ctx, std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
template <typename ArgType>
|
||||
ArgType Arg(EmitContext& ctx, const IR::Value& arg) {
|
||||
if constexpr (std::is_same_v<ArgType, Id>) {
|
||||
|
||||
@@ -44,14 +44,6 @@ Id AttrPointer(EmitContext& ctx, Id pointer_type, Id vertex, Id base, Args&&...
|
||||
}
|
||||
}
|
||||
|
||||
bool IsLegacyAttribute(IR::Attribute attribute) {
|
||||
return (attribute >= IR::Attribute::ColorFrontDiffuseR &&
|
||||
attribute <= IR::Attribute::ColorBackSpecularA) ||
|
||||
attribute == IR::Attribute::FogCoordinate ||
|
||||
(attribute >= IR::Attribute::FixedFncTexture0S &&
|
||||
attribute <= IR::Attribute::FixedFncTexture9Q);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
Id OutputAccessChain(EmitContext& ctx, Id result_type, Id base, Args&&... args) {
|
||||
if (ctx.stage == Stage::TessellationControl) {
|
||||
@@ -83,17 +75,6 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
|
||||
return OutputAccessChain(ctx, ctx.output_f32, info.id, index_id);
|
||||
}
|
||||
}
|
||||
if (IsLegacyAttribute(attr)) {
|
||||
if (attr == IR::Attribute::FogCoordinate) {
|
||||
return OutputAccessChain(ctx, ctx.output_f32, ctx.OutputLegacyAttribute(attr),
|
||||
ctx.Const(0u));
|
||||
} else {
|
||||
const u32 element{static_cast<u32>(attr) % 4};
|
||||
const Id element_id{ctx.Const(element)};
|
||||
return OutputAccessChain(ctx, ctx.output_f32, ctx.OutputLegacyAttribute(attr),
|
||||
element_id);
|
||||
}
|
||||
}
|
||||
switch (attr) {
|
||||
case IR::Attribute::PointSize:
|
||||
return ctx.output_point_size;
|
||||
@@ -327,18 +308,6 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
|
||||
const Id value{ctx.OpLoad(type->id, pointer)};
|
||||
return type->needs_cast ? ctx.OpBitcast(ctx.F32[1], value) : value;
|
||||
}
|
||||
if (IsLegacyAttribute(attr)) {
|
||||
if (attr == IR::Attribute::FogCoordinate) {
|
||||
const Id attr_ptr{AttrPointer(ctx, ctx.input_f32, vertex,
|
||||
ctx.InputLegacyAttribute(attr), ctx.Const(0u))};
|
||||
return ctx.OpLoad(ctx.F32[1], attr_ptr);
|
||||
} else {
|
||||
const Id element_id{ctx.Const(element)};
|
||||
const Id attr_ptr{AttrPointer(ctx, ctx.input_f32, vertex,
|
||||
ctx.InputLegacyAttribute(attr), element_id)};
|
||||
return ctx.OpLoad(ctx.F32[1], attr_ptr);
|
||||
}
|
||||
}
|
||||
switch (attr) {
|
||||
case IR::Attribute::PrimitiveId:
|
||||
return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.primitive_id));
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
|
||||
namespace Shader::Backend::SPIRV {
|
||||
namespace {
|
||||
constexpr size_t NUM_FIXEDFNCTEXTURE = 10;
|
||||
|
||||
enum class Operation {
|
||||
Increment,
|
||||
Decrement,
|
||||
@@ -432,34 +430,6 @@ Id DescType(EmitContext& ctx, Id sampled_type, Id pointer_type, u32 count) {
|
||||
return pointer_type;
|
||||
}
|
||||
}
|
||||
|
||||
size_t FindAndSetNextUnusedLocation(std::bitset<IR::NUM_GENERICS>& used_locations,
|
||||
size_t& start_offset) {
|
||||
for (size_t location = start_offset; location < used_locations.size(); ++location) {
|
||||
if (!used_locations.test(location)) {
|
||||
start_offset = location;
|
||||
used_locations.set(location);
|
||||
return location;
|
||||
}
|
||||
}
|
||||
throw RuntimeError("Unable to get an unused location for legacy attribute");
|
||||
}
|
||||
|
||||
Id DefineLegacyInput(EmitContext& ctx, std::bitset<IR::NUM_GENERICS>& used_locations,
|
||||
size_t& start_offset) {
|
||||
const Id id{DefineInput(ctx, ctx.F32[4], true)};
|
||||
const size_t location = FindAndSetNextUnusedLocation(used_locations, start_offset);
|
||||
ctx.Decorate(id, spv::Decoration::Location, location);
|
||||
return id;
|
||||
}
|
||||
|
||||
Id DefineLegacyOutput(EmitContext& ctx, std::bitset<IR::NUM_GENERICS>& used_locations,
|
||||
size_t& start_offset, std::optional<u32> invocations) {
|
||||
const Id id{DefineOutput(ctx, ctx.F32[4], invocations)};
|
||||
const size_t location = FindAndSetNextUnusedLocation(used_locations, start_offset);
|
||||
ctx.Decorate(id, spv::Decoration::Location, location);
|
||||
return id;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name) {
|
||||
@@ -543,64 +513,6 @@ Id EmitContext::BitOffset16(const IR::Value& offset) {
|
||||
return OpBitwiseAnd(U32[1], OpShiftLeftLogical(U32[1], Def(offset), Const(3u)), Const(16u));
|
||||
}
|
||||
|
||||
Id EmitContext::InputLegacyAttribute(IR::Attribute attribute) {
|
||||
if (attribute >= IR::Attribute::ColorFrontDiffuseR &&
|
||||
attribute <= IR::Attribute::ColorFrontDiffuseA) {
|
||||
return input_front_color;
|
||||
}
|
||||
if (attribute >= IR::Attribute::ColorFrontSpecularR &&
|
||||
attribute <= IR::Attribute::ColorFrontSpecularA) {
|
||||
return input_front_secondary_color;
|
||||
}
|
||||
if (attribute >= IR::Attribute::ColorBackDiffuseR &&
|
||||
attribute <= IR::Attribute::ColorBackDiffuseA) {
|
||||
return input_back_color;
|
||||
}
|
||||
if (attribute >= IR::Attribute::ColorBackSpecularR &&
|
||||
attribute <= IR::Attribute::ColorBackSpecularA) {
|
||||
return input_back_secondary_color;
|
||||
}
|
||||
if (attribute == IR::Attribute::FogCoordinate) {
|
||||
return input_fog_frag_coord;
|
||||
}
|
||||
if (attribute >= IR::Attribute::FixedFncTexture0S &&
|
||||
attribute <= IR::Attribute::FixedFncTexture9Q) {
|
||||
u32 index =
|
||||
(static_cast<u32>(attribute) - static_cast<u32>(IR::Attribute::FixedFncTexture0S)) / 4;
|
||||
return input_fixed_fnc_textures[index];
|
||||
}
|
||||
throw InvalidArgument("Attribute is not legacy attribute {}", attribute);
|
||||
}
|
||||
|
||||
Id EmitContext::OutputLegacyAttribute(IR::Attribute attribute) {
|
||||
if (attribute >= IR::Attribute::ColorFrontDiffuseR &&
|
||||
attribute <= IR::Attribute::ColorFrontDiffuseA) {
|
||||
return output_front_color;
|
||||
}
|
||||
if (attribute >= IR::Attribute::ColorFrontSpecularR &&
|
||||
attribute <= IR::Attribute::ColorFrontSpecularA) {
|
||||
return output_front_secondary_color;
|
||||
}
|
||||
if (attribute >= IR::Attribute::ColorBackDiffuseR &&
|
||||
attribute <= IR::Attribute::ColorBackDiffuseA) {
|
||||
return output_back_color;
|
||||
}
|
||||
if (attribute >= IR::Attribute::ColorBackSpecularR &&
|
||||
attribute <= IR::Attribute::ColorBackSpecularA) {
|
||||
return output_back_secondary_color;
|
||||
}
|
||||
if (attribute == IR::Attribute::FogCoordinate) {
|
||||
return output_fog_frag_coord;
|
||||
}
|
||||
if (attribute >= IR::Attribute::FixedFncTexture0S &&
|
||||
attribute <= IR::Attribute::FixedFncTexture9Q) {
|
||||
u32 index =
|
||||
(static_cast<u32>(attribute) - static_cast<u32>(IR::Attribute::FixedFncTexture0S)) / 4;
|
||||
return output_fixed_fnc_textures[index];
|
||||
}
|
||||
throw InvalidArgument("Attribute is not legacy attribute {}", attribute);
|
||||
}
|
||||
|
||||
void EmitContext::DefineCommonTypes(const Info& info) {
|
||||
void_id = TypeVoid();
|
||||
|
||||
@@ -1389,7 +1301,6 @@ void EmitContext::DefineInputs(const IR::Program& program) {
|
||||
loads[IR::Attribute::TessellationEvaluationPointV]) {
|
||||
tess_coord = DefineInput(*this, F32[3], false, spv::BuiltIn::TessCoord);
|
||||
}
|
||||
std::bitset<IR::NUM_GENERICS> used_locations{};
|
||||
for (size_t index = 0; index < IR::NUM_GENERICS; ++index) {
|
||||
const AttributeType input_type{runtime_info.generic_input_types[index]};
|
||||
if (!runtime_info.previous_stage_stores.Generic(index)) {
|
||||
@@ -1401,7 +1312,6 @@ void EmitContext::DefineInputs(const IR::Program& program) {
|
||||
if (input_type == AttributeType::Disabled) {
|
||||
continue;
|
||||
}
|
||||
used_locations.set(index);
|
||||
const Id type{GetAttributeType(*this, input_type)};
|
||||
const Id id{DefineInput(*this, type, true)};
|
||||
Decorate(id, spv::Decoration::Location, static_cast<u32>(index));
|
||||
@@ -1427,30 +1337,6 @@ void EmitContext::DefineInputs(const IR::Program& program) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
size_t previous_unused_location = 0;
|
||||
if (loads.AnyComponent(IR::Attribute::ColorFrontDiffuseR)) {
|
||||
input_front_color = DefineLegacyInput(*this, used_locations, previous_unused_location);
|
||||
}
|
||||
if (loads.AnyComponent(IR::Attribute::ColorFrontSpecularR)) {
|
||||
input_front_secondary_color =
|
||||
DefineLegacyInput(*this, used_locations, previous_unused_location);
|
||||
}
|
||||
if (loads.AnyComponent(IR::Attribute::ColorBackDiffuseR)) {
|
||||
input_back_color = DefineLegacyInput(*this, used_locations, previous_unused_location);
|
||||
}
|
||||
if (loads.AnyComponent(IR::Attribute::ColorBackSpecularR)) {
|
||||
input_back_secondary_color =
|
||||
DefineLegacyInput(*this, used_locations, previous_unused_location);
|
||||
}
|
||||
if (loads.AnyComponent(IR::Attribute::FogCoordinate)) {
|
||||
input_fog_frag_coord = DefineLegacyInput(*this, used_locations, previous_unused_location);
|
||||
}
|
||||
for (size_t index = 0; index < NUM_FIXEDFNCTEXTURE; ++index) {
|
||||
if (loads.AnyComponent(IR::Attribute::FixedFncTexture0S + index * 4)) {
|
||||
input_fixed_fnc_textures[index] =
|
||||
DefineLegacyInput(*this, used_locations, previous_unused_location);
|
||||
}
|
||||
}
|
||||
if (stage == Stage::TessellationEval) {
|
||||
for (size_t index = 0; index < info.uses_patches.size(); ++index) {
|
||||
if (!info.uses_patches[index]) {
|
||||
@@ -1501,38 +1387,9 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
|
||||
viewport_mask = DefineOutput(*this, TypeArray(U32[1], Const(1u)), std::nullopt,
|
||||
spv::BuiltIn::ViewportMaskNV);
|
||||
}
|
||||
std::bitset<IR::NUM_GENERICS> used_locations{};
|
||||
for (size_t index = 0; index < IR::NUM_GENERICS; ++index) {
|
||||
if (info.stores.Generic(index)) {
|
||||
DefineGenericOutput(*this, index, invocations);
|
||||
used_locations.set(index);
|
||||
}
|
||||
}
|
||||
size_t previous_unused_location = 0;
|
||||
if (info.stores.AnyComponent(IR::Attribute::ColorFrontDiffuseR)) {
|
||||
output_front_color =
|
||||
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
|
||||
}
|
||||
if (info.stores.AnyComponent(IR::Attribute::ColorFrontSpecularR)) {
|
||||
output_front_secondary_color =
|
||||
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
|
||||
}
|
||||
if (info.stores.AnyComponent(IR::Attribute::ColorBackDiffuseR)) {
|
||||
output_back_color =
|
||||
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
|
||||
}
|
||||
if (info.stores.AnyComponent(IR::Attribute::ColorBackSpecularR)) {
|
||||
output_back_secondary_color =
|
||||
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
|
||||
}
|
||||
if (info.stores.AnyComponent(IR::Attribute::FogCoordinate)) {
|
||||
output_fog_frag_coord =
|
||||
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
|
||||
}
|
||||
for (size_t index = 0; index < NUM_FIXEDFNCTEXTURE; ++index) {
|
||||
if (info.stores.AnyComponent(IR::Attribute::FixedFncTexture0S + index * 4)) {
|
||||
output_fixed_fnc_textures[index] =
|
||||
DefineLegacyOutput(*this, used_locations, previous_unused_location, invocations);
|
||||
}
|
||||
}
|
||||
switch (stage) {
|
||||
|
||||
@@ -113,9 +113,6 @@ public:
|
||||
[[nodiscard]] Id BitOffset8(const IR::Value& offset);
|
||||
[[nodiscard]] Id BitOffset16(const IR::Value& offset);
|
||||
|
||||
Id InputLegacyAttribute(IR::Attribute attribute);
|
||||
Id OutputLegacyAttribute(IR::Attribute attribute);
|
||||
|
||||
Id Const(u32 value) {
|
||||
return Constant(U32[1], value);
|
||||
}
|
||||
@@ -281,22 +278,10 @@ public:
|
||||
Id write_global_func_u32x4{};
|
||||
|
||||
Id input_position{};
|
||||
Id input_front_color{};
|
||||
Id input_front_secondary_color{};
|
||||
Id input_back_color{};
|
||||
Id input_back_secondary_color{};
|
||||
Id input_fog_frag_coord{};
|
||||
std::array<Id, 10> input_fixed_fnc_textures{};
|
||||
std::array<Id, 32> input_generics{};
|
||||
|
||||
Id output_point_size{};
|
||||
Id output_position{};
|
||||
Id output_front_color{};
|
||||
Id output_front_secondary_color{};
|
||||
Id output_back_color{};
|
||||
Id output_back_secondary_color{};
|
||||
Id output_fog_frag_coord{};
|
||||
std::array<Id, 10> output_fixed_fnc_textures{};
|
||||
std::array<std::array<GenericElementInfo, 4>, 32> output_generics{};
|
||||
|
||||
Id output_tess_level_outer{};
|
||||
|
||||
@@ -224,6 +224,8 @@ enum class Attribute : u64 {
|
||||
|
||||
constexpr size_t NUM_GENERICS = 32;
|
||||
|
||||
constexpr size_t NUM_FIXEDFNCTEXTURE = 10;
|
||||
|
||||
[[nodiscard]] bool IsGeneric(Attribute attribute) noexcept;
|
||||
|
||||
[[nodiscard]] u32 GenericAttributeIndex(Attribute attribute);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "shader_recompiler/exception.h"
|
||||
@@ -127,6 +128,42 @@ void AddNVNStorageBuffers(IR::Program& program) {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool IsLegacyAttribute(IR::Attribute attribute) {
|
||||
return (attribute >= IR::Attribute::ColorFrontDiffuseR &&
|
||||
attribute <= IR::Attribute::ColorBackSpecularA) ||
|
||||
attribute == IR::Attribute::FogCoordinate ||
|
||||
(attribute >= IR::Attribute::FixedFncTexture0S &&
|
||||
attribute <= IR::Attribute::FixedFncTexture9Q);
|
||||
}
|
||||
|
||||
std::map<IR::Attribute, IR::Attribute> GenerateLegacyToGenericMappings(
|
||||
const VaryingState& state, std::queue<IR::Attribute> ununsed_generics) {
|
||||
std::map<IR::Attribute, IR::Attribute> mapping;
|
||||
for (size_t index = 0; index < 4; ++index) {
|
||||
auto attr = IR::Attribute::ColorFrontDiffuseR + index * 4;
|
||||
if (state.AnyComponent(attr)) {
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
mapping.insert({attr + i, ununsed_generics.front() + i});
|
||||
}
|
||||
ununsed_generics.pop();
|
||||
}
|
||||
}
|
||||
if (state[IR::Attribute::FogCoordinate]) {
|
||||
mapping.insert({IR::Attribute::FogCoordinate, ununsed_generics.front()});
|
||||
ununsed_generics.pop();
|
||||
}
|
||||
for (size_t index = 0; index < IR::NUM_FIXEDFNCTEXTURE; ++index) {
|
||||
auto attr = IR::Attribute::FixedFncTexture0S + index * 4;
|
||||
if (state.AnyComponent(attr)) {
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
mapping.insert({attr + i, ununsed_generics.front() + i});
|
||||
}
|
||||
ununsed_generics.pop();
|
||||
}
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool,
|
||||
@@ -226,4 +263,62 @@ IR::Program MergeDualVertexPrograms(IR::Program& vertex_a, IR::Program& vertex_b
|
||||
return result;
|
||||
}
|
||||
|
||||
void ConvertLegacyToGeneric(IR::Program& program, const Shader::RuntimeInfo& runtime_info) {
|
||||
auto& stores = program.info.stores;
|
||||
if (stores.Legacy()) {
|
||||
std::queue<IR::Attribute> ununsed_output_generics{};
|
||||
for (size_t index = 0; index < IR::NUM_GENERICS; ++index) {
|
||||
if (!stores.Generic(index)) {
|
||||
ununsed_output_generics.push(IR::Attribute::Generic0X + index * 4);
|
||||
}
|
||||
}
|
||||
auto mappings = GenerateLegacyToGenericMappings(stores, ununsed_output_generics);
|
||||
for (IR::Block* const block : program.post_order_blocks) {
|
||||
for (IR::Inst& inst : block->Instructions()) {
|
||||
switch (inst.GetOpcode()) {
|
||||
case IR::Opcode::SetAttribute: {
|
||||
const auto attr = inst.Arg(0).Attribute();
|
||||
if (IsLegacyAttribute(attr)) {
|
||||
stores.Set(mappings[attr], true);
|
||||
inst.SetArg(0, Shader::IR::Value(mappings[attr]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto& loads = program.info.loads;
|
||||
if (loads.Legacy()) {
|
||||
std::queue<IR::Attribute> ununsed_input_generics{};
|
||||
for (size_t index = 0; index < IR::NUM_GENERICS; ++index) {
|
||||
const AttributeType input_type{runtime_info.generic_input_types[index]};
|
||||
if (!runtime_info.previous_stage_stores.Generic(index) || !loads.Generic(index) ||
|
||||
input_type == AttributeType::Disabled) {
|
||||
ununsed_input_generics.push(IR::Attribute::Generic0X + index * 4);
|
||||
}
|
||||
}
|
||||
auto mappings = GenerateLegacyToGenericMappings(loads, ununsed_input_generics);
|
||||
for (IR::Block* const block : program.post_order_blocks) {
|
||||
for (IR::Inst& inst : block->Instructions()) {
|
||||
switch (inst.GetOpcode()) {
|
||||
case IR::Opcode::GetAttribute: {
|
||||
const auto attr = inst.Arg(0).Attribute();
|
||||
if (IsLegacyAttribute(attr)) {
|
||||
loads.Set(mappings[attr], true);
|
||||
inst.SetArg(0, Shader::IR::Value(mappings[attr]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Shader::Maxwell
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "shader_recompiler/frontend/maxwell/control_flow.h"
|
||||
#include "shader_recompiler/host_translate_info.h"
|
||||
#include "shader_recompiler/object_pool.h"
|
||||
#include "shader_recompiler/runtime_info.h"
|
||||
|
||||
namespace Shader::Maxwell {
|
||||
|
||||
@@ -20,4 +21,7 @@ namespace Shader::Maxwell {
|
||||
[[nodiscard]] IR::Program MergeDualVertexPrograms(IR::Program& vertex_a, IR::Program& vertex_b,
|
||||
Environment& env_vertex_b);
|
||||
|
||||
[[nodiscard]] void ConvertLegacyToGeneric(IR::Program& program,
|
||||
const Shader::RuntimeInfo& runtime_info);
|
||||
|
||||
} // namespace Shader::Maxwell
|
||||
|
||||
@@ -53,7 +53,8 @@ struct VaryingState {
|
||||
return AnyComponent(IR::Attribute::ColorFrontDiffuseR) ||
|
||||
AnyComponent(IR::Attribute::ColorFrontSpecularR) ||
|
||||
AnyComponent(IR::Attribute::ColorBackDiffuseR) ||
|
||||
AnyComponent(IR::Attribute::ColorBackSpecularR) || FixedFunctionTexture();
|
||||
AnyComponent(IR::Attribute::ColorBackSpecularR) || FixedFunctionTexture() ||
|
||||
mask[static_cast<size_t>(IR::Attribute::FogCoordinate)];
|
||||
}
|
||||
|
||||
[[nodiscard]] bool FixedFunctionTexture() const noexcept {
|
||||
|
||||
@@ -10,11 +10,12 @@ add_executable(tests
|
||||
core/network/network.cpp
|
||||
tests.cpp
|
||||
video_core/buffer_base.cpp
|
||||
input_common/calibration_configuration_job.cpp
|
||||
)
|
||||
|
||||
create_target_directory_groups(tests)
|
||||
|
||||
target_link_libraries(tests PRIVATE common core)
|
||||
target_link_libraries(tests PRIVATE common core input_common)
|
||||
target_link_libraries(tests PRIVATE ${PLATFORM_LIBRARIES} catch-single-include Threads::Threads)
|
||||
|
||||
add_test(NAME tests COMMAND tests)
|
||||
|
||||
136
src/tests/input_common/calibration_configuration_job.cpp
Normal file
136
src/tests/input_common/calibration_configuration_job.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
// Copyright 2020 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/crc.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include "input_common/drivers/udp_client.h"
|
||||
#include "input_common/helpers/udp_protocol.h"
|
||||
|
||||
class FakeCemuhookServer {
|
||||
public:
|
||||
FakeCemuhookServer()
|
||||
: socket(io_service, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 0)) {}
|
||||
|
||||
~FakeCemuhookServer() {
|
||||
is_running = false;
|
||||
boost::system::error_code error_code;
|
||||
socket.shutdown(boost::asio::socket_base::shutdown_both, error_code);
|
||||
socket.close();
|
||||
if (handler.joinable()) {
|
||||
handler.join();
|
||||
}
|
||||
}
|
||||
|
||||
u16 GetPort() {
|
||||
return socket.local_endpoint().port();
|
||||
}
|
||||
|
||||
std::string GetHost() {
|
||||
return socket.local_endpoint().address().to_string();
|
||||
}
|
||||
|
||||
void Run(const std::vector<InputCommon::CemuhookUDP::Response::TouchPad> touch_movement_path) {
|
||||
constexpr size_t HeaderSize = sizeof(InputCommon::CemuhookUDP::Header);
|
||||
constexpr size_t PadDataSize =
|
||||
sizeof(InputCommon::CemuhookUDP::Message<InputCommon::CemuhookUDP::Response::PadData>);
|
||||
|
||||
REQUIRE(touch_movement_path.size() > 0);
|
||||
is_running = true;
|
||||
handler = std::thread([touch_movement_path, this]() {
|
||||
auto current_touch_position = touch_movement_path.begin();
|
||||
while (is_running) {
|
||||
boost::asio::ip::udp::endpoint sender_endpoint;
|
||||
boost::system::error_code error_code;
|
||||
auto received_size = socket.receive_from(boost::asio::buffer(receive_buffer),
|
||||
sender_endpoint, 0, error_code);
|
||||
|
||||
if (received_size < HeaderSize) {
|
||||
continue;
|
||||
}
|
||||
|
||||
InputCommon::CemuhookUDP::Header header{};
|
||||
std::memcpy(&header, receive_buffer.data(), HeaderSize);
|
||||
switch (header.type) {
|
||||
case InputCommon::CemuhookUDP::Type::PadData: {
|
||||
InputCommon::CemuhookUDP::Response::PadData pad_data{};
|
||||
pad_data.touch[0] = *current_touch_position;
|
||||
const auto pad_message = InputCommon::CemuhookUDP::CreateMessage(
|
||||
InputCommon::CemuhookUDP::SERVER_MAGIC, pad_data, 0);
|
||||
std::memcpy(send_buffer.data(), &pad_message, PadDataSize);
|
||||
socket.send_to(boost::asio::buffer(send_buffer, PadDataSize), sender_endpoint,
|
||||
0, error_code);
|
||||
|
||||
bool can_advance =
|
||||
std::next(current_touch_position) != touch_movement_path.end();
|
||||
if (can_advance) {
|
||||
std::advance(current_touch_position, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InputCommon::CemuhookUDP::Type::PortInfo:
|
||||
case InputCommon::CemuhookUDP::Type::Version:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
boost::asio::io_service io_service;
|
||||
boost::asio::ip::udp::socket socket;
|
||||
std::array<u8, InputCommon::CemuhookUDP::MAX_PACKET_SIZE> send_buffer;
|
||||
std::array<u8, InputCommon::CemuhookUDP::MAX_PACKET_SIZE> receive_buffer;
|
||||
bool is_running = false;
|
||||
std::thread handler;
|
||||
};
|
||||
|
||||
TEST_CASE("CalibrationConfigurationJob completed", "[input_common]") {
|
||||
Common::Event complete_event;
|
||||
FakeCemuhookServer server;
|
||||
server.Run({{
|
||||
.is_active = 1,
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
},
|
||||
{
|
||||
.is_active = 1,
|
||||
.x = 200,
|
||||
.y = 200,
|
||||
}});
|
||||
|
||||
InputCommon::CemuhookUDP::CalibrationConfigurationJob::Status status{};
|
||||
u16 min_x{};
|
||||
u16 min_y{};
|
||||
u16 max_x{};
|
||||
u16 max_y{};
|
||||
InputCommon::CemuhookUDP::CalibrationConfigurationJob job(
|
||||
server.GetHost(), server.GetPort(),
|
||||
[&status,
|
||||
&complete_event](InputCommon::CemuhookUDP::CalibrationConfigurationJob::Status status_) {
|
||||
status = status_;
|
||||
if (status ==
|
||||
InputCommon::CemuhookUDP::CalibrationConfigurationJob::Status::Completed) {
|
||||
complete_event.Set();
|
||||
}
|
||||
},
|
||||
[&](u16 min_x_, u16 min_y_, u16 max_x_, u16 max_y_) {
|
||||
min_x = min_x_;
|
||||
min_y = min_y_;
|
||||
max_x = max_x_;
|
||||
max_y = max_y_;
|
||||
});
|
||||
|
||||
complete_event.WaitUntil(std::chrono::system_clock::now() + std::chrono::seconds(10));
|
||||
REQUIRE(status == InputCommon::CemuhookUDP::CalibrationConfigurationJob::Status::Completed);
|
||||
REQUIRE(min_x == 0);
|
||||
REQUIRE(min_y == 0);
|
||||
REQUIRE(max_x == 200);
|
||||
REQUIRE(max_y == 200);
|
||||
}
|
||||
@@ -32,7 +32,7 @@ constexpr std::array PREFERRED_GPU_DECODERS = {
|
||||
#ifdef _WIN32
|
||||
AV_HWDEVICE_TYPE_D3D11VA,
|
||||
AV_HWDEVICE_TYPE_DXVA2,
|
||||
#elif defined(__linux__)
|
||||
#elif defined(__unix__)
|
||||
AV_HWDEVICE_TYPE_VAAPI,
|
||||
AV_HWDEVICE_TYPE_VDPAU,
|
||||
#endif
|
||||
@@ -130,6 +130,12 @@ bool Codec::CreateGpuAvDevice() {
|
||||
}
|
||||
if (config->methods & HW_CONFIG_METHOD && config->device_type == type) {
|
||||
av_codec_ctx->pix_fmt = config->pix_fmt;
|
||||
if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX) {
|
||||
// skip zero-copy decoders, we don't currently support them
|
||||
LOG_DEBUG(Service_NVDRV, "Skipping decoder {} with unsupported capability {}.",
|
||||
av_hwdevice_get_type_name(type), config->methods);
|
||||
continue;
|
||||
}
|
||||
LOG_INFO(Service_NVDRV, "Using {} GPU decoder", av_hwdevice_get_type_name(type));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace {
|
||||
using Shader::Backend::GLASM::EmitGLASM;
|
||||
using Shader::Backend::GLSL::EmitGLSL;
|
||||
using Shader::Backend::SPIRV::EmitSPIRV;
|
||||
using Shader::Maxwell::ConvertLegacyToGeneric;
|
||||
using Shader::Maxwell::MergeDualVertexPrograms;
|
||||
using Shader::Maxwell::TranslateProgram;
|
||||
using VideoCommon::ComputeEnvironment;
|
||||
@@ -462,12 +463,14 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
|
||||
MakeRuntimeInfo(key, program, previous_program, glasm_use_storage_buffers, use_glasm)};
|
||||
switch (device.GetShaderBackend()) {
|
||||
case Settings::ShaderBackend::GLSL:
|
||||
ConvertLegacyToGeneric(program, runtime_info);
|
||||
sources[stage_index] = EmitGLSL(profile, runtime_info, program, binding);
|
||||
break;
|
||||
case Settings::ShaderBackend::GLASM:
|
||||
sources[stage_index] = EmitGLASM(profile, runtime_info, program, binding);
|
||||
break;
|
||||
case Settings::ShaderBackend::SPIRV:
|
||||
ConvertLegacyToGeneric(program, runtime_info);
|
||||
sources_spirv[stage_index] = EmitSPIRV(profile, runtime_info, program, binding);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1047,7 +1047,7 @@ bool Image::ScaleDown(bool ignore) {
|
||||
}
|
||||
|
||||
ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
|
||||
ImageId image_id_, Image& image)
|
||||
ImageId image_id_, Image& image, const SlotVector<Image>&)
|
||||
: VideoCommon::ImageViewBase{info, image.info, image_id_}, views{runtime.null_image_views} {
|
||||
const Device& device = runtime.device;
|
||||
if (True(image.flags & ImageFlagBits::Converted)) {
|
||||
|
||||
@@ -36,6 +36,7 @@ using VideoCommon::ImageViewType;
|
||||
using VideoCommon::NUM_RT;
|
||||
using VideoCommon::Region2D;
|
||||
using VideoCommon::RenderTargets;
|
||||
using VideoCommon::SlotVector;
|
||||
|
||||
struct ImageBufferMap {
|
||||
~ImageBufferMap();
|
||||
@@ -92,7 +93,7 @@ public:
|
||||
|
||||
void ReinterpretImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
|
||||
|
||||
void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled) {
|
||||
void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@@ -234,7 +235,8 @@ class ImageView : public VideoCommon::ImageViewBase {
|
||||
friend Image;
|
||||
|
||||
public:
|
||||
explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&);
|
||||
explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&,
|
||||
const SlotVector<Image>&);
|
||||
explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo&,
|
||||
const VideoCommon::ImageViewInfo&, GPUVAddr);
|
||||
explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info,
|
||||
|
||||
@@ -437,39 +437,29 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
|
||||
|
||||
glBindTextureUnit(0, fxaa_texture.handle);
|
||||
}
|
||||
|
||||
// Set projection matrix
|
||||
const std::array ortho_matrix =
|
||||
MakeOrthographicMatrix(static_cast<float>(layout.width), static_cast<float>(layout.height));
|
||||
|
||||
GLuint fragment_handle;
|
||||
const auto filter = Settings::values.scaling_filter.GetValue();
|
||||
switch (filter) {
|
||||
case Settings::ScalingFilter::NearestNeighbor:
|
||||
fragment_handle = present_bilinear_fragment.handle;
|
||||
break;
|
||||
case Settings::ScalingFilter::Bilinear:
|
||||
fragment_handle = present_bilinear_fragment.handle;
|
||||
break;
|
||||
case Settings::ScalingFilter::Bicubic:
|
||||
fragment_handle = present_bicubic_fragment.handle;
|
||||
break;
|
||||
case Settings::ScalingFilter::Gaussian:
|
||||
fragment_handle = present_gaussian_fragment.handle;
|
||||
break;
|
||||
case Settings::ScalingFilter::ScaleForce:
|
||||
fragment_handle = present_scaleforce_fragment.handle;
|
||||
break;
|
||||
case Settings::ScalingFilter::Fsr:
|
||||
LOG_WARNING(
|
||||
Render_OpenGL,
|
||||
"FidelityFX FSR Super Sampling is not supported in OpenGL, changing to ScaleForce");
|
||||
fragment_handle = present_scaleforce_fragment.handle;
|
||||
break;
|
||||
default:
|
||||
fragment_handle = present_bilinear_fragment.handle;
|
||||
break;
|
||||
}
|
||||
const auto fragment_handle = [this]() {
|
||||
switch (Settings::values.scaling_filter.GetValue()) {
|
||||
case Settings::ScalingFilter::NearestNeighbor:
|
||||
case Settings::ScalingFilter::Bilinear:
|
||||
return present_bilinear_fragment.handle;
|
||||
case Settings::ScalingFilter::Bicubic:
|
||||
return present_bicubic_fragment.handle;
|
||||
case Settings::ScalingFilter::Gaussian:
|
||||
return present_gaussian_fragment.handle;
|
||||
case Settings::ScalingFilter::ScaleForce:
|
||||
return present_scaleforce_fragment.handle;
|
||||
case Settings::ScalingFilter::Fsr:
|
||||
LOG_WARNING(
|
||||
Render_OpenGL,
|
||||
"FidelityFX Super Resolution is not supported in OpenGL, changing to ScaleForce");
|
||||
return present_scaleforce_fragment.handle;
|
||||
default:
|
||||
return present_bilinear_fragment.handle;
|
||||
}
|
||||
}();
|
||||
program_manager.BindPresentPrograms(present_vertex.handle, fragment_handle);
|
||||
glProgramUniformMatrix3x2fv(present_vertex.handle, ModelViewMatrixLocation, 1, GL_FALSE,
|
||||
ortho_matrix.data());
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h"
|
||||
#include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h"
|
||||
#include "video_core/host_shaders/convert_depth_to_float_frag_spv.h"
|
||||
@@ -335,6 +336,17 @@ void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout, const Regi
|
||||
cmdbuf.SetScissor(0, scissor);
|
||||
cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
|
||||
}
|
||||
|
||||
VkExtent2D GetConversionExtent(const ImageView& src_image_view) {
|
||||
const auto& resolution = Settings::values.resolution_info;
|
||||
const bool is_rescaled = src_image_view.IsRescaled();
|
||||
u32 width = src_image_view.size.width;
|
||||
u32 height = src_image_view.size.height;
|
||||
return VkExtent2D{
|
||||
.width = is_rescaled ? resolution.ScaleUp(width) : width,
|
||||
.height = is_rescaled ? resolution.ScaleUp(height) : height,
|
||||
};
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
BlitImageHelper::BlitImageHelper(const Device& device_, VKScheduler& scheduler_,
|
||||
@@ -425,108 +437,52 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
|
||||
}
|
||||
|
||||
void BlitImageHelper::ConvertD32ToR32(const Framebuffer* dst_framebuffer,
|
||||
const ImageView& src_image_view, u32 up_scale,
|
||||
u32 down_shift) {
|
||||
const ImageView& src_image_view) {
|
||||
ConvertDepthToColorPipeline(convert_d32_to_r32_pipeline, dst_framebuffer->RenderPass());
|
||||
Convert(*convert_d32_to_r32_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift);
|
||||
Convert(*convert_d32_to_r32_pipeline, dst_framebuffer, src_image_view);
|
||||
}
|
||||
|
||||
void BlitImageHelper::ConvertR32ToD32(const Framebuffer* dst_framebuffer,
|
||||
const ImageView& src_image_view, u32 up_scale,
|
||||
u32 down_shift) {
|
||||
const ImageView& src_image_view) {
|
||||
ConvertColorToDepthPipeline(convert_r32_to_d32_pipeline, dst_framebuffer->RenderPass());
|
||||
Convert(*convert_r32_to_d32_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift);
|
||||
Convert(*convert_r32_to_d32_pipeline, dst_framebuffer, src_image_view);
|
||||
}
|
||||
|
||||
void BlitImageHelper::ConvertD16ToR16(const Framebuffer* dst_framebuffer,
|
||||
const ImageView& src_image_view, u32 up_scale,
|
||||
u32 down_shift) {
|
||||
const ImageView& src_image_view) {
|
||||
ConvertDepthToColorPipeline(convert_d16_to_r16_pipeline, dst_framebuffer->RenderPass());
|
||||
Convert(*convert_d16_to_r16_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift);
|
||||
Convert(*convert_d16_to_r16_pipeline, dst_framebuffer, src_image_view);
|
||||
}
|
||||
|
||||
void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer,
|
||||
const ImageView& src_image_view, u32 up_scale,
|
||||
u32 down_shift) {
|
||||
const ImageView& src_image_view) {
|
||||
ConvertColorToDepthPipeline(convert_r16_to_d16_pipeline, dst_framebuffer->RenderPass());
|
||||
Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view, up_scale, down_shift);
|
||||
Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view);
|
||||
}
|
||||
|
||||
void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer,
|
||||
ImageView& src_image_view, u32 up_scale, u32 down_shift) {
|
||||
const ImageView& src_image_view) {
|
||||
ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
|
||||
convert_abgr8_to_d24s8_frag, true);
|
||||
ConvertColor(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view, up_scale,
|
||||
down_shift);
|
||||
convert_abgr8_to_d24s8_frag);
|
||||
Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view);
|
||||
}
|
||||
|
||||
void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
|
||||
ImageView& src_image_view, u32 up_scale, u32 down_shift) {
|
||||
ImageView& src_image_view) {
|
||||
ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
|
||||
convert_d24s8_to_abgr8_frag, false);
|
||||
ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view, up_scale,
|
||||
down_shift);
|
||||
convert_d24s8_to_abgr8_frag);
|
||||
ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view);
|
||||
}
|
||||
|
||||
void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
|
||||
const ImageView& src_image_view, u32 up_scale, u32 down_shift) {
|
||||
const ImageView& src_image_view) {
|
||||
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
||||
const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D);
|
||||
const VkSampler sampler = *nearest_sampler;
|
||||
const VkExtent2D extent{
|
||||
.width = std::max((src_image_view.size.width * up_scale) >> down_shift, 1U),
|
||||
.height = std::max((src_image_view.size.height * up_scale) >> down_shift, 1U),
|
||||
};
|
||||
scheduler.RequestRenderpass(dst_framebuffer);
|
||||
scheduler.Record([pipeline, layout, sampler, src_view, extent, up_scale, down_shift,
|
||||
this](vk::CommandBuffer cmdbuf) {
|
||||
const VkOffset2D offset{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
};
|
||||
const VkViewport viewport{
|
||||
.x = 0.0f,
|
||||
.y = 0.0f,
|
||||
.width = static_cast<float>(extent.width),
|
||||
.height = static_cast<float>(extent.height),
|
||||
.minDepth = 0.0f,
|
||||
.maxDepth = 0.0f,
|
||||
};
|
||||
const VkRect2D scissor{
|
||||
.offset = offset,
|
||||
.extent = extent,
|
||||
};
|
||||
const PushConstants push_constants{
|
||||
.tex_scale = {viewport.width, viewport.height},
|
||||
.tex_offset = {0.0f, 0.0f},
|
||||
};
|
||||
const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
|
||||
UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view);
|
||||
const VkExtent2D extent = GetConversionExtent(src_image_view);
|
||||
|
||||
// TODO: Barriers
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
|
||||
nullptr);
|
||||
cmdbuf.SetViewport(0, viewport);
|
||||
cmdbuf.SetScissor(0, scissor);
|
||||
cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
|
||||
cmdbuf.Draw(3, 1, 0, 0);
|
||||
});
|
||||
scheduler.InvalidateState();
|
||||
}
|
||||
|
||||
void BlitImageHelper::ConvertColor(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
|
||||
ImageView& src_image_view, u32 up_scale, u32 down_shift) {
|
||||
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
||||
const VkImageView src_view = src_image_view.ColorView();
|
||||
const VkSampler sampler = *nearest_sampler;
|
||||
const VkExtent2D extent{
|
||||
.width = std::max((src_image_view.size.width * up_scale) >> down_shift, 1U),
|
||||
.height = std::max((src_image_view.size.height * up_scale) >> down_shift, 1U),
|
||||
};
|
||||
scheduler.RequestRenderpass(dst_framebuffer);
|
||||
scheduler.Record([pipeline, layout, sampler, src_view, extent, up_scale, down_shift,
|
||||
this](vk::CommandBuffer cmdbuf) {
|
||||
scheduler.Record([pipeline, layout, sampler, src_view, extent, this](vk::CommandBuffer cmdbuf) {
|
||||
const VkOffset2D offset{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
@@ -563,18 +519,16 @@ void BlitImageHelper::ConvertColor(VkPipeline pipeline, const Framebuffer* dst_f
|
||||
}
|
||||
|
||||
void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
|
||||
ImageView& src_image_view, u32 up_scale, u32 down_shift) {
|
||||
ImageView& src_image_view) {
|
||||
const VkPipelineLayout layout = *two_textures_pipeline_layout;
|
||||
const VkImageView src_depth_view = src_image_view.DepthView();
|
||||
const VkImageView src_stencil_view = src_image_view.StencilView();
|
||||
const VkSampler sampler = *nearest_sampler;
|
||||
const VkExtent2D extent{
|
||||
.width = std::max((src_image_view.size.width * up_scale) >> down_shift, 1U),
|
||||
.height = std::max((src_image_view.size.height * up_scale) >> down_shift, 1U),
|
||||
};
|
||||
const VkExtent2D extent = GetConversionExtent(src_image_view);
|
||||
|
||||
scheduler.RequestRenderpass(dst_framebuffer);
|
||||
scheduler.Record([pipeline, layout, sampler, src_depth_view, src_stencil_view, extent, up_scale,
|
||||
down_shift, this](vk::CommandBuffer cmdbuf) {
|
||||
scheduler.Record([pipeline, layout, sampler, src_depth_view, src_stencil_view, extent,
|
||||
this](vk::CommandBuffer cmdbuf) {
|
||||
const VkOffset2D offset{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
@@ -695,11 +649,14 @@ VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePip
|
||||
return *blit_depth_stencil_pipelines.back();
|
||||
}
|
||||
|
||||
void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
|
||||
void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
||||
bool is_target_depth) {
|
||||
if (pipeline) {
|
||||
return;
|
||||
}
|
||||
const std::array stages = MakeStages(*full_screen_vert, *convert_depth_to_float_frag);
|
||||
VkShaderModule frag_shader =
|
||||
is_target_depth ? *convert_float_to_depth_frag : *convert_depth_to_float_frag;
|
||||
const std::array stages = MakeStages(*full_screen_vert, frag_shader);
|
||||
pipeline = device.GetLogical().CreateGraphicsPipeline({
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
@@ -712,8 +669,9 @@ void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRend
|
||||
.pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||
.pDepthStencilState = nullptr,
|
||||
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
|
||||
.pDepthStencilState = is_target_depth ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO : nullptr,
|
||||
.pColorBlendState = is_target_depth ? &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO
|
||||
: &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
|
||||
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.layout = *one_texture_pipeline_layout,
|
||||
.renderPass = renderpass,
|
||||
@@ -723,37 +681,17 @@ void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRend
|
||||
});
|
||||
}
|
||||
|
||||
void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
|
||||
ConvertPipeline(pipeline, renderpass, false);
|
||||
}
|
||||
|
||||
void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
|
||||
if (pipeline) {
|
||||
return;
|
||||
}
|
||||
const std::array stages = MakeStages(*full_screen_vert, *convert_float_to_depth_frag);
|
||||
pipeline = device.GetLogical().CreateGraphicsPipeline({
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.stageCount = static_cast<u32>(stages.size()),
|
||||
.pStages = stages.data(),
|
||||
.pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.pTessellationState = nullptr,
|
||||
.pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||
.pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
||||
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO,
|
||||
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.layout = *one_texture_pipeline_layout,
|
||||
.renderPass = renderpass,
|
||||
.subpass = 0,
|
||||
.basePipelineHandle = VK_NULL_HANDLE,
|
||||
.basePipelineIndex = 0,
|
||||
});
|
||||
ConvertPipeline(pipeline, renderpass, true);
|
||||
}
|
||||
|
||||
void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
||||
vk::ShaderModule& module, bool is_target_depth,
|
||||
bool single_texture) {
|
||||
vk::ShaderModule& module, bool single_texture,
|
||||
bool is_target_depth) {
|
||||
if (pipeline) {
|
||||
return;
|
||||
}
|
||||
@@ -782,13 +720,13 @@ void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass ren
|
||||
}
|
||||
|
||||
void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
||||
vk::ShaderModule& module, bool single_texture) {
|
||||
ConvertPipelineEx(pipeline, renderpass, module, false, single_texture);
|
||||
vk::ShaderModule& module) {
|
||||
ConvertPipelineEx(pipeline, renderpass, module, false, false);
|
||||
}
|
||||
|
||||
void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
||||
vk::ShaderModule& module, bool single_texture) {
|
||||
ConvertPipelineEx(pipeline, renderpass, module, true, single_texture);
|
||||
vk::ShaderModule& module) {
|
||||
ConvertPipelineEx(pipeline, renderpass, module, true, true);
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
@@ -44,50 +44,43 @@ public:
|
||||
const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter,
|
||||
Tegra::Engines::Fermi2D::Operation operation);
|
||||
|
||||
void ConvertD32ToR32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
|
||||
u32 up_scale, u32 down_shift);
|
||||
void ConvertD32ToR32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
|
||||
|
||||
void ConvertR32ToD32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
|
||||
u32 up_scale, u32 down_shift);
|
||||
void ConvertR32ToD32(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
|
||||
|
||||
void ConvertD16ToR16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
|
||||
u32 up_scale, u32 down_shift);
|
||||
void ConvertD16ToR16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
|
||||
|
||||
void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
|
||||
u32 up_scale, u32 down_shift);
|
||||
void ConvertR16ToD16(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
|
||||
|
||||
void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
|
||||
u32 up_scale, u32 down_shift);
|
||||
void ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer, const ImageView& src_image_view);
|
||||
|
||||
void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
|
||||
u32 up_scale, u32 down_shift);
|
||||
void ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer, ImageView& src_image_view);
|
||||
|
||||
private:
|
||||
void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
|
||||
const ImageView& src_image_view, u32 up_scale, u32 down_shift);
|
||||
|
||||
void ConvertColor(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
|
||||
ImageView& src_image_view, u32 up_scale, u32 down_shift);
|
||||
const ImageView& src_image_view);
|
||||
|
||||
void ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
|
||||
ImageView& src_image_view, u32 up_scale, u32 down_shift);
|
||||
ImageView& src_image_view);
|
||||
|
||||
[[nodiscard]] VkPipeline FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key);
|
||||
|
||||
[[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key);
|
||||
|
||||
void ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass, bool is_target_depth);
|
||||
|
||||
void ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
|
||||
|
||||
void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
|
||||
|
||||
void ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
||||
vk::ShaderModule& module, bool is_target_depth, bool single_texture);
|
||||
vk::ShaderModule& module, bool single_texture, bool is_target_depth);
|
||||
|
||||
void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
||||
vk::ShaderModule& module, bool single_texture);
|
||||
vk::ShaderModule& module);
|
||||
|
||||
void ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
||||
vk::ShaderModule& module, bool single_texture);
|
||||
vk::ShaderModule& module);
|
||||
|
||||
const Device& device;
|
||||
VKScheduler& scheduler;
|
||||
|
||||
@@ -176,8 +176,8 @@ struct FormatTuple {
|
||||
{VK_FORMAT_R32_UINT, Attachable | Storage}, // R32_UINT
|
||||
{VK_FORMAT_R32_SINT, Attachable | Storage}, // R32_SINT
|
||||
{VK_FORMAT_ASTC_8x8_UNORM_BLOCK}, // ASTC_2D_8X8_UNORM
|
||||
{VK_FORMAT_UNDEFINED}, // ASTC_2D_8X5_UNORM
|
||||
{VK_FORMAT_UNDEFINED}, // ASTC_2D_5X4_UNORM
|
||||
{VK_FORMAT_ASTC_8x5_UNORM_BLOCK}, // ASTC_2D_8X5_UNORM
|
||||
{VK_FORMAT_ASTC_5x4_UNORM_BLOCK}, // ASTC_2D_5X4_UNORM
|
||||
{VK_FORMAT_B8G8R8A8_SRGB, Attachable}, // B8G8R8A8_SRGB
|
||||
{VK_FORMAT_BC1_RGBA_SRGB_BLOCK}, // BC1_RGBA_SRGB
|
||||
{VK_FORMAT_BC2_SRGB_BLOCK}, // BC2_SRGB
|
||||
|
||||
@@ -391,28 +391,23 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
|
||||
.offset = {0, 0},
|
||||
.extent = size,
|
||||
};
|
||||
const auto filter = Settings::values.scaling_filter.GetValue();
|
||||
cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE);
|
||||
switch (filter) {
|
||||
case Settings::ScalingFilter::NearestNeighbor:
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *bilinear_pipeline);
|
||||
break;
|
||||
case Settings::ScalingFilter::Bilinear:
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *bilinear_pipeline);
|
||||
break;
|
||||
case Settings::ScalingFilter::Bicubic:
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *bicubic_pipeline);
|
||||
break;
|
||||
case Settings::ScalingFilter::Gaussian:
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *gaussian_pipeline);
|
||||
break;
|
||||
case Settings::ScalingFilter::ScaleForce:
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *scaleforce_pipeline);
|
||||
break;
|
||||
default:
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *bilinear_pipeline);
|
||||
break;
|
||||
}
|
||||
auto graphics_pipeline = [this]() {
|
||||
switch (Settings::values.scaling_filter.GetValue()) {
|
||||
case Settings::ScalingFilter::NearestNeighbor:
|
||||
case Settings::ScalingFilter::Bilinear:
|
||||
return *bilinear_pipeline;
|
||||
case Settings::ScalingFilter::Bicubic:
|
||||
return *bicubic_pipeline;
|
||||
case Settings::ScalingFilter::Gaussian:
|
||||
return *gaussian_pipeline;
|
||||
case Settings::ScalingFilter::ScaleForce:
|
||||
return *scaleforce_pipeline;
|
||||
default:
|
||||
return *bilinear_pipeline;
|
||||
}
|
||||
}();
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline);
|
||||
cmdbuf.SetViewport(0, viewport);
|
||||
cmdbuf.SetScissor(0, scissor);
|
||||
|
||||
|
||||
@@ -605,7 +605,11 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||
.flags = 0,
|
||||
.topology = input_assembly_topology,
|
||||
.primitiveRestartEnable = key.state.primitive_restart_enable != 0 &&
|
||||
SupportsPrimitiveRestart(input_assembly_topology),
|
||||
((input_assembly_topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST &&
|
||||
device.IsTopologyListPrimitiveRestartSupported()) ||
|
||||
SupportsPrimitiveRestart(input_assembly_topology) ||
|
||||
(input_assembly_topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST &&
|
||||
device.IsPatchListPrimitiveRestartSupported())),
|
||||
};
|
||||
const VkPipelineTessellationStateCreateInfo tessellation_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,
|
||||
@@ -613,7 +617,6 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||
.flags = 0,
|
||||
.patchControlPoints = key.state.patch_control_points_minus_one.Value() + 1,
|
||||
};
|
||||
|
||||
std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles;
|
||||
std::ranges::transform(key.state.viewport_swizzles, swizzles.begin(), UnpackViewportSwizzle);
|
||||
const VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{
|
||||
@@ -748,8 +751,8 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.logicOpEnable = VK_FALSE,
|
||||
.logicOp = VK_LOGIC_OP_COPY,
|
||||
.logicOpEnable = key.state.logic_op_enable != 0,
|
||||
.logicOp = static_cast<VkLogicOp>(key.state.logic_op.Value()),
|
||||
.attachmentCount = static_cast<u32>(cb_attachments.size()),
|
||||
.pAttachments = cb_attachments.data(),
|
||||
.blendConstants = {},
|
||||
|
||||
@@ -48,6 +48,7 @@ MICROPROFILE_DECLARE(Vulkan_PipelineCache);
|
||||
|
||||
namespace {
|
||||
using Shader::Backend::SPIRV::EmitSPIRV;
|
||||
using Shader::Maxwell::ConvertLegacyToGeneric;
|
||||
using Shader::Maxwell::MergeDualVertexPrograms;
|
||||
using Shader::Maxwell::TranslateProgram;
|
||||
using VideoCommon::ComputeEnvironment;
|
||||
@@ -543,6 +544,7 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
||||
infos[stage_index] = &program.info;
|
||||
|
||||
const auto runtime_info{MakeRuntimeInfo(programs, key, program, previous_stage)};
|
||||
ConvertLegacyToGeneric(program, runtime_info);
|
||||
const std::vector<u32> code{EmitSPIRV(profile, runtime_info, program, binding)};
|
||||
device.SaveShader(code);
|
||||
modules[stage_index] = BuildShader(device, code);
|
||||
|
||||
@@ -1057,37 +1057,37 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
|
||||
});
|
||||
}
|
||||
|
||||
void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view,
|
||||
bool rescaled) {
|
||||
const u32 up_scale = rescaled ? resolution.up_scale : 1;
|
||||
const u32 down_shift = rescaled ? resolution.down_shift : 0;
|
||||
void TextureCacheRuntime::ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view) {
|
||||
switch (dst_view.format) {
|
||||
case PixelFormat::R16_UNORM:
|
||||
if (src_view.format == PixelFormat::D16_UNORM) {
|
||||
return blit_image_helper.ConvertD16ToR16(dst, src_view, up_scale, down_shift);
|
||||
return blit_image_helper.ConvertD16ToR16(dst, src_view);
|
||||
}
|
||||
break;
|
||||
case PixelFormat::A8B8G8R8_UNORM:
|
||||
if (src_view.format == PixelFormat::S8_UINT_D24_UNORM) {
|
||||
return blit_image_helper.ConvertD24S8ToABGR8(dst, src_view, up_scale, down_shift);
|
||||
return blit_image_helper.ConvertD24S8ToABGR8(dst, src_view);
|
||||
}
|
||||
break;
|
||||
case PixelFormat::R32_FLOAT:
|
||||
if (src_view.format == PixelFormat::D32_FLOAT) {
|
||||
return blit_image_helper.ConvertD32ToR32(dst, src_view, up_scale, down_shift);
|
||||
return blit_image_helper.ConvertD32ToR32(dst, src_view);
|
||||
}
|
||||
break;
|
||||
case PixelFormat::D16_UNORM:
|
||||
if (src_view.format == PixelFormat::R16_UNORM) {
|
||||
return blit_image_helper.ConvertR16ToD16(dst, src_view, up_scale, down_shift);
|
||||
return blit_image_helper.ConvertR16ToD16(dst, src_view);
|
||||
}
|
||||
break;
|
||||
case PixelFormat::S8_UINT_D24_UNORM:
|
||||
return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view, up_scale, down_shift);
|
||||
if (src_view.format == PixelFormat::A8B8G8R8_UNORM ||
|
||||
src_view.format == PixelFormat::B8G8R8A8_UNORM) {
|
||||
return blit_image_helper.ConvertABGR8ToD24S8(dst, src_view);
|
||||
}
|
||||
break;
|
||||
case PixelFormat::D32_FLOAT:
|
||||
if (src_view.format == PixelFormat::R32_FLOAT) {
|
||||
return blit_image_helper.ConvertR32ToD32(dst, src_view, up_scale, down_shift);
|
||||
return blit_image_helper.ConvertR32ToD32(dst, src_view);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1329,6 +1329,10 @@ void Image::DownloadMemory(const StagingBufferRef& map, std::span<const BufferIm
|
||||
}
|
||||
}
|
||||
|
||||
bool Image::IsRescaled() const noexcept {
|
||||
return True(flags & ImageFlagBits::Rescaled);
|
||||
}
|
||||
|
||||
bool Image::ScaleUp(bool ignore) {
|
||||
if (True(flags & ImageFlagBits::Rescaled)) {
|
||||
return false;
|
||||
@@ -1469,7 +1473,7 @@ bool Image::BlitScaleHelper(bool scale_up) {
|
||||
ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
|
||||
ImageId image_id_, Image& image)
|
||||
: VideoCommon::ImageViewBase{info, image.info, image_id_}, device{&runtime.device},
|
||||
image_handle{image.Handle()}, samples{ConvertSampleCount(image.info.num_samples)} {
|
||||
image_handle{image.Handle()}, samples(ConvertSampleCount(image.info.num_samples)) {
|
||||
using Shader::TextureType;
|
||||
|
||||
const VkImageAspectFlags aspect_mask = ImageViewAspectMask(info);
|
||||
@@ -1552,6 +1556,12 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
|
||||
}
|
||||
}
|
||||
|
||||
ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info,
|
||||
ImageId image_id_, Image& image, const SlotVector<Image>& slot_imgs)
|
||||
: ImageView{runtime, info, image_id_, image} {
|
||||
slot_images = &slot_imgs;
|
||||
}
|
||||
|
||||
ImageView::ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo& info,
|
||||
const VideoCommon::ImageViewInfo& view_info, GPUVAddr gpu_addr_)
|
||||
: VideoCommon::ImageViewBase{info, view_info}, gpu_addr{gpu_addr_},
|
||||
@@ -1607,6 +1617,15 @@ VkImageView ImageView::StorageView(Shader::TextureType texture_type,
|
||||
return *view;
|
||||
}
|
||||
|
||||
bool ImageView::IsRescaled() const noexcept {
|
||||
if (!slot_images) {
|
||||
return false;
|
||||
}
|
||||
const auto& slots = *slot_images;
|
||||
const auto& src_image = slots[image_id];
|
||||
return src_image.IsRescaled();
|
||||
}
|
||||
|
||||
vk::ImageView ImageView::MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask) {
|
||||
return device->GetLogical().CreateImageView({
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
|
||||
@@ -23,6 +23,7 @@ using VideoCommon::ImageId;
|
||||
using VideoCommon::NUM_RT;
|
||||
using VideoCommon::Region2D;
|
||||
using VideoCommon::RenderTargets;
|
||||
using VideoCommon::SlotVector;
|
||||
using VideoCore::Surface::PixelFormat;
|
||||
|
||||
class ASTCDecoderPass;
|
||||
@@ -65,7 +66,7 @@ public:
|
||||
|
||||
void ReinterpretImage(Image& dst, Image& src, std::span<const VideoCommon::ImageCopy> copies);
|
||||
|
||||
void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view, bool rescaled);
|
||||
void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view);
|
||||
|
||||
bool CanAccelerateImageUpload(Image&) const noexcept {
|
||||
return false;
|
||||
@@ -139,6 +140,8 @@ public:
|
||||
return std::exchange(initialized, true);
|
||||
}
|
||||
|
||||
bool IsRescaled() const noexcept;
|
||||
|
||||
bool ScaleUp(bool ignore = false);
|
||||
|
||||
bool ScaleDown(bool ignore = false);
|
||||
@@ -168,6 +171,8 @@ private:
|
||||
class ImageView : public VideoCommon::ImageViewBase {
|
||||
public:
|
||||
explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&);
|
||||
explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&,
|
||||
const SlotVector<Image>&);
|
||||
explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo&,
|
||||
const VideoCommon::ImageViewInfo&, GPUVAddr);
|
||||
explicit ImageView(TextureCacheRuntime&, const VideoCommon::NullImageViewParams&);
|
||||
@@ -189,6 +194,8 @@ public:
|
||||
[[nodiscard]] VkImageView StorageView(Shader::TextureType texture_type,
|
||||
Shader::ImageFormat image_format);
|
||||
|
||||
[[nodiscard]] bool IsRescaled() const noexcept;
|
||||
|
||||
[[nodiscard]] VkImageView Handle(Shader::TextureType texture_type) const noexcept {
|
||||
return *image_views[static_cast<size_t>(texture_type)];
|
||||
}
|
||||
@@ -222,6 +229,8 @@ private:
|
||||
[[nodiscard]] vk::ImageView MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask);
|
||||
|
||||
const Device* device = nullptr;
|
||||
const SlotVector<Image>* slot_images = nullptr;
|
||||
|
||||
std::array<vk::ImageView, Shader::NUM_TEXTURE_TYPES> image_views;
|
||||
std::unique_ptr<StorageViews> storage_views;
|
||||
vk::ImageView depth_view;
|
||||
|
||||
@@ -1137,8 +1137,13 @@ typename TextureCache<P>::BlitImages TextureCache<P>::GetBlitImages(
|
||||
} while (has_deleted_images);
|
||||
const ImageBase& src_image = slot_images[src_id];
|
||||
const ImageBase& dst_image = slot_images[dst_id];
|
||||
const bool native_bgr = runtime.HasNativeBgr();
|
||||
if (GetFormatType(dst_info.format) != GetFormatType(dst_image.info.format) ||
|
||||
GetFormatType(src_info.format) != GetFormatType(src_image.info.format)) {
|
||||
GetFormatType(src_info.format) != GetFormatType(src_image.info.format) ||
|
||||
!VideoCore::Surface::IsViewCompatible(dst_info.format, dst_image.info.format, false,
|
||||
native_bgr) ||
|
||||
!VideoCore::Surface::IsViewCompatible(src_info.format, src_image.info.format, false,
|
||||
native_bgr)) {
|
||||
// Make sure the images match the expected format.
|
||||
do {
|
||||
has_deleted_images = false;
|
||||
@@ -1392,7 +1397,8 @@ ImageViewId TextureCache<P>::FindOrEmplaceImageView(ImageId image_id, const Imag
|
||||
if (const ImageViewId image_view_id = image.FindView(info); image_view_id) {
|
||||
return image_view_id;
|
||||
}
|
||||
const ImageViewId image_view_id = slot_image_views.insert(runtime, info, image_id, image);
|
||||
const ImageViewId image_view_id =
|
||||
slot_image_views.insert(runtime, info, image_id, image, slot_images);
|
||||
image.InsertView(info, image_view_id);
|
||||
return image_view_id;
|
||||
}
|
||||
@@ -1850,9 +1856,20 @@ void TextureCache<P>::CopyImage(ImageId dst_id, ImageId src_id, std::vector<Imag
|
||||
.height = std::min(dst_view.size.height, src_view.size.height),
|
||||
.depth = std::min(dst_view.size.depth, src_view.size.depth),
|
||||
};
|
||||
UNIMPLEMENTED_IF(copy.extent != expected_size);
|
||||
const Extent3D scaled_extent = [is_rescaled, expected_size]() {
|
||||
if (!is_rescaled) {
|
||||
return expected_size;
|
||||
}
|
||||
const auto& resolution = Settings::values.resolution_info;
|
||||
return Extent3D{
|
||||
.width = resolution.ScaleUp(expected_size.width),
|
||||
.height = resolution.ScaleUp(expected_size.height),
|
||||
.depth = expected_size.depth,
|
||||
};
|
||||
}();
|
||||
UNIMPLEMENTED_IF(copy.extent != scaled_extent);
|
||||
|
||||
runtime.ConvertImage(dst_framebuffer, dst_view, src_view, is_rescaled);
|
||||
runtime.ConvertImage(dst_framebuffer, dst_view, src_view);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -271,7 +271,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
.tessellationShader = true,
|
||||
.sampleRateShading = true,
|
||||
.dualSrcBlend = true,
|
||||
.logicOp = false,
|
||||
.logicOp = true,
|
||||
.multiDrawIndirect = false,
|
||||
.drawIndirectFirstInstance = false,
|
||||
.depthClamp = true,
|
||||
@@ -433,6 +433,19 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
LOG_INFO(Render_Vulkan, "Device doesn't support uint8 indexes");
|
||||
}
|
||||
|
||||
VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT primitive_topology_list_restart;
|
||||
if (is_topology_list_restart_supported || is_patch_list_restart_supported) {
|
||||
primitive_topology_list_restart = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT,
|
||||
.pNext = nullptr,
|
||||
.primitiveTopologyListRestart = is_topology_list_restart_supported,
|
||||
.primitiveTopologyPatchListRestart = is_patch_list_restart_supported,
|
||||
};
|
||||
SetNext(next, primitive_topology_list_restart);
|
||||
} else {
|
||||
LOG_INFO(Render_Vulkan, "Device doesn't support list topology primitive restart");
|
||||
}
|
||||
|
||||
VkPhysicalDeviceTransformFeedbackFeaturesEXT transform_feedback;
|
||||
if (ext_transform_feedback) {
|
||||
transform_feedback = {
|
||||
@@ -891,6 +904,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
|
||||
bool has_ext_provoking_vertex{};
|
||||
bool has_ext_vertex_input_dynamic_state{};
|
||||
bool has_ext_line_rasterization{};
|
||||
bool has_ext_primitive_topology_list_restart{};
|
||||
for (const std::string& extension : supported_extensions) {
|
||||
const auto test = [&](std::optional<std::reference_wrapper<bool>> status, const char* name,
|
||||
bool push) {
|
||||
@@ -915,6 +929,8 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
|
||||
test(has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false);
|
||||
test(ext_depth_range_unrestricted, VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true);
|
||||
test(ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true);
|
||||
test(has_ext_primitive_topology_list_restart,
|
||||
VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME, true);
|
||||
test(ext_sampler_filter_minmax, VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME, true);
|
||||
test(ext_shader_viewport_index_layer, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME,
|
||||
true);
|
||||
@@ -1113,6 +1129,19 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
|
||||
khr_pipeline_executable_properties = true;
|
||||
}
|
||||
}
|
||||
if (has_ext_primitive_topology_list_restart) {
|
||||
VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT primitive_topology_list_restart{};
|
||||
primitive_topology_list_restart.sType =
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT;
|
||||
primitive_topology_list_restart.pNext = nullptr;
|
||||
features.pNext = &primitive_topology_list_restart;
|
||||
physical.GetFeatures2KHR(features);
|
||||
|
||||
is_topology_list_restart_supported =
|
||||
primitive_topology_list_restart.primitiveTopologyListRestart;
|
||||
is_patch_list_restart_supported =
|
||||
primitive_topology_list_restart.primitiveTopologyPatchListRestart;
|
||||
}
|
||||
if (has_khr_image_format_list && has_khr_swapchain_mutable_format) {
|
||||
extensions.push_back(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME);
|
||||
extensions.push_back(VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME);
|
||||
|
||||
@@ -238,6 +238,16 @@ public:
|
||||
return khr_workgroup_memory_explicit_layout;
|
||||
}
|
||||
|
||||
/// Returns true if the device supports VK_EXT_primitive_topology_list_restart.
|
||||
bool IsTopologyListPrimitiveRestartSupported() const {
|
||||
return is_topology_list_restart_supported;
|
||||
}
|
||||
|
||||
/// Returns true if the device supports VK_EXT_primitive_topology_list_restart.
|
||||
bool IsPatchListPrimitiveRestartSupported() const {
|
||||
return is_patch_list_restart_supported;
|
||||
}
|
||||
|
||||
/// Returns true if the device supports VK_EXT_index_type_uint8.
|
||||
bool IsExtIndexTypeUint8Supported() const {
|
||||
return ext_index_type_uint8;
|
||||
@@ -401,6 +411,9 @@ private:
|
||||
bool is_shader_int16_supported{}; ///< Support for int16.
|
||||
bool is_shader_storage_image_multisample{}; ///< Support for image operations on MSAA images.
|
||||
bool is_blit_depth_stencil_supported{}; ///< Support for blitting from and to depth stencil.
|
||||
bool is_topology_list_restart_supported{}; ///< Support for primitive restart with list
|
||||
///< topologies.
|
||||
bool is_patch_list_restart_supported{}; ///< Support for primitive restart with list patch.
|
||||
bool nv_viewport_swizzle{}; ///< Support for VK_NV_viewport_swizzle.
|
||||
bool nv_viewport_array2{}; ///< Support for VK_NV_viewport_array2.
|
||||
bool nv_geometry_shader_passthrough{}; ///< Support for VK_NV_geometry_shader_passthrough.
|
||||
|
||||
@@ -251,6 +251,9 @@ target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include)
|
||||
if (NOT WIN32)
|
||||
target_include_directories(yuzu PRIVATE ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
||||
endif()
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
target_link_libraries(yuzu PRIVATE Qt5::DBus)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(yuzu PRIVATE
|
||||
# Use QStringBuilder for string concatenation to reduce
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "core/hid/hid_types.h"
|
||||
#include "core/hle/lock.h"
|
||||
#include "core/hle/service/hid/controllers/npad.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
@@ -664,7 +663,5 @@ void QtControllerSelector::ReconfigureControllers(
|
||||
}
|
||||
|
||||
void QtControllerSelector::MainWindowReconfigureFinished() {
|
||||
// Acquire the HLE mutex
|
||||
std::lock_guard lock(HLE::g_hle_lock);
|
||||
callback();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <QDateTime>
|
||||
#include "core/hle/lock.h"
|
||||
#include "yuzu/applets/qt_error.h"
|
||||
#include "yuzu/main.h"
|
||||
|
||||
@@ -57,7 +56,5 @@ void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_te
|
||||
}
|
||||
|
||||
void QtErrorDisplay::MainWindowFinishedError() {
|
||||
// Acquire the HLE mutex
|
||||
std::lock_guard lock{HLE::g_hle_lock};
|
||||
callback();
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "common/fs/path_util.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/constants.h"
|
||||
#include "core/hle/lock.h"
|
||||
#include "yuzu/applets/qt_profile_select.h"
|
||||
#include "yuzu/main.h"
|
||||
#include "yuzu/util/controller_navigation.h"
|
||||
@@ -170,7 +169,5 @@ void QtProfileSelector::SelectProfile(
|
||||
}
|
||||
|
||||
void QtProfileSelector::MainWindowFinishedSelection(std::optional<Common::UUID> uuid) {
|
||||
// Acquire the HLE mutex
|
||||
std::lock_guard lock{HLE::g_hle_lock};
|
||||
callback(uuid);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user