mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-06-16 04:07:51 +00:00
Compare commits
107 Commits
f63b2c2fa3
...
6c6e19fdbe
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6c6e19fdbe | ||
![]() |
5800b874d7 | ||
![]() |
1526c06133 | ||
![]() |
7ad85e875d | ||
![]() |
42d5f2b705 | ||
![]() |
5064b615ba | ||
![]() |
33b529a510 | ||
![]() |
8c3ca46988 | ||
![]() |
944dd711b7 | ||
![]() |
1b7d42f775 | ||
![]() |
24b0bf01d5 | ||
![]() |
19fbbf0dba | ||
![]() |
1786e34bd3 | ||
![]() |
65f3ba70f5 | ||
![]() |
ec52a74967 | ||
![]() |
8b7669550f | ||
![]() |
46e66fe945 | ||
![]() |
056ece6f29 | ||
![]() |
a07a2fe398 | ||
![]() |
61e8fa060b | ||
![]() |
b6ff1b5573 | ||
![]() |
5906512847 | ||
![]() |
52fcdde485 | ||
![]() |
5eb61024c6 | ||
![]() |
a27b845514 | ||
![]() |
1b1ca019a4 | ||
![]() |
241834709b | ||
![]() |
c68549e9ef | ||
![]() |
5545a386cf | ||
![]() |
185b080f03 | ||
![]() |
c3d3b81533 | ||
![]() |
774a84a953 | ||
![]() |
b3f50c969e | ||
![]() |
3b83907b88 | ||
![]() |
d940d62cae | ||
![]() |
7afa9e6c6f | ||
![]() |
12d178a8df | ||
![]() |
f910c1d934 | ||
![]() |
70abcb2030 | ||
![]() |
d8ea31ca46 | ||
![]() |
2ae43324cb | ||
![]() |
7d59c2743d | ||
![]() |
8113399b68 | ||
![]() |
bafe78203d | ||
![]() |
15f125ebee | ||
![]() |
316740daed | ||
![]() |
903eafcf65 | ||
![]() |
2a7e8a4003 | ||
![]() |
9ec69b5925 | ||
![]() |
d7de49ccf6 | ||
![]() |
5ec5db9240 | ||
![]() |
974c56d3c5 | ||
![]() |
977f2da6a7 | ||
![]() |
b1d114f7f7 | ||
![]() |
be3d48ec5f | ||
![]() |
a0611b512b | ||
![]() |
fadc2ac223 | ||
![]() |
ea959f2651 | ||
![]() |
a43fc68452 | ||
![]() |
ae26b38fc0 | ||
![]() |
b9bea58f0f | ||
![]() |
b7fb2fa737 | ||
![]() |
2de9122b5f | ||
![]() |
8665b22822 | ||
![]() |
bae0e5f67a | ||
![]() |
2ae928ca79 | ||
![]() |
f04f659710 | ||
![]() |
ec1d659363 | ||
![]() |
c37933932d | ||
![]() |
23af1e025b | ||
![]() |
135b6840e5 | ||
![]() |
e3df00b7f4 | ||
![]() |
71da0f2d24 | ||
![]() |
5d2518d490 | ||
![]() |
3f090dd474 | ||
![]() |
8def02072b | ||
![]() |
84f2af73e6 | ||
![]() |
4b65cc9a4c | ||
![]() |
8192d9d2a9 | ||
![]() |
a6b04f53e0 | ||
![]() |
a8eafa4ccd | ||
![]() |
a5b4a0b9e4 | ||
![]() |
fd285f6348 | ||
![]() |
3dc1605569 | ||
![]() |
a6a5e201b6 | ||
![]() |
aafe961177 | ||
![]() |
eed7843d4a | ||
![]() |
1e4dfc0956 | ||
![]() |
5bc661aeca | ||
![]() |
fcff7a3a49 | ||
![]() |
543b85a451 | ||
![]() |
e796e82e8c | ||
![]() |
2b9935e6f4 | ||
![]() |
6c98e7b538 | ||
![]() |
f99d3dbd5c | ||
![]() |
34e8fb068f | ||
![]() |
7c237bbd7c | ||
![]() |
b23dddea4e | ||
![]() |
b61a398e18 | ||
![]() |
2ed5f16600 | ||
![]() |
c23b4e1020 | ||
![]() |
8b228503d9 | ||
![]() |
1554e4ab6c | ||
![]() |
ec29d120b5 | ||
![]() |
f240e20e3f | ||
![]() |
d48e6e25ad | ||
![]() |
096ab8c026 |
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -84,6 +84,9 @@
|
|||||||
[submodule "Externals/Vulkan-Headers"]
|
[submodule "Externals/Vulkan-Headers"]
|
||||||
path = Externals/Vulkan-Headers
|
path = Externals/Vulkan-Headers
|
||||||
url = https://github.com/KhronosGroup/Vulkan-Headers.git
|
url = https://github.com/KhronosGroup/Vulkan-Headers.git
|
||||||
|
[submodule "Externals/watcher/watcher"]
|
||||||
|
path = Externals/watcher/watcher
|
||||||
|
url = https://github.com/e-dant/watcher.git
|
||||||
[submodule "Externals/SFML/SFML"]
|
[submodule "Externals/SFML/SFML"]
|
||||||
path = Externals/SFML/SFML
|
path = Externals/SFML/SFML
|
||||||
url = https://github.com/SFML/SFML.git
|
url = https://github.com/SFML/SFML.git
|
||||||
|
@ -691,8 +691,8 @@ dolphin_find_optional_system_library_pkgconfig(ZSTD libzstd>=1.4.0 zstd::zstd Ex
|
|||||||
|
|
||||||
dolphin_find_optional_system_library_pkgconfig(ZLIB zlib>=1.3.1 ZLIB::ZLIB Externals/zlib-ng)
|
dolphin_find_optional_system_library_pkgconfig(ZLIB zlib>=1.3.1 ZLIB::ZLIB Externals/zlib-ng)
|
||||||
|
|
||||||
dolphin_find_optional_system_library_pkgconfig(MINIZIP
|
dolphin_find_optional_system_library_pkgconfig(minizip-ng
|
||||||
"minizip>=4.0.4" minizip::minizip Externals/minizip-ng
|
"minizip-ng>=4.0.4" minizip-ng::minizip-ng Externals/minizip-ng
|
||||||
)
|
)
|
||||||
|
|
||||||
dolphin_find_optional_system_library(LZO Externals/LZO)
|
dolphin_find_optional_system_library(LZO Externals/LZO)
|
||||||
@ -784,6 +784,8 @@ if (USE_RETRO_ACHIEVEMENTS)
|
|||||||
add_subdirectory(Externals/rcheevos)
|
add_subdirectory(Externals/rcheevos)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(Externals/watcher)
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
# Pre-build events: Define configuration variables and write SCM info header
|
# Pre-build events: Define configuration variables and write SCM info header
|
||||||
#
|
#
|
||||||
|
File diff suppressed because one or more lines are too long
5
Data/Sys/GameSettings/GIHP78.ini
Normal file
5
Data/Sys/GameSettings/GIHP78.ini
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# GIHP78 - Scooby-Doo! Night of 100 Frights
|
||||||
|
|
||||||
|
[Video_Settings]
|
||||||
|
# Fixes video stuttering on FMVs encoded at 25 FPS
|
||||||
|
SafeTextureCacheColorSamples = 512
|
8
Data/Sys/GameSettings/SBLE5G.ini
Normal file
8
Data/Sys/GameSettings/SBLE5G.ini
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# SBLE5G - A Boy and His Blob
|
||||||
|
|
||||||
|
[OnFrame]
|
||||||
|
$Fix selecting right-most bean
|
||||||
|
0x800BD308:dword:0x4181000C
|
||||||
|
|
||||||
|
[OnFrame_Enabled]
|
||||||
|
$Fix selecting right-most bean
|
8
Data/Sys/GameSettings/SBLP5G.ini
Normal file
8
Data/Sys/GameSettings/SBLP5G.ini
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# SBLP5G - A Boy and His Blob
|
||||||
|
|
||||||
|
[OnFrame]
|
||||||
|
$Fix selecting right-most bean
|
||||||
|
0x800BE268:dword:0x4181000C
|
||||||
|
|
||||||
|
[OnFrame_Enabled]
|
||||||
|
$Fix selecting right-most bean
|
9
Data/Sys/GameSettings/SCYE4Q.ini
Normal file
9
Data/Sys/GameSettings/SCYE4Q.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# SCYE4Q - Cars 2
|
||||||
|
|
||||||
|
[OnFrame]
|
||||||
|
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
|
||||||
|
$BAT Speedhack
|
||||||
|
0x8019CB1C:dword:0x48000180
|
||||||
|
|
||||||
|
[OnFrame_Enabled]
|
||||||
|
$BAT Speedhack
|
9
Data/Sys/GameSettings/SCYP4Q.ini
Normal file
9
Data/Sys/GameSettings/SCYP4Q.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# SCYP4Q - Cars 2
|
||||||
|
|
||||||
|
[OnFrame]
|
||||||
|
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
|
||||||
|
$BAT Speedhack
|
||||||
|
0x8019CB1C:dword:0x48000180
|
||||||
|
|
||||||
|
[OnFrame_Enabled]
|
||||||
|
$BAT Speedhack
|
9
Data/Sys/GameSettings/SCYR4Q.ini
Normal file
9
Data/Sys/GameSettings/SCYR4Q.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# SCYR4Q - Cars 2
|
||||||
|
|
||||||
|
[OnFrame]
|
||||||
|
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
|
||||||
|
$BAT Speedhack
|
||||||
|
0x8019B4EC:dword:0x48000180
|
||||||
|
|
||||||
|
[OnFrame_Enabled]
|
||||||
|
$BAT Speedhack
|
9
Data/Sys/GameSettings/SCYX4Q.ini
Normal file
9
Data/Sys/GameSettings/SCYX4Q.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# SCYX4Q - Cars 2
|
||||||
|
|
||||||
|
[OnFrame]
|
||||||
|
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
|
||||||
|
$BAT Speedhack
|
||||||
|
0x8019CBBC:dword:0x48000180
|
||||||
|
|
||||||
|
[OnFrame_Enabled]
|
||||||
|
$BAT Speedhack
|
9
Data/Sys/GameSettings/SCYY4Q.ini
Normal file
9
Data/Sys/GameSettings/SCYY4Q.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# SCYY4Q - Cars 2
|
||||||
|
|
||||||
|
[OnFrame]
|
||||||
|
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
|
||||||
|
$BAT Speedhack
|
||||||
|
0x8019B55C:dword:0x48000180
|
||||||
|
|
||||||
|
[OnFrame_Enabled]
|
||||||
|
$BAT Speedhack
|
9
Data/Sys/GameSettings/SCYZ4Q.ini
Normal file
9
Data/Sys/GameSettings/SCYZ4Q.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# SCYZ4Q - Cars 2
|
||||||
|
|
||||||
|
[OnFrame]
|
||||||
|
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
|
||||||
|
$BAT Speedhack
|
||||||
|
0x8019B55C:dword:0x48000180
|
||||||
|
|
||||||
|
[OnFrame_Enabled]
|
||||||
|
$BAT Speedhack
|
@ -1,4 +1,4 @@
|
|||||||
# SQIE4Q, SQIP4Q - Disney Infinity
|
# SQIE4Q, SQIP4Q, SQIY4Q - Disney Infinity
|
||||||
|
|
||||||
[Core]
|
[Core]
|
||||||
# Values set here will override the main Dolphin settings.
|
# Values set here will override the main Dolphin settings.
|
||||||
|
9
Data/Sys/GameSettings/SQIE4Q.ini
Normal file
9
Data/Sys/GameSettings/SQIE4Q.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# SQIE4Q - Disney Infinity
|
||||||
|
|
||||||
|
[OnFrame]
|
||||||
|
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
|
||||||
|
$BAT Speedhack
|
||||||
|
0x8008E60C:dword:0x48000180
|
||||||
|
|
||||||
|
[OnFrame_Enabled]
|
||||||
|
$BAT Speedhack
|
9
Data/Sys/GameSettings/SQIP4Q.ini
Normal file
9
Data/Sys/GameSettings/SQIP4Q.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# SQIP4Q - Disney Infinity
|
||||||
|
|
||||||
|
[OnFrame]
|
||||||
|
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
|
||||||
|
$BAT Speedhack
|
||||||
|
0x8008E60C:dword:0x48000180
|
||||||
|
|
||||||
|
[OnFrame_Enabled]
|
||||||
|
$BAT Speedhack
|
9
Data/Sys/GameSettings/SQIY4Q.ini
Normal file
9
Data/Sys/GameSettings/SQIY4Q.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# SQIY4Q - Disney Infinity
|
||||||
|
|
||||||
|
[OnFrame]
|
||||||
|
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
|
||||||
|
$BAT Speedhack
|
||||||
|
0x8008E60C:dword:0x48000180
|
||||||
|
|
||||||
|
[OnFrame_Enabled]
|
||||||
|
$BAT Speedhack
|
9
Data/Sys/GameSettings/STSE4Q.ini
Normal file
9
Data/Sys/GameSettings/STSE4Q.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# STSE4Q - Toy Story 3
|
||||||
|
|
||||||
|
[OnFrame]
|
||||||
|
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
|
||||||
|
$BAT Speedhack
|
||||||
|
0x801FA2E4:dword:0x48000180
|
||||||
|
|
||||||
|
[OnFrame_Enabled]
|
||||||
|
$BAT Speedhack
|
9
Data/Sys/GameSettings/STSP4Qr1.ini
Normal file
9
Data/Sys/GameSettings/STSP4Qr1.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# STSP4Q - Toy Story 3
|
||||||
|
|
||||||
|
[OnFrame]
|
||||||
|
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
|
||||||
|
$BAT Speedhack
|
||||||
|
0x801FA2E4:dword:0x48000180
|
||||||
|
|
||||||
|
[OnFrame_Enabled]
|
||||||
|
$BAT Speedhack
|
9
Data/Sys/GameSettings/STSP4Qr2.ini
Normal file
9
Data/Sys/GameSettings/STSP4Qr2.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# STSP4Q - Toy Story 3
|
||||||
|
|
||||||
|
[OnFrame]
|
||||||
|
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
|
||||||
|
$BAT Speedhack
|
||||||
|
0x801FA354:dword:0x48000180
|
||||||
|
|
||||||
|
[OnFrame_Enabled]
|
||||||
|
$BAT Speedhack
|
9
Data/Sys/GameSettings/STSX4Q.ini
Normal file
9
Data/Sys/GameSettings/STSX4Q.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# STSX4Q - Toy Story 3
|
||||||
|
|
||||||
|
[OnFrame]
|
||||||
|
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
|
||||||
|
$BAT Speedhack
|
||||||
|
0x801FA354:dword:0x48000180
|
||||||
|
|
||||||
|
[OnFrame_Enabled]
|
||||||
|
$BAT Speedhack
|
9
Data/Sys/GameSettings/STSY4Qr0.ini
Normal file
9
Data/Sys/GameSettings/STSY4Qr0.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# STSY4Q - Toy Story 3
|
||||||
|
|
||||||
|
[OnFrame]
|
||||||
|
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
|
||||||
|
$BAT Speedhack
|
||||||
|
0x801FA2E4:dword:0x48000180
|
||||||
|
|
||||||
|
[OnFrame_Enabled]
|
||||||
|
$BAT Speedhack
|
9
Data/Sys/GameSettings/STSY4Qr1.ini
Normal file
9
Data/Sys/GameSettings/STSY4Qr1.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# STSY4Q - Toy Story 3
|
||||||
|
|
||||||
|
[OnFrame]
|
||||||
|
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
|
||||||
|
$BAT Speedhack
|
||||||
|
0x801FA354:dword:0x48000180
|
||||||
|
|
||||||
|
[OnFrame_Enabled]
|
||||||
|
$BAT Speedhack
|
9
Data/Sys/GameSettings/STSZ4Q.ini
Normal file
9
Data/Sys/GameSettings/STSZ4Q.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# STSZ4Q - Toy Story 3 Toy Box Special Edition
|
||||||
|
|
||||||
|
[OnFrame]
|
||||||
|
#This speedhack modifies the way the game manages memory to run faster in Dolphin.
|
||||||
|
$BAT Speedhack
|
||||||
|
0x801FA2E4:dword:0x48000180
|
||||||
|
|
||||||
|
[OnFrame_Enabled]
|
||||||
|
$BAT Speedhack
|
2
Externals/glslang/CMakeLists.txt
vendored
2
Externals/glslang/CMakeLists.txt
vendored
@ -77,5 +77,5 @@ dolphin_disable_warnings(glslang)
|
|||||||
|
|
||||||
target_include_directories(glslang
|
target_include_directories(glslang
|
||||||
PRIVATE
|
PRIVATE
|
||||||
${CMAKE_SOURCE_DIR}/Externals/glslang
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
)
|
)
|
||||||
|
10
Externals/minizip-ng/CMakeLists.txt
vendored
10
Externals/minizip-ng/CMakeLists.txt
vendored
@ -6,10 +6,10 @@ include(CheckIncludeFile)
|
|||||||
add_library(minizip STATIC
|
add_library(minizip STATIC
|
||||||
minizip-ng/mz.h
|
minizip-ng/mz.h
|
||||||
# minizip-ng/compat/crypt.h
|
# minizip-ng/compat/crypt.h
|
||||||
minizip-ng/compat/ioapi.c
|
# minizip-ng/compat/ioapi.c
|
||||||
minizip-ng/compat/ioapi.h
|
# minizip-ng/compat/ioapi.h
|
||||||
minizip-ng/compat/unzip.c
|
# minizip-ng/compat/unzip.c
|
||||||
minizip-ng/compat/unzip.h
|
# minizip-ng/compat/unzip.h
|
||||||
# minizip-ng/compat/zip.c
|
# minizip-ng/compat/zip.c
|
||||||
# minizip-ng/compat/zip.h
|
# minizip-ng/compat/zip.h
|
||||||
minizip-ng/mz_crypt.c
|
minizip-ng/mz_crypt.c
|
||||||
@ -93,4 +93,4 @@ endif()
|
|||||||
|
|
||||||
target_link_libraries(minizip PUBLIC ZLIB::ZLIB)
|
target_link_libraries(minizip PUBLIC ZLIB::ZLIB)
|
||||||
|
|
||||||
add_library(minizip::minizip ALIAS minizip)
|
add_library(minizip-ng::minizip-ng ALIAS minizip)
|
||||||
|
4
Externals/minizip-ng/minizip-ng.vcxproj
vendored
4
Externals/minizip-ng/minizip-ng.vcxproj
vendored
@ -23,8 +23,6 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="minizip-ng\compat\ioapi.c" />
|
|
||||||
<ClCompile Include="minizip-ng\compat\unzip.c" />
|
|
||||||
<ClCompile Include="minizip-ng\mz_crypt.c" />
|
<ClCompile Include="minizip-ng\mz_crypt.c" />
|
||||||
<ClCompile Include="minizip-ng\mz_os.c" />
|
<ClCompile Include="minizip-ng\mz_os.c" />
|
||||||
<ClCompile Include="minizip-ng\mz_os_win32.c" />
|
<ClCompile Include="minizip-ng\mz_os_win32.c" />
|
||||||
@ -39,8 +37,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="minizip-ng\mz.h" />
|
<ClInclude Include="minizip-ng\mz.h" />
|
||||||
<ClCompile Include="minizip-ng\compat\ioapi.h" />
|
|
||||||
<ClCompile Include="minizip-ng\compat\unzip.h" />
|
|
||||||
<ClInclude Include="minizip-ng\mz_crypt.h" />
|
<ClInclude Include="minizip-ng\mz_crypt.h" />
|
||||||
<ClInclude Include="minizip-ng\mz_os.h" />
|
<ClInclude Include="minizip-ng\mz_os.h" />
|
||||||
<ClInclude Include="minizip-ng\mz_strm.h" />
|
<ClInclude Include="minizip-ng\mz_strm.h" />
|
||||||
|
4
Externals/watcher/CMakeLists.txt
vendored
Normal file
4
Externals/watcher/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
add_library(watcher INTERFACE IMPORTED GLOBAL)
|
||||||
|
set_target_properties(watcher PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_LIST_DIR}/watcher/include
|
||||||
|
)
|
1
Externals/watcher/watcher
vendored
Submodule
1
Externals/watcher/watcher
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit b03bdcfc11549df595b77239cefe2643943a3e2f
|
@ -13,6 +13,9 @@
|
|||||||
<uses-feature
|
<uses-feature
|
||||||
android:name="android.hardware.gamepad"
|
android:name="android.hardware.gamepad"
|
||||||
android:required="false"/>
|
android:required="false"/>
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.microphone"
|
||||||
|
android:required="false"/>
|
||||||
<uses-feature
|
<uses-feature
|
||||||
android:name="android.software.leanback"
|
android:name="android.software.leanback"
|
||||||
android:required="false"/>
|
android:required="false"/>
|
||||||
@ -25,12 +28,8 @@
|
|||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA"/>
|
<uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA"/>
|
||||||
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA"/>
|
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA"/>
|
||||||
<uses-permission
|
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||||
android:name="android.permission.VIBRATE"
|
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||||
android:required="false"/>
|
|
||||||
<uses-permission
|
|
||||||
android:name="android.permission.RECORD_AUDIO"
|
|
||||||
android:required="false"/>
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".DolphinApplication"
|
android:name=".DolphinApplication"
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
package org.dolphinemu.dolphinemu.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.media.AudioManager
|
||||||
|
import androidx.annotation.Keep
|
||||||
|
import org.dolphinemu.dolphinemu.DolphinApplication
|
||||||
|
|
||||||
|
object AudioUtils {
|
||||||
|
@JvmStatic @Keep
|
||||||
|
fun getSampleRate(): Int =
|
||||||
|
getAudioServiceProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE, 48000)
|
||||||
|
|
||||||
|
@JvmStatic @Keep
|
||||||
|
fun getFramesPerBuffer(): Int =
|
||||||
|
getAudioServiceProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER, 256)
|
||||||
|
|
||||||
|
private fun getAudioServiceProperty(property: String, fallback: Int): Int {
|
||||||
|
return try {
|
||||||
|
val context = DolphinApplication.getAppContext()
|
||||||
|
val am = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||||
|
Integer.parseUnsignedInt(am.getProperty(property))
|
||||||
|
} catch (e: NullPointerException) {
|
||||||
|
fallback
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -122,6 +122,10 @@ static jmethodID s_permission_handler_request_record_audio_permission;
|
|||||||
|
|
||||||
static jmethodID s_runnable_run;
|
static jmethodID s_runnable_run;
|
||||||
|
|
||||||
|
static jclass s_audio_utils_class;
|
||||||
|
static jmethodID s_audio_utils_get_sample_rate;
|
||||||
|
static jmethodID s_audio_utils_get_frames_per_buffer;
|
||||||
|
|
||||||
namespace IDCache
|
namespace IDCache
|
||||||
{
|
{
|
||||||
JNIEnv* GetEnvForThread()
|
JNIEnv* GetEnvForThread()
|
||||||
@ -562,6 +566,21 @@ jmethodID GetRunnableRun()
|
|||||||
return s_runnable_run;
|
return s_runnable_run;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jclass GetAudioUtilsClass()
|
||||||
|
{
|
||||||
|
return s_audio_utils_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
jmethodID GetAudioUtilsGetSampleRate()
|
||||||
|
{
|
||||||
|
return s_audio_utils_get_sample_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
jmethodID GetAudioUtilsGetFramesPerBuffer()
|
||||||
|
{
|
||||||
|
return s_audio_utils_get_frames_per_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace IDCache
|
} // namespace IDCache
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -798,6 +817,13 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
|||||||
s_runnable_run = env->GetMethodID(runnable_class, "run", "()V");
|
s_runnable_run = env->GetMethodID(runnable_class, "run", "()V");
|
||||||
env->DeleteLocalRef(runnable_class);
|
env->DeleteLocalRef(runnable_class);
|
||||||
|
|
||||||
|
const jclass audio_utils_class = env->FindClass("org/dolphinemu/dolphinemu/utils/AudioUtils");
|
||||||
|
s_audio_utils_class = reinterpret_cast<jclass>(env->NewGlobalRef(audio_utils_class));
|
||||||
|
s_audio_utils_get_sample_rate = env->GetStaticMethodID(audio_utils_class, "getSampleRate", "()I");
|
||||||
|
s_audio_utils_get_frames_per_buffer =
|
||||||
|
env->GetStaticMethodID(audio_utils_class, "getFramesPerBuffer", "()I");
|
||||||
|
env->DeleteLocalRef(audio_utils_class);
|
||||||
|
|
||||||
return JNI_VERSION;
|
return JNI_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -834,5 +860,6 @@ JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved)
|
|||||||
env->DeleteGlobalRef(s_core_device_control_class);
|
env->DeleteGlobalRef(s_core_device_control_class);
|
||||||
env->DeleteGlobalRef(s_input_detector_class);
|
env->DeleteGlobalRef(s_input_detector_class);
|
||||||
env->DeleteGlobalRef(s_permission_handler_class);
|
env->DeleteGlobalRef(s_permission_handler_class);
|
||||||
|
env->DeleteGlobalRef(s_audio_utils_class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,4 +121,8 @@ jmethodID GetPermissionHandlerRequestRecordAudioPermission();
|
|||||||
|
|
||||||
jmethodID GetRunnableRun();
|
jmethodID GetRunnableRun();
|
||||||
|
|
||||||
|
jclass GetAudioUtilsClass();
|
||||||
|
jmethodID GetAudioUtilsGetSampleRate();
|
||||||
|
jmethodID GetAudioUtilsGetFramesPerBuffer();
|
||||||
|
|
||||||
} // namespace IDCache
|
} // namespace IDCache
|
||||||
|
@ -57,17 +57,17 @@ PRIVATE
|
|||||||
|
|
||||||
target_include_directories(main
|
target_include_directories(main
|
||||||
PRIVATE
|
PRIVATE
|
||||||
${CMAKE_SOURCE_DIR}/Externals/libadrenotools/include
|
${CMAKE_CURRENT_SOURCE_DIR}/../../../Externals/libadrenotools/include
|
||||||
${CMAKE_SOURCE_DIR}/Externals/VulkanMemoryAllocator/include
|
${CMAKE_CURRENT_SOURCE_DIR}/../../../Externals/VulkanMemoryAllocator/include
|
||||||
)
|
)
|
||||||
|
|
||||||
file(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/Source/Android/app/src/main/assets/)
|
file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../../Source/Android/app/src/main/assets/)
|
||||||
file(REMOVE_RECURSE ${CMAKE_SOURCE_DIR}/Source/Android/app/src/main/assets/Sys/)
|
file(REMOVE_RECURSE ${CMAKE_CURRENT_SOURCE_DIR}/../../../Source/Android/app/src/main/assets/Sys/)
|
||||||
file(COPY ${CMAKE_SOURCE_DIR}/Data/Sys DESTINATION ${CMAKE_SOURCE_DIR}/Source/Android/app/src/main/assets/)
|
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/../../../Data/Sys DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/../../../Source/Android/app/src/main/assets/)
|
||||||
|
|
||||||
# Delete folders that aren't used by the Android version of Dolphin
|
# Delete folders that aren't used by the Android version of Dolphin
|
||||||
file(REMOVE_RECURSE ${CMAKE_SOURCE_DIR}/Source/Android/app/src/main/assets/Sys/Resources/)
|
file(REMOVE_RECURSE ${CMAKE_CURRENT_SOURCE_DIR}/../../../Source/Android/app/src/main/assets/Sys/Resources/)
|
||||||
file(REMOVE_RECURSE ${CMAKE_SOURCE_DIR}/Source/Android/app/src/main/assets/Sys/Themes/)
|
file(REMOVE_RECURSE ${CMAKE_CURRENT_SOURCE_DIR}/../../../Source/Android/app/src/main/assets/Sys/Themes/)
|
||||||
|
|
||||||
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} main)
|
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} main)
|
||||||
|
|
||||||
|
@ -55,14 +55,14 @@ JNIEXPORT jboolean JNICALL
|
|||||||
Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_ControlGroup_getEnabled(
|
Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_ControlGroup_getEnabled(
|
||||||
JNIEnv* env, jobject obj)
|
JNIEnv* env, jobject obj)
|
||||||
{
|
{
|
||||||
return static_cast<jboolean>(GetPointer(env, obj)->enabled);
|
return static_cast<jboolean>(GetPointer(env, obj)->enabled.GetValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_ControlGroup_setEnabled(
|
Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_ControlGroup_setEnabled(
|
||||||
JNIEnv* env, jobject obj, jboolean value)
|
JNIEnv* env, jobject obj, jboolean value)
|
||||||
{
|
{
|
||||||
GetPointer(env, obj)->enabled = value;
|
GetPointer(env, obj)->enabled.SetValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "AudioCommon/WASAPIStream.h"
|
#include "AudioCommon/WASAPIStream.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
|
#include "Common/TimeUtil.h"
|
||||||
#include "Core/Config/MainSettings.h"
|
#include "Core/Config/MainSettings.h"
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/System.h"
|
#include "Core/System.h"
|
||||||
@ -166,7 +167,8 @@ void UpdateSoundStream(Core::System& system)
|
|||||||
|
|
||||||
if (sound_stream)
|
if (sound_stream)
|
||||||
{
|
{
|
||||||
int volume = Config::Get(Config::MAIN_AUDIO_MUTED) ? 0 : Config::Get(Config::MAIN_AUDIO_VOLUME);
|
int const volume =
|
||||||
|
Config::Get(Config::MAIN_AUDIO_MUTED) ? 0 : Config::Get(Config::MAIN_AUDIO_VOLUME);
|
||||||
sound_stream->SetVolume(volume);
|
sound_stream->SetVolume(volume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,7 +194,7 @@ void SetSoundStreamRunning(Core::System& system, bool running)
|
|||||||
|
|
||||||
void SendAIBuffer(Core::System& system, const short* samples, unsigned int num_samples)
|
void SendAIBuffer(Core::System& system, const short* samples, unsigned int num_samples)
|
||||||
{
|
{
|
||||||
SoundStream* sound_stream = system.GetSoundStream();
|
const SoundStream* const sound_stream = system.GetSoundStream();
|
||||||
|
|
||||||
if (!sound_stream)
|
if (!sound_stream)
|
||||||
return;
|
return;
|
||||||
@ -212,14 +214,17 @@ void SendAIBuffer(Core::System& system, const short* samples, unsigned int num_s
|
|||||||
|
|
||||||
void StartAudioDump(Core::System& system)
|
void StartAudioDump(Core::System& system)
|
||||||
{
|
{
|
||||||
SoundStream* sound_stream = system.GetSoundStream();
|
const SoundStream* const sound_stream = system.GetSoundStream();
|
||||||
|
|
||||||
std::time_t start_time = std::time(nullptr);
|
std::time_t const start_time = std::time(nullptr);
|
||||||
|
|
||||||
std::string path_prefix = File::GetUserPath(D_DUMPAUDIO_IDX) + SConfig::GetInstance().GetGameID();
|
std::string path_prefix = File::GetUserPath(D_DUMPAUDIO_IDX) + SConfig::GetInstance().GetGameID();
|
||||||
|
|
||||||
std::string base_name =
|
const auto local_time = Common::LocalTime(start_time);
|
||||||
fmt::format("{}_{:%Y-%m-%d_%H-%M-%S}", path_prefix, fmt::localtime(start_time));
|
if (!local_time)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string base_name = fmt::format("{}_{:%Y-%m-%d_%H-%M-%S}", path_prefix, *local_time);
|
||||||
|
|
||||||
const std::string audio_file_name_dtk = fmt::format("{}_dtkdump.wav", base_name);
|
const std::string audio_file_name_dtk = fmt::format("{}_dtkdump.wav", base_name);
|
||||||
const std::string audio_file_name_dsp = fmt::format("{}_dspdump.wav", base_name);
|
const std::string audio_file_name_dsp = fmt::format("{}_dspdump.wav", base_name);
|
||||||
@ -232,7 +237,7 @@ void StartAudioDump(Core::System& system)
|
|||||||
|
|
||||||
void StopAudioDump(Core::System& system)
|
void StopAudioDump(Core::System& system)
|
||||||
{
|
{
|
||||||
SoundStream* sound_stream = system.GetSoundStream();
|
const SoundStream* const sound_stream = system.GetSoundStream();
|
||||||
|
|
||||||
if (!sound_stream)
|
if (!sound_stream)
|
||||||
return;
|
return;
|
||||||
@ -265,7 +270,7 @@ void DecreaseVolume(Core::System& system, unsigned short offset)
|
|||||||
|
|
||||||
void ToggleMuteVolume(Core::System& system)
|
void ToggleMuteVolume(Core::System& system)
|
||||||
{
|
{
|
||||||
bool isMuted = Config::Get(Config::MAIN_AUDIO_MUTED);
|
bool const isMuted = Config::Get(Config::MAIN_AUDIO_MUTED);
|
||||||
Config::SetBaseOrCurrent(Config::MAIN_AUDIO_MUTED, !isMuted);
|
Config::SetBaseOrCurrent(Config::MAIN_AUDIO_MUTED, !isMuted);
|
||||||
UpdateSoundStream(system);
|
UpdateSoundStream(system);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
#include "Common/Event.h"
|
#include "Common/Event.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/ScopeGuard.h"
|
#include "Common/ScopeGuard.h"
|
||||||
#include "Common/Thread.h"
|
|
||||||
#include "Core/Config/MainSettings.h"
|
#include "Core/Config/MainSettings.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -23,7 +22,7 @@ constexpr u32 BUFFER_SAMPLES = 512;
|
|||||||
long CubebStream::DataCallback(cubeb_stream* stream, void* user_data, const void* /*input_buffer*/,
|
long CubebStream::DataCallback(cubeb_stream* stream, void* user_data, const void* /*input_buffer*/,
|
||||||
void* output_buffer, long num_frames)
|
void* output_buffer, long num_frames)
|
||||||
{
|
{
|
||||||
auto* self = static_cast<CubebStream*>(user_data);
|
const auto* const self = static_cast<CubebStream*>(user_data);
|
||||||
|
|
||||||
if (self->m_stereo)
|
if (self->m_stereo)
|
||||||
self->m_mixer->Mix(static_cast<short*>(output_buffer), num_frames);
|
self->m_mixer->Mix(static_cast<short*>(output_buffer), num_frames);
|
||||||
@ -44,7 +43,7 @@ CubebStream::CubebStream()
|
|||||||
Common::Event sync_event;
|
Common::Event sync_event;
|
||||||
m_work_queue.Push([this, &sync_event] {
|
m_work_queue.Push([this, &sync_event] {
|
||||||
Common::ScopeGuard sync_event_guard([&sync_event] { sync_event.Set(); });
|
Common::ScopeGuard sync_event_guard([&sync_event] { sync_event.Set(); });
|
||||||
auto result = ::CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
|
auto const result = CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
|
||||||
m_coinit_success = result == S_OK;
|
m_coinit_success = result == S_OK;
|
||||||
m_should_couninit = result == S_OK || result == S_FALSE;
|
m_should_couninit = result == S_OK || result == S_FALSE;
|
||||||
});
|
});
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -182,7 +182,8 @@ std::size_t Mixer::MixSurround(float* samples, std::size_t num_samples)
|
|||||||
|
|
||||||
memset(samples, 0, num_samples * SURROUND_CHANNELS * sizeof(float));
|
memset(samples, 0, num_samples * SURROUND_CHANNELS * sizeof(float));
|
||||||
|
|
||||||
std::size_t needed_frames = m_surround_decoder.QueryFramesNeededForSurroundOutput(num_samples);
|
std::size_t const needed_frames =
|
||||||
|
m_surround_decoder.QueryFramesNeededForSurroundOutput(num_samples);
|
||||||
|
|
||||||
constexpr std::size_t max_samples = 0x8000;
|
constexpr std::size_t max_samples = 0x8000;
|
||||||
ASSERT_MSG(AUDIO, needed_frames <= max_samples,
|
ASSERT_MSG(AUDIO, needed_frames <= max_samples,
|
||||||
@ -190,7 +191,7 @@ std::size_t Mixer::MixSurround(float* samples, std::size_t num_samples)
|
|||||||
needed_frames, max_samples);
|
needed_frames, max_samples);
|
||||||
|
|
||||||
std::array<s16, max_samples> buffer;
|
std::array<s16, max_samples> buffer;
|
||||||
std::size_t available_frames = Mix(buffer.data(), static_cast<std::size_t>(needed_frames));
|
std::size_t const available_frames = Mix(buffer.data(), static_cast<std::size_t>(needed_frames));
|
||||||
if (available_frames != needed_frames)
|
if (available_frames != needed_frames)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(AUDIO,
|
ERROR_LOG_FMT(AUDIO,
|
||||||
@ -229,7 +230,7 @@ void Mixer::PushSamples(const s16* samples, std::size_t num_samples)
|
|||||||
if (m_log_dsp_audio)
|
if (m_log_dsp_audio)
|
||||||
{
|
{
|
||||||
const s32 sample_rate_divisor = m_dma_mixer.GetInputSampleRateDivisor();
|
const s32 sample_rate_divisor = m_dma_mixer.GetInputSampleRateDivisor();
|
||||||
auto volume = m_dma_mixer.GetVolume();
|
auto const volume = m_dma_mixer.GetVolume();
|
||||||
m_wave_writer_dsp.AddStereoSamplesBE(samples, static_cast<u32>(num_samples),
|
m_wave_writer_dsp.AddStereoSamplesBE(samples, static_cast<u32>(num_samples),
|
||||||
sample_rate_divisor, volume.first, volume.second);
|
sample_rate_divisor, volume.first, volume.second);
|
||||||
}
|
}
|
||||||
@ -241,7 +242,7 @@ void Mixer::PushStreamingSamples(const s16* samples, std::size_t num_samples)
|
|||||||
if (m_log_dtk_audio)
|
if (m_log_dtk_audio)
|
||||||
{
|
{
|
||||||
const s32 sample_rate_divisor = m_streaming_mixer.GetInputSampleRateDivisor();
|
const s32 sample_rate_divisor = m_streaming_mixer.GetInputSampleRateDivisor();
|
||||||
auto volume = m_streaming_mixer.GetVolume();
|
auto const volume = m_streaming_mixer.GetVolume();
|
||||||
m_wave_writer_dtk.AddStereoSamplesBE(samples, static_cast<u32>(num_samples),
|
m_wave_writer_dtk.AddStereoSamplesBE(samples, static_cast<u32>(num_samples),
|
||||||
sample_rate_divisor, volume.first, volume.second);
|
sample_rate_divisor, volume.first, volume.second);
|
||||||
}
|
}
|
||||||
@ -286,7 +287,8 @@ void Mixer::PushSkylanderPortalSamples(const u8* samples, std::size_t num_sample
|
|||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < num_samples; ++i)
|
for (std::size_t i = 0; i < num_samples; ++i)
|
||||||
{
|
{
|
||||||
s16 sample = static_cast<u16>(samples[i * 2 + 1]) << 8 | static_cast<u16>(samples[i * 2]);
|
s16 const sample =
|
||||||
|
static_cast<u16>(samples[i * 2 + 1]) << 8 | static_cast<u16>(samples[i * 2]);
|
||||||
samples_stereo[i * 2] = sample;
|
samples_stereo[i * 2] = sample;
|
||||||
samples_stereo[i * 2 + 1] = sample;
|
samples_stereo[i * 2 + 1] = sample;
|
||||||
}
|
}
|
||||||
@ -335,7 +337,8 @@ void Mixer::StartLogDTKAudio(const std::string& filename)
|
|||||||
{
|
{
|
||||||
if (!m_log_dtk_audio)
|
if (!m_log_dtk_audio)
|
||||||
{
|
{
|
||||||
bool success = m_wave_writer_dtk.Start(filename, m_streaming_mixer.GetInputSampleRateDivisor());
|
bool const success =
|
||||||
|
m_wave_writer_dtk.Start(filename, m_streaming_mixer.GetInputSampleRateDivisor());
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
m_log_dtk_audio = true;
|
m_log_dtk_audio = true;
|
||||||
@ -372,7 +375,7 @@ void Mixer::StartLogDSPAudio(const std::string& filename)
|
|||||||
{
|
{
|
||||||
if (!m_log_dsp_audio)
|
if (!m_log_dsp_audio)
|
||||||
{
|
{
|
||||||
bool success = m_wave_writer_dsp.Start(filename, m_dma_mixer.GetInputSampleRateDivisor());
|
bool const success = m_wave_writer_dsp.Start(filename, m_dma_mixer.GetInputSampleRateDivisor());
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
m_log_dsp_audio = true;
|
m_log_dsp_audio = true;
|
||||||
@ -494,10 +497,10 @@ void Mixer::MixerFifo::Enqueue()
|
|||||||
0.0002984010f, 0.0002102045f, 0.0001443499f, 0.0000961509f, 0.0000616906f, 0.0000377350f,
|
0.0002984010f, 0.0002102045f, 0.0001443499f, 0.0000961509f, 0.0000616906f, 0.0000377350f,
|
||||||
0.0000216492f, 0.0000113187f, 0.0000050749f, 0.0000016272f};
|
0.0000216492f, 0.0000113187f, 0.0000050749f, 0.0000016272f};
|
||||||
|
|
||||||
const std::size_t head = m_queue_head.load(std::memory_order_acquire);
|
std::size_t const head = m_queue_head.load(std::memory_order_acquire);
|
||||||
|
|
||||||
// Check if we run out of space in the circular queue. (rare)
|
// Check if we run out of space in the circular queue. (rare)
|
||||||
std::size_t next_head = (head + 1) & GRANULE_QUEUE_MASK;
|
std::size_t const next_head = (head + 1) & GRANULE_QUEUE_MASK;
|
||||||
if (next_head == m_queue_tail.load(std::memory_order_acquire))
|
if (next_head == m_queue_tail.load(std::memory_order_acquire))
|
||||||
{
|
{
|
||||||
WARN_LOG_FMT(AUDIO,
|
WARN_LOG_FMT(AUDIO,
|
||||||
|
@ -3,11 +3,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include "AudioCommon/SurroundDecoder.h"
|
#include "AudioCommon/SurroundDecoder.h"
|
||||||
#include "AudioCommon/WaveFile.h"
|
#include "AudioCommon/WaveFile.h"
|
||||||
|
@ -76,7 +76,7 @@ static bool InitLibrary()
|
|||||||
|
|
||||||
if (!InitFunctions())
|
if (!InitFunctions())
|
||||||
{
|
{
|
||||||
::FreeLibrary(s_openal_dll);
|
FreeLibrary(s_openal_dll);
|
||||||
s_openal_dll = nullptr;
|
s_openal_dll = nullptr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -168,7 +168,7 @@ bool OpenALStream::SetRunning(bool running)
|
|||||||
|
|
||||||
static ALenum CheckALError(const char* desc)
|
static ALenum CheckALError(const char* desc)
|
||||||
{
|
{
|
||||||
ALenum err = palGetError();
|
ALenum const err = palGetError();
|
||||||
|
|
||||||
if (err != AL_NO_ERROR)
|
if (err != AL_NO_ERROR)
|
||||||
{
|
{
|
||||||
@ -211,16 +211,16 @@ void OpenALStream::SoundLoop()
|
|||||||
{
|
{
|
||||||
Common::SetCurrentThreadName("Audio thread - openal");
|
Common::SetCurrentThreadName("Audio thread - openal");
|
||||||
|
|
||||||
bool float32_capable = palIsExtensionPresent("AL_EXT_float32") != 0;
|
bool const float32_capable = palIsExtensionPresent("AL_EXT_float32") != 0;
|
||||||
bool surround_capable = palIsExtensionPresent("AL_EXT_MCFORMATS") || IsCreativeXFi();
|
bool const surround_capable = palIsExtensionPresent("AL_EXT_MCFORMATS") || IsCreativeXFi();
|
||||||
bool use_surround = Config::ShouldUseDPL2Decoder() && surround_capable;
|
bool use_surround = Config::ShouldUseDPL2Decoder() && surround_capable;
|
||||||
|
|
||||||
// As there is no extension to check for 32-bit fixed point support
|
// As there is no extension to check for 32-bit fixed point support
|
||||||
// and we know that only a X-Fi with hardware OpenAL supports it,
|
// and we know that only a X-Fi with hardware OpenAL supports it,
|
||||||
// we just check if one is being used.
|
// we just check if one is being used.
|
||||||
bool fixed32_capable = IsCreativeXFi();
|
bool const fixed32_capable = IsCreativeXFi();
|
||||||
|
|
||||||
u32 frequency = m_mixer->GetSampleRate();
|
u32 const frequency = m_mixer->GetSampleRate();
|
||||||
|
|
||||||
u32 frames_per_buffer;
|
u32 frames_per_buffer;
|
||||||
// Can't have zero samples per buffer
|
// Can't have zero samples per buffer
|
||||||
@ -288,12 +288,12 @@ void OpenALStream::SoundLoop()
|
|||||||
num_buffers_queued -= num_buffers_processed;
|
num_buffers_queued -= num_buffers_processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int min_frames = frames_per_buffer;
|
unsigned int const min_frames = frames_per_buffer;
|
||||||
|
|
||||||
if (use_surround)
|
if (use_surround)
|
||||||
{
|
{
|
||||||
std::array<float, OAL_MAX_FRAMES * SURROUND_CHANNELS> dpl2;
|
std::array<float, OAL_MAX_FRAMES * SURROUND_CHANNELS> dpl2;
|
||||||
u32 rendered_frames = static_cast<u32>(m_mixer->MixSurround(dpl2.data(), min_frames));
|
u32 const rendered_frames = static_cast<u32>(m_mixer->MixSurround(dpl2.data(), min_frames));
|
||||||
|
|
||||||
if (rendered_frames < min_frames)
|
if (rendered_frames < min_frames)
|
||||||
continue;
|
continue;
|
||||||
@ -351,7 +351,8 @@ void OpenALStream::SoundLoop()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u32 rendered_frames = static_cast<u32>(m_mixer->Mix(m_realtime_buffer.data(), min_frames));
|
u32 const rendered_frames =
|
||||||
|
static_cast<u32>(m_mixer->Mix(m_realtime_buffer.data(), min_frames));
|
||||||
|
|
||||||
if (!rendered_frames)
|
if (!rendered_frames)
|
||||||
continue;
|
continue;
|
||||||
|
@ -7,9 +7,6 @@
|
|||||||
|
|
||||||
#include "AudioCommon/SoundStream.h"
|
#include "AudioCommon/SoundStream.h"
|
||||||
#include "Common/Event.h"
|
#include "Common/Event.h"
|
||||||
#include "Core/Core.h"
|
|
||||||
#include "Core/HW/AudioInterface.h"
|
|
||||||
#include "Core/HW/SystemTimers.h"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <al.h>
|
#include <al.h>
|
||||||
|
@ -8,40 +8,27 @@
|
|||||||
|
|
||||||
#include <SLES/OpenSLES.h>
|
#include <SLES/OpenSLES.h>
|
||||||
#include <SLES/OpenSLES_Android.h>
|
#include <SLES/OpenSLES_Android.h>
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
|
#include "jni/AndroidCommon/IDCache.h"
|
||||||
|
|
||||||
// engine interfaces
|
void OpenSLESStream::BQPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void* context)
|
||||||
static SLObjectItf engineObject;
|
|
||||||
static SLEngineItf engineEngine;
|
|
||||||
static SLObjectItf outputMixObject;
|
|
||||||
|
|
||||||
// buffer queue player interfaces
|
|
||||||
static SLObjectItf bqPlayerObject = nullptr;
|
|
||||||
static SLPlayItf bqPlayerPlay;
|
|
||||||
static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
|
|
||||||
static SLVolumeItf bqPlayerVolume;
|
|
||||||
static Mixer* g_mixer;
|
|
||||||
#define BUFFER_SIZE 512
|
|
||||||
#define BUFFER_SIZE_IN_SAMPLES (BUFFER_SIZE / 2)
|
|
||||||
|
|
||||||
// Double buffering.
|
|
||||||
static short buffer[2][BUFFER_SIZE];
|
|
||||||
static int curBuffer = 0;
|
|
||||||
|
|
||||||
static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void* context)
|
|
||||||
{
|
{
|
||||||
ASSERT(bq == bqPlayerBufferQueue);
|
reinterpret_cast<OpenSLESStream*>(context)->PushSamples(bq);
|
||||||
ASSERT(nullptr == context);
|
}
|
||||||
|
|
||||||
|
void OpenSLESStream::PushSamples(SLAndroidSimpleBufferQueueItf bq)
|
||||||
|
{
|
||||||
|
ASSERT(bq == m_bq_player_buffer_queue);
|
||||||
|
|
||||||
// Render to the fresh buffer
|
// Render to the fresh buffer
|
||||||
g_mixer->Mix(reinterpret_cast<short*>(buffer[curBuffer]), BUFFER_SIZE_IN_SAMPLES);
|
m_mixer->Mix(m_buffer[m_current_buffer].data(), m_frames_per_buffer);
|
||||||
SLresult result =
|
SLresult result = (*bq)->Enqueue(bq, m_buffer[m_current_buffer].data(), m_bytes_per_buffer);
|
||||||
(*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[curBuffer], sizeof(buffer[0]));
|
m_current_buffer ^= 1; // Switch buffer
|
||||||
curBuffer ^= 1; // Switch buffer
|
|
||||||
|
|
||||||
// Comment from sample code:
|
// Comment from sample code:
|
||||||
// the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
|
// the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
|
||||||
@ -51,61 +38,78 @@ static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void* context)
|
|||||||
|
|
||||||
bool OpenSLESStream::Init()
|
bool OpenSLESStream::Init()
|
||||||
{
|
{
|
||||||
|
JNIEnv* env = IDCache::GetEnvForThread();
|
||||||
|
jclass audio_utils = IDCache::GetAudioUtilsClass();
|
||||||
|
const SLuint32 sample_rate =
|
||||||
|
env->CallStaticIntMethod(audio_utils, IDCache::GetAudioUtilsGetSampleRate());
|
||||||
|
m_frames_per_buffer =
|
||||||
|
env->CallStaticIntMethod(audio_utils, IDCache::GetAudioUtilsGetFramesPerBuffer());
|
||||||
|
|
||||||
|
INFO_LOG_FMT(AUDIO, "OpenSLES configuration: {} Hz, {} frames per buffer", sample_rate,
|
||||||
|
m_frames_per_buffer);
|
||||||
|
|
||||||
|
constexpr SLuint32 channels = 2;
|
||||||
|
const SLuint32 samples_per_buffer = m_frames_per_buffer * channels;
|
||||||
|
m_bytes_per_buffer = m_frames_per_buffer * channels * sizeof(m_buffer[0][0]);
|
||||||
|
|
||||||
|
for (std::vector<short>& buffer : m_buffer)
|
||||||
|
buffer.resize(samples_per_buffer);
|
||||||
|
|
||||||
SLresult result;
|
SLresult result;
|
||||||
// create engine
|
// create engine
|
||||||
result = slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr);
|
result = slCreateEngine(&m_engine_object, 0, nullptr, 0, nullptr, nullptr);
|
||||||
ASSERT(SL_RESULT_SUCCESS == result);
|
ASSERT(SL_RESULT_SUCCESS == result);
|
||||||
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
|
result = (*m_engine_object)->Realize(m_engine_object, SL_BOOLEAN_FALSE);
|
||||||
ASSERT(SL_RESULT_SUCCESS == result);
|
ASSERT(SL_RESULT_SUCCESS == result);
|
||||||
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
|
result = (*m_engine_object)->GetInterface(m_engine_object, SL_IID_ENGINE, &m_engine_engine);
|
||||||
ASSERT(SL_RESULT_SUCCESS == result);
|
ASSERT(SL_RESULT_SUCCESS == result);
|
||||||
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, 0, 0);
|
result = (*m_engine_engine)->CreateOutputMix(m_engine_engine, &m_output_mix_object, 0, 0, 0);
|
||||||
ASSERT(SL_RESULT_SUCCESS == result);
|
ASSERT(SL_RESULT_SUCCESS == result);
|
||||||
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
|
result = (*m_output_mix_object)->Realize(m_output_mix_object, SL_BOOLEAN_FALSE);
|
||||||
ASSERT(SL_RESULT_SUCCESS == result);
|
ASSERT(SL_RESULT_SUCCESS == result);
|
||||||
|
|
||||||
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
|
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
|
||||||
SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM,
|
SLDataFormat_PCM format_pcm = {
|
||||||
2,
|
SL_DATAFORMAT_PCM, channels,
|
||||||
m_mixer->GetSampleRate() * 1000,
|
sample_rate * 1000, SL_PCMSAMPLEFORMAT_FIXED_16,
|
||||||
SL_PCMSAMPLEFORMAT_FIXED_16,
|
SL_PCMSAMPLEFORMAT_FIXED_16, SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
|
||||||
SL_PCMSAMPLEFORMAT_FIXED_16,
|
|
||||||
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
|
|
||||||
SL_BYTEORDER_LITTLEENDIAN};
|
SL_BYTEORDER_LITTLEENDIAN};
|
||||||
|
|
||||||
SLDataSource audioSrc = {&loc_bufq, &format_pcm};
|
SLDataSource audioSrc = {&loc_bufq, &format_pcm};
|
||||||
|
|
||||||
// configure audio sink
|
// configure audio sink
|
||||||
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
|
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, m_output_mix_object};
|
||||||
SLDataSink audioSnk = {&loc_outmix, nullptr};
|
SLDataSink audioSnk = {&loc_outmix, nullptr};
|
||||||
|
|
||||||
// create audio player
|
// create audio player
|
||||||
const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME};
|
const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME};
|
||||||
const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
|
const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
|
||||||
result =
|
result = (*m_engine_engine)
|
||||||
(*engineEngine)
|
->CreateAudioPlayer(m_engine_engine, &m_bq_player_object, &audioSrc, &audioSnk, 2,
|
||||||
->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 2, ids, req);
|
ids, req);
|
||||||
ASSERT(SL_RESULT_SUCCESS == result);
|
ASSERT(SL_RESULT_SUCCESS == result);
|
||||||
|
|
||||||
result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
|
result = (*m_bq_player_object)->Realize(m_bq_player_object, SL_BOOLEAN_FALSE);
|
||||||
ASSERT(SL_RESULT_SUCCESS == result);
|
ASSERT(SL_RESULT_SUCCESS == result);
|
||||||
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
|
result = (*m_bq_player_object)->GetInterface(m_bq_player_object, SL_IID_PLAY, &m_bq_player_play);
|
||||||
|
ASSERT(SL_RESULT_SUCCESS == result);
|
||||||
|
result = (*m_bq_player_object)
|
||||||
|
->GetInterface(m_bq_player_object, SL_IID_BUFFERQUEUE, &m_bq_player_buffer_queue);
|
||||||
ASSERT(SL_RESULT_SUCCESS == result);
|
ASSERT(SL_RESULT_SUCCESS == result);
|
||||||
result =
|
result =
|
||||||
(*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, &bqPlayerBufferQueue);
|
(*m_bq_player_object)->GetInterface(m_bq_player_object, SL_IID_VOLUME, &m_bq_player_volume);
|
||||||
ASSERT(SL_RESULT_SUCCESS == result);
|
ASSERT(SL_RESULT_SUCCESS == result);
|
||||||
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
|
result = (*m_bq_player_buffer_queue)
|
||||||
|
->RegisterCallback(m_bq_player_buffer_queue, BQPlayerCallback, this);
|
||||||
ASSERT(SL_RESULT_SUCCESS == result);
|
ASSERT(SL_RESULT_SUCCESS == result);
|
||||||
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, nullptr);
|
result = (*m_bq_player_play)->SetPlayState(m_bq_player_play, SL_PLAYSTATE_PLAYING);
|
||||||
ASSERT(SL_RESULT_SUCCESS == result);
|
|
||||||
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
|
|
||||||
ASSERT(SL_RESULT_SUCCESS == result);
|
ASSERT(SL_RESULT_SUCCESS == result);
|
||||||
|
|
||||||
// Render and enqueue a first buffer.
|
// Render and enqueue a first buffer.
|
||||||
curBuffer ^= 1;
|
m_current_buffer ^= 1;
|
||||||
g_mixer = m_mixer.get();
|
|
||||||
|
|
||||||
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[0], sizeof(buffer[0]));
|
result = (*m_bq_player_buffer_queue)
|
||||||
|
->Enqueue(m_bq_player_buffer_queue, m_buffer[0].data(), m_bytes_per_buffer);
|
||||||
if (SL_RESULT_SUCCESS != result)
|
if (SL_RESULT_SUCCESS != result)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -114,39 +118,39 @@ bool OpenSLESStream::Init()
|
|||||||
|
|
||||||
OpenSLESStream::~OpenSLESStream()
|
OpenSLESStream::~OpenSLESStream()
|
||||||
{
|
{
|
||||||
if (bqPlayerObject != nullptr)
|
if (m_bq_player_object != nullptr)
|
||||||
{
|
{
|
||||||
(*bqPlayerObject)->Destroy(bqPlayerObject);
|
(*m_bq_player_object)->Destroy(m_bq_player_object);
|
||||||
bqPlayerObject = nullptr;
|
m_bq_player_object = nullptr;
|
||||||
bqPlayerPlay = nullptr;
|
m_bq_player_play = nullptr;
|
||||||
bqPlayerBufferQueue = nullptr;
|
m_bq_player_buffer_queue = nullptr;
|
||||||
bqPlayerVolume = nullptr;
|
m_bq_player_volume = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outputMixObject != nullptr)
|
if (m_output_mix_object != nullptr)
|
||||||
{
|
{
|
||||||
(*outputMixObject)->Destroy(outputMixObject);
|
(*m_output_mix_object)->Destroy(m_output_mix_object);
|
||||||
outputMixObject = nullptr;
|
m_output_mix_object = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (engineObject != nullptr)
|
if (m_engine_object != nullptr)
|
||||||
{
|
{
|
||||||
(*engineObject)->Destroy(engineObject);
|
(*m_engine_object)->Destroy(m_engine_object);
|
||||||
engineObject = nullptr;
|
m_engine_object = nullptr;
|
||||||
engineEngine = nullptr;
|
m_engine_engine = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenSLESStream::SetRunning(bool running)
|
bool OpenSLESStream::SetRunning(bool running)
|
||||||
{
|
{
|
||||||
SLuint32 new_state = running ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_PAUSED;
|
SLuint32 new_state = running ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_PAUSED;
|
||||||
return (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, new_state) == SL_RESULT_SUCCESS;
|
return (*m_bq_player_play)->SetPlayState(m_bq_player_play, new_state) == SL_RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenSLESStream::SetVolume(int volume)
|
void OpenSLESStream::SetVolume(int volume)
|
||||||
{
|
{
|
||||||
const SLmillibel attenuation =
|
const SLmillibel attenuation =
|
||||||
volume <= 0 ? SL_MILLIBEL_MIN : static_cast<SLmillibel>(2000 * std::log10(volume / 100.0f));
|
volume <= 0 ? SL_MILLIBEL_MIN : static_cast<SLmillibel>(2000 * std::log10(volume / 100.0f));
|
||||||
(*bqPlayerVolume)->SetVolumeLevel(bqPlayerVolume, attenuation);
|
(*m_bq_player_volume)->SetVolumeLevel(m_bq_player_volume, attenuation);
|
||||||
}
|
}
|
||||||
#endif // HAVE_OPENSL_ES
|
#endif // HAVE_OPENSL_ES
|
||||||
|
@ -3,10 +3,15 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <thread>
|
#ifdef HAVE_OPENSL_ES
|
||||||
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <SLES/OpenSLES.h>
|
||||||
|
#include <SLES/OpenSLES_Android.h>
|
||||||
|
#endif // HAVE_OPENSL_ES
|
||||||
|
|
||||||
#include "AudioCommon/SoundStream.h"
|
#include "AudioCommon/SoundStream.h"
|
||||||
#include "Common/Event.h"
|
|
||||||
|
|
||||||
class OpenSLESStream final : public SoundStream
|
class OpenSLESStream final : public SoundStream
|
||||||
{
|
{
|
||||||
@ -19,7 +24,25 @@ public:
|
|||||||
static bool IsValid() { return true; }
|
static bool IsValid() { return true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::thread thread;
|
static void BQPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void* context);
|
||||||
Common::Event soundSyncEvent;
|
void PushSamples(SLAndroidSimpleBufferQueueItf bq);
|
||||||
|
|
||||||
|
// engine interfaces
|
||||||
|
SLObjectItf m_engine_object;
|
||||||
|
SLEngineItf m_engine_engine;
|
||||||
|
SLObjectItf m_output_mix_object;
|
||||||
|
|
||||||
|
// buffer queue player interfaces
|
||||||
|
SLObjectItf m_bq_player_object = nullptr;
|
||||||
|
SLPlayItf m_bq_player_play;
|
||||||
|
SLAndroidSimpleBufferQueueItf m_bq_player_buffer_queue;
|
||||||
|
SLVolumeItf m_bq_player_volume;
|
||||||
|
|
||||||
|
SLuint32 m_frames_per_buffer;
|
||||||
|
SLuint32 m_bytes_per_buffer;
|
||||||
|
|
||||||
|
// Double buffering.
|
||||||
|
std::array<std::vector<short>, 2> m_buffer;
|
||||||
|
int m_current_buffer = 0;
|
||||||
#endif // HAVE_OPENSL_ES
|
#endif // HAVE_OPENSL_ES
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "AudioCommon/SoundStream.h"
|
#include "AudioCommon/SoundStream.h"
|
||||||
#include "Common/CommonTypes.h"
|
|
||||||
#include "Common/Flag.h"
|
#include "Common/Flag.h"
|
||||||
#include "Common/Thread.h"
|
#include "Common/Thread.h"
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ size_t SurroundDecoder::QueryFramesNeededForSurroundOutput(const size_t output_f
|
|||||||
if (m_decoded_fifo.size() < output_frames * SURROUND_CHANNELS)
|
if (m_decoded_fifo.size() < output_frames * SURROUND_CHANNELS)
|
||||||
{
|
{
|
||||||
// Output stereo frames needed to have at least the desired number of surround frames
|
// Output stereo frames needed to have at least the desired number of surround frames
|
||||||
size_t frames_needed = output_frames - m_decoded_fifo.size() / SURROUND_CHANNELS;
|
size_t const frames_needed = output_frames - m_decoded_fifo.size() / SURROUND_CHANNELS;
|
||||||
return frames_needed + m_frame_block_size - frames_needed % m_frame_block_size;
|
return frames_needed + m_frame_block_size - frames_needed % m_frame_block_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
#include <Audioclient.h>
|
#include <Audioclient.h>
|
||||||
#include <mmdeviceapi.h>
|
#include <mmdeviceapi.h>
|
||||||
#include <devpkey.h>
|
|
||||||
#include <functiondiscoverykeys_devpkey.h>
|
#include <functiondiscoverykeys_devpkey.h>
|
||||||
#include <wil/resource.h>
|
#include <wil/resource.h>
|
||||||
// clang-format on
|
// clang-format on
|
||||||
@ -159,7 +158,8 @@ ComPtr<IMMDevice> WASAPIStream::GetDeviceByName(std::string_view name)
|
|||||||
bool WASAPIStream::Init()
|
bool WASAPIStream::Init()
|
||||||
{
|
{
|
||||||
ASSERT(m_enumerator == nullptr);
|
ASSERT(m_enumerator == nullptr);
|
||||||
HRESULT result = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER,
|
HRESULT const result =
|
||||||
|
CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER,
|
||||||
IID_PPV_ARGS(m_enumerator.GetAddressOf()));
|
IID_PPV_ARGS(m_enumerator.GetAddressOf()));
|
||||||
|
|
||||||
if (!HandleWinAPI("Failed to create MMDeviceEnumerator", result))
|
if (!HandleWinAPI("Failed to create MMDeviceEnumerator", result))
|
||||||
|
@ -32,7 +32,7 @@ class WASAPIStream final : public SoundStream
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
public:
|
public:
|
||||||
explicit WASAPIStream();
|
explicit WASAPIStream();
|
||||||
~WASAPIStream();
|
~WASAPIStream() override;
|
||||||
bool Init() override;
|
bool Init() override;
|
||||||
bool SetRunning(bool running) override;
|
bool SetRunning(bool running) override;
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ if (APPLE AND ENABLE_QT)
|
|||||||
if (MACOS_CODE_SIGNING)
|
if (MACOS_CODE_SIGNING)
|
||||||
add_custom_command(TARGET build_final_bundle
|
add_custom_command(TARGET build_final_bundle
|
||||||
POST_BUILD
|
POST_BUILD
|
||||||
COMMAND "${CMAKE_SOURCE_DIR}/Tools/mac-codesign.sh"
|
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/../../Tools/mac-codesign.sh"
|
||||||
"-t"
|
"-t"
|
||||||
"${MACOS_CODE_SIGNING_IDENTITY}"
|
"${MACOS_CODE_SIGNING_IDENTITY}"
|
||||||
"${DOLPHIN_MAC_BUNDLE}/Contents/Helpers/Dolphin Updater.app")
|
"${DOLPHIN_MAC_BUNDLE}/Contents/Helpers/Dolphin Updater.app")
|
||||||
@ -79,9 +79,9 @@ if (APPLE AND ENABLE_QT)
|
|||||||
if (MACOS_CODE_SIGNING)
|
if (MACOS_CODE_SIGNING)
|
||||||
add_custom_command(TARGET build_final_bundle
|
add_custom_command(TARGET build_final_bundle
|
||||||
POST_BUILD
|
POST_BUILD
|
||||||
COMMAND "${CMAKE_SOURCE_DIR}/Tools/mac-codesign.sh"
|
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/../../Tools/mac-codesign.sh"
|
||||||
"-t"
|
"-t"
|
||||||
"-e" "${CMAKE_SOURCE_DIR}/Source/Core/DolphinQt/DolphinEmu$<$<CONFIG:Debug>:Debug>.entitlements"
|
"-e" "${CMAKE_CURRENT_SOURCE_DIR}/../../Source/Core/DolphinQt/DolphinEmu$<$<CONFIG:Debug>:Debug>.entitlements"
|
||||||
"${MACOS_CODE_SIGNING_IDENTITY}"
|
"${MACOS_CODE_SIGNING_IDENTITY}"
|
||||||
"${DOLPHIN_MAC_BUNDLE}")
|
"${DOLPHIN_MAC_BUNDLE}")
|
||||||
endif()
|
endif()
|
||||||
|
@ -31,7 +31,7 @@ public:
|
|||||||
{
|
{
|
||||||
m_active_block = &m_output_result.blocks.emplace_back(base_addr);
|
m_active_block = &m_output_result.blocks.emplace_back(base_addr);
|
||||||
}
|
}
|
||||||
virtual ~GekkoIRPlugin() = default;
|
~GekkoIRPlugin() override = default;
|
||||||
|
|
||||||
void OnDirectivePre(GekkoDirective directive) override;
|
void OnDirectivePre(GekkoDirective directive) override;
|
||||||
void OnDirectivePost(GekkoDirective directive) override;
|
void OnDirectivePost(GekkoDirective directive) override;
|
||||||
|
@ -64,6 +64,8 @@ add_library(common
|
|||||||
FatFsUtil.h
|
FatFsUtil.h
|
||||||
FileSearch.cpp
|
FileSearch.cpp
|
||||||
FileSearch.h
|
FileSearch.h
|
||||||
|
FilesystemWatcher.cpp
|
||||||
|
FilesystemWatcher.h
|
||||||
FileUtil.cpp
|
FileUtil.cpp
|
||||||
FileUtil.h
|
FileUtil.h
|
||||||
FixedSizeQueue.h
|
FixedSizeQueue.h
|
||||||
@ -176,7 +178,7 @@ PUBLIC
|
|||||||
enet::enet
|
enet::enet
|
||||||
fmt::fmt
|
fmt::fmt
|
||||||
MbedTLS::mbedtls
|
MbedTLS::mbedtls
|
||||||
minizip::minizip
|
minizip-ng::minizip-ng
|
||||||
sfml-network
|
sfml-network
|
||||||
|
|
||||||
PRIVATE
|
PRIVATE
|
||||||
@ -184,6 +186,7 @@ PRIVATE
|
|||||||
FatFs
|
FatFs
|
||||||
Iconv::Iconv
|
Iconv::Iconv
|
||||||
spng::spng
|
spng::spng
|
||||||
|
watcher
|
||||||
${VTUNE_LIBRARIES}
|
${VTUNE_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -46,8 +46,7 @@ public:
|
|||||||
ASSERT(!mbedtls_aes_setkey_dec(&ctx, key, 128));
|
ASSERT(!mbedtls_aes_setkey_dec(&ctx, key, 128));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,
|
bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out, size_t len) const override
|
||||||
size_t len) const override
|
|
||||||
{
|
{
|
||||||
std::array<u8, BLOCK_SIZE> iv_tmp{};
|
std::array<u8, BLOCK_SIZE> iv_tmp{};
|
||||||
if (iv)
|
if (iv)
|
||||||
@ -206,8 +205,7 @@ public:
|
|||||||
_mm_storeu_si128(&((__m128i*)buf_out)[d], block[d]);
|
_mm_storeu_si128(&((__m128i*)buf_out)[d], block[d]);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out,
|
bool Crypt(const u8* iv, u8* iv_out, const u8* buf_in, u8* buf_out, size_t len) const override
|
||||||
size_t len) const override
|
|
||||||
{
|
{
|
||||||
if (len % BLOCK_SIZE)
|
if (len % BLOCK_SIZE)
|
||||||
return false;
|
return false;
|
||||||
|
@ -41,18 +41,18 @@ public:
|
|||||||
mbedtls_sha1_init(&ctx);
|
mbedtls_sha1_init(&ctx);
|
||||||
ASSERT(!mbedtls_sha1_starts_ret(&ctx));
|
ASSERT(!mbedtls_sha1_starts_ret(&ctx));
|
||||||
}
|
}
|
||||||
~ContextMbed() { mbedtls_sha1_free(&ctx); }
|
~ContextMbed() override { mbedtls_sha1_free(&ctx); }
|
||||||
virtual void Update(const u8* msg, size_t len) override
|
void Update(const u8* msg, size_t len) override
|
||||||
{
|
{
|
||||||
ASSERT(!mbedtls_sha1_update_ret(&ctx, msg, len));
|
ASSERT(!mbedtls_sha1_update_ret(&ctx, msg, len));
|
||||||
}
|
}
|
||||||
virtual Digest Finish() override
|
Digest Finish() override
|
||||||
{
|
{
|
||||||
Digest digest;
|
Digest digest;
|
||||||
ASSERT(!mbedtls_sha1_finish_ret(&ctx, digest.data()));
|
ASSERT(!mbedtls_sha1_finish_ret(&ctx, digest.data()));
|
||||||
return digest;
|
return digest;
|
||||||
}
|
}
|
||||||
virtual bool HwAccelerated() const override { return false; }
|
bool HwAccelerated() const override { return false; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mbedtls_sha1_context ctx{};
|
mbedtls_sha1_context ctx{};
|
||||||
@ -204,7 +204,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
ATTRIBUTE_TARGET("sha")
|
ATTRIBUTE_TARGET("sha")
|
||||||
virtual void ProcessBlock(const u8* msg) override
|
void ProcessBlock(const u8* msg) override
|
||||||
{
|
{
|
||||||
// There are 80 rounds with 4 bytes per round, giving 0x140 byte work space, but we can keep
|
// There are 80 rounds with 4 bytes per round, giving 0x140 byte work space, but we can keep
|
||||||
// active state in just 0x40 bytes.
|
// active state in just 0x40 bytes.
|
||||||
@ -248,7 +248,7 @@ private:
|
|||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Digest GetDigest() override
|
Digest GetDigest() override
|
||||||
{
|
{
|
||||||
Digest digest;
|
Digest digest;
|
||||||
_mm_storeu_si128((__m128i*)&digest[0], byterev_16B(state[0]));
|
_mm_storeu_si128((__m128i*)&digest[0], byterev_16B(state[0]));
|
||||||
@ -257,7 +257,7 @@ private:
|
|||||||
return digest;
|
return digest;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool HwAccelerated() const override { return true; }
|
bool HwAccelerated() const override { return true; }
|
||||||
|
|
||||||
std::array<XmmReg, 2> state{};
|
std::array<XmmReg, 2> state{};
|
||||||
};
|
};
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/ScopeGuard.h"
|
#include "Common/ScopeGuard.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
#include "Common/TimeUtil.h"
|
||||||
|
|
||||||
#include "Core/Config/MainSettings.h"
|
#include "Core/Config/MainSettings.h"
|
||||||
|
|
||||||
@ -95,12 +96,7 @@ int SDCardDiskIOCtl(File::IOFile* image, u8 pdrv, u8 cmd, void* buff)
|
|||||||
u32 GetSystemTimeFAT()
|
u32 GetSystemTimeFAT()
|
||||||
{
|
{
|
||||||
const std::time_t time = std::time(nullptr);
|
const std::time_t time = std::time(nullptr);
|
||||||
std::tm tm;
|
std::tm tm = *Common::LocalTime(time);
|
||||||
#ifdef _WIN32
|
|
||||||
localtime_s(&tm, &time);
|
|
||||||
#else
|
|
||||||
localtime_r(&time, &tm);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DWORD fattime = 0;
|
DWORD fattime = 0;
|
||||||
fattime |= (tm.tm_year - 80) << 25;
|
fattime |= (tm.tm_year - 80) << 25;
|
||||||
|
67
Source/Core/Common/FilesystemWatcher.cpp
Normal file
67
Source/Core/Common/FilesystemWatcher.cpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// Copyright 2025 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "Common/FilesystemWatcher.h"
|
||||||
|
|
||||||
|
#include <wtr/watcher.hpp>
|
||||||
|
|
||||||
|
#include "Common/Logging/Log.h"
|
||||||
|
#include "Common/StringUtil.h"
|
||||||
|
|
||||||
|
namespace Common
|
||||||
|
{
|
||||||
|
FilesystemWatcher::FilesystemWatcher() = default;
|
||||||
|
FilesystemWatcher::~FilesystemWatcher() = default;
|
||||||
|
|
||||||
|
void FilesystemWatcher::Watch(const std::string& path)
|
||||||
|
{
|
||||||
|
const auto [iter, inserted] = m_watched_paths.try_emplace(path, nullptr);
|
||||||
|
if (inserted)
|
||||||
|
{
|
||||||
|
iter->second = std::make_unique<wtr::watch>(path, [this](wtr::event e) {
|
||||||
|
const auto watched_path = PathToString(e.path_name);
|
||||||
|
if (e.path_type == wtr::event::path_type::watcher)
|
||||||
|
{
|
||||||
|
if (watched_path.starts_with('e'))
|
||||||
|
ERROR_LOG_FMT(COMMON, "Filesystem watcher: '{}'", watched_path);
|
||||||
|
else if (watched_path.starts_with('w'))
|
||||||
|
WARN_LOG_FMT(COMMON, "Filesystem watcher: '{}'", watched_path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.effect_type == wtr::event::effect_type::create)
|
||||||
|
{
|
||||||
|
const auto path = WithUnifiedPathSeparators(watched_path);
|
||||||
|
PathAdded(path);
|
||||||
|
}
|
||||||
|
else if (e.effect_type == wtr::event::effect_type::modify)
|
||||||
|
{
|
||||||
|
const auto path = WithUnifiedPathSeparators(watched_path);
|
||||||
|
PathModified(path);
|
||||||
|
}
|
||||||
|
else if (e.effect_type == wtr::event::effect_type::rename)
|
||||||
|
{
|
||||||
|
if (!e.associated)
|
||||||
|
{
|
||||||
|
WARN_LOG_FMT(COMMON, "Rename on path '{}' seen without association!", watched_path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto old_path = WithUnifiedPathSeparators(watched_path);
|
||||||
|
const auto new_path = WithUnifiedPathSeparators(PathToString(e.associated->path_name));
|
||||||
|
PathRenamed(old_path, new_path);
|
||||||
|
}
|
||||||
|
else if (e.effect_type == wtr::event::effect_type::destroy)
|
||||||
|
{
|
||||||
|
const auto path = WithUnifiedPathSeparators(watched_path);
|
||||||
|
PathDeleted(path);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilesystemWatcher::Unwatch(const std::string& path)
|
||||||
|
{
|
||||||
|
m_watched_paths.erase(path);
|
||||||
|
}
|
||||||
|
} // namespace Common
|
47
Source/Core/Common/FilesystemWatcher.h
Normal file
47
Source/Core/Common/FilesystemWatcher.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// Copyright 2025 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace wtr
|
||||||
|
{
|
||||||
|
inline namespace watcher
|
||||||
|
{
|
||||||
|
class watch;
|
||||||
|
}
|
||||||
|
} // namespace wtr
|
||||||
|
|
||||||
|
namespace Common
|
||||||
|
{
|
||||||
|
// A class that can watch a path and receive callbacks
|
||||||
|
// when files or directories underneath that path receive events
|
||||||
|
class FilesystemWatcher
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FilesystemWatcher();
|
||||||
|
virtual ~FilesystemWatcher();
|
||||||
|
|
||||||
|
void Watch(const std::string& path);
|
||||||
|
void Unwatch(const std::string& path);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// A new file or folder was added to one of the watched paths
|
||||||
|
virtual void PathAdded(std::string_view path) {}
|
||||||
|
|
||||||
|
// A file or folder was modified in one of the watched paths
|
||||||
|
virtual void PathModified(std::string_view path) {}
|
||||||
|
|
||||||
|
// A file or folder was renamed in one of the watched paths
|
||||||
|
virtual void PathRenamed(std::string_view old_path, std::string_view new_path) {}
|
||||||
|
|
||||||
|
// A file or folder was deleted in one of the watched paths
|
||||||
|
virtual void PathDeleted(std::string_view path) {}
|
||||||
|
|
||||||
|
std::map<std::string, std::unique_ptr<wtr::watch>> m_watched_paths;
|
||||||
|
};
|
||||||
|
} // namespace Common
|
@ -10,9 +10,9 @@
|
|||||||
class GLContextWGL final : public GLContext
|
class GLContextWGL final : public GLContext
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
~GLContextWGL();
|
~GLContextWGL() override;
|
||||||
|
|
||||||
bool IsHeadless() const;
|
bool IsHeadless() const override;
|
||||||
|
|
||||||
std::unique_ptr<GLContext> CreateSharedContext() override;
|
std::unique_ptr<GLContext> CreateSharedContext() override;
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ class HostDisassemblerBochs final : public HostDisassembler
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit HostDisassemblerBochs();
|
explicit HostDisassemblerBochs();
|
||||||
~HostDisassemblerBochs() = default;
|
~HostDisassemblerBochs() override = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
disassembler m_disasm;
|
disassembler m_disasm;
|
||||||
|
@ -9,7 +9,7 @@ class ConsoleListener : public Common::Log::LogListener
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConsoleListener();
|
ConsoleListener();
|
||||||
~ConsoleListener();
|
~ConsoleListener() override;
|
||||||
|
|
||||||
void Log(Common::Log::LogLevel level, const char* text) override;
|
void Log(Common::Log::LogLevel level, const char* text) override;
|
||||||
|
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <unzip.h>
|
#include <mz.h>
|
||||||
|
#include <mz_zip.h>
|
||||||
|
#include <mz_zip_rw.h>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/ScopeGuard.h"
|
#include "Common/ScopeGuard.h"
|
||||||
@ -13,14 +15,14 @@
|
|||||||
namespace Common
|
namespace Common
|
||||||
{
|
{
|
||||||
// Reads all of the current file. destination must be big enough to fit the whole file.
|
// Reads all of the current file. destination must be big enough to fit the whole file.
|
||||||
inline bool ReadFileFromZip(unzFile file, u8* destination, u64 len)
|
inline bool ReadFileFromZip(void* zip_reader, u8* destination, u64 len)
|
||||||
{
|
{
|
||||||
const u64 MAX_BUFFER_SIZE = 65535;
|
const u64 MAX_BUFFER_SIZE = 65535;
|
||||||
|
|
||||||
if (unzOpenCurrentFile(file) != UNZ_OK)
|
if (mz_zip_reader_entry_open(zip_reader) != MZ_OK)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Common::ScopeGuard guard{[&] { unzCloseCurrentFile(file); }};
|
Common::ScopeGuard guard{[&] { mz_zip_reader_entry_close(zip_reader); }};
|
||||||
|
|
||||||
u64 bytes_to_go = len;
|
u64 bytes_to_go = len;
|
||||||
while (bytes_to_go > 0)
|
while (bytes_to_go > 0)
|
||||||
@ -28,7 +30,7 @@ inline bool ReadFileFromZip(unzFile file, u8* destination, u64 len)
|
|||||||
// NOTE: multiples of 4G can't cause read_len == 0 && bytes_to_go > 0, as MAX_BUFFER_SIZE is
|
// NOTE: multiples of 4G can't cause read_len == 0 && bytes_to_go > 0, as MAX_BUFFER_SIZE is
|
||||||
// small.
|
// small.
|
||||||
const u32 read_len = static_cast<u32>(std::min(bytes_to_go, MAX_BUFFER_SIZE));
|
const u32 read_len = static_cast<u32>(std::min(bytes_to_go, MAX_BUFFER_SIZE));
|
||||||
const int rv = unzReadCurrentFile(file, destination, read_len);
|
const int rv = mz_zip_reader_entry_read(zip_reader, destination, read_len);
|
||||||
if (rv < 0)
|
if (rv < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -37,11 +39,11 @@ inline bool ReadFileFromZip(unzFile file, u8* destination, u64 len)
|
|||||||
destination += bytes_read;
|
destination += bytes_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
return unzEndOfFile(file) == 1;
|
return bytes_to_go == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ContiguousContainer>
|
template <typename ContiguousContainer>
|
||||||
bool ReadFileFromZip(unzFile file, ContiguousContainer* destination)
|
bool ReadFileFromZip(void* file, ContiguousContainer* destination)
|
||||||
{
|
{
|
||||||
return ReadFileFromZip(file, reinterpret_cast<u8*>(destination->data()), destination->size());
|
return ReadFileFromZip(file, reinterpret_cast<u8*>(destination->data()), destination->size());
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,6 @@ std::string SettingsWriter::GenerateSerialNumber()
|
|||||||
|
|
||||||
// Must be 9 characters at most; otherwise the serial number will be rejected by SDK libraries,
|
// Must be 9 characters at most; otherwise the serial number will be rejected by SDK libraries,
|
||||||
// as there is a check to ensure the string length is strictly lower than 10.
|
// as there is a check to ensure the string length is strictly lower than 10.
|
||||||
// 3 for %j, 2 for %H, 2 for %M, 2 for %S.
|
return fmt::format("{:09}", t % 1000000000);
|
||||||
return fmt::format("{:%j%H%M%S}", fmt::localtime(t));
|
|
||||||
}
|
}
|
||||||
} // namespace Common
|
} // namespace Common
|
||||||
|
@ -2,23 +2,25 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "Common/TimeUtil.h"
|
#include "Common/TimeUtil.h"
|
||||||
|
#include "Common/Logging/Log.h"
|
||||||
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace Common
|
namespace Common
|
||||||
{
|
{
|
||||||
std::optional<std::tm> Localtime(std::time_t time)
|
std::optional<std::tm> LocalTime(std::time_t time)
|
||||||
{
|
{
|
||||||
std::tm local_time;
|
std::tm local_time;
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
if (localtime_s(&local_time, &time) != 0)
|
if (localtime_s(&local_time, &time) != 0)
|
||||||
return std::nullopt;
|
|
||||||
#else
|
#else
|
||||||
std::tm* result = localtime_r(&time, &local_time);
|
if (localtime_r(&time, &local_time) == NULL)
|
||||||
if (result != &local_time)
|
|
||||||
return std::nullopt;
|
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(COMMON, "Failed to convert time to local time: {}", std::strerror(errno));
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
return local_time;
|
return local_time;
|
||||||
}
|
}
|
||||||
} // Namespace Common
|
} // Namespace Common
|
||||||
|
@ -9,5 +9,5 @@
|
|||||||
namespace Common
|
namespace Common
|
||||||
{
|
{
|
||||||
// Threadsafe and error-checking variant of std::localtime()
|
// Threadsafe and error-checking variant of std::localtime()
|
||||||
std::optional<std::tm> Localtime(std::time_t time);
|
std::optional<std::tm> LocalTime(std::time_t time);
|
||||||
} // Namespace Common
|
} // Namespace Common
|
||||||
|
@ -165,17 +165,26 @@ void AchievementManager::LoadGame(const DiscIO::Volume* volume)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (volume == nullptr)
|
|
||||||
{
|
|
||||||
WARN_LOG_FMT(ACHIEVEMENTS, "Called Load Game without a game.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!m_client)
|
if (!m_client)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(ACHIEVEMENTS,
|
ERROR_LOG_FMT(ACHIEVEMENTS,
|
||||||
"Attempted to load game achievements without achievement client initialized.");
|
"Attempted to load game achievements without achievement client initialized.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (volume == nullptr)
|
||||||
|
{
|
||||||
|
WARN_LOG_FMT(ACHIEVEMENTS, "Software format unsupported by AchievementManager.");
|
||||||
|
if (rc_client_get_game_info(m_client))
|
||||||
|
{
|
||||||
|
rc_client_begin_change_media_from_hash(m_client, "", ChangeMediaCallback, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc_client_set_read_memory_function(m_client, MemoryVerifier);
|
||||||
|
rc_client_begin_load_game(m_client, "", LoadGameCallback, NULL);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
rc_client_set_unofficial_enabled(m_client, Config::Get(Config::RA_UNOFFICIAL_ENABLED));
|
rc_client_set_unofficial_enabled(m_client, Config::Get(Config::RA_UNOFFICIAL_ENABLED));
|
||||||
rc_client_set_encore_mode_enabled(m_client, Config::Get(Config::RA_ENCORE_ENABLED));
|
rc_client_set_encore_mode_enabled(m_client, Config::Get(Config::RA_ENCORE_ENABLED));
|
||||||
rc_client_set_spectator_mode_enabled(m_client, Config::Get(Config::RA_SPECTATOR_ENABLED));
|
rc_client_set_spectator_mode_enabled(m_client, Config::Get(Config::RA_SPECTATOR_ENABLED));
|
||||||
@ -329,10 +338,11 @@ void AchievementManager::DoFrame()
|
|||||||
if (!system)
|
if (!system)
|
||||||
return;
|
return;
|
||||||
Core::CPUThreadGuard thread_guard(*system);
|
Core::CPUThreadGuard thread_guard(*system);
|
||||||
u32 mem2_size = system->GetMemory().GetExRamSizeReal();
|
u32 mem2_size = (system->IsWii()) ? system->GetMemory().GetExRamSizeReal() : 0;
|
||||||
if (m_cloned_memory.size() != MEM1_SIZE + mem2_size)
|
if (m_cloned_memory.size() != MEM1_SIZE + mem2_size)
|
||||||
m_cloned_memory.resize(MEM1_SIZE + mem2_size);
|
m_cloned_memory.resize(MEM1_SIZE + mem2_size);
|
||||||
system->GetMemory().CopyFromEmu(m_cloned_memory.data(), 0, MEM1_SIZE);
|
system->GetMemory().CopyFromEmu(m_cloned_memory.data(), 0, MEM1_SIZE);
|
||||||
|
if (mem2_size > 0)
|
||||||
system->GetMemory().CopyFromEmu(m_cloned_memory.data() + MEM1_SIZE, MEM2_START, mem2_size);
|
system->GetMemory().CopyFromEmu(m_cloned_memory.data() + MEM1_SIZE, MEM2_START, mem2_size);
|
||||||
}
|
}
|
||||||
#endif // RC_CLIENT_SUPPORTS_RAINTEGRATION
|
#endif // RC_CLIENT_SUPPORTS_RAINTEGRATION
|
||||||
@ -598,11 +608,6 @@ rc_client_t* AchievementManager::GetClient()
|
|||||||
return m_client;
|
return m_client;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_api_fetch_game_data_response_t* AchievementManager::GetGameData()
|
|
||||||
{
|
|
||||||
return &m_game_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AchievementManager::Badge& AchievementManager::GetGameBadge() const
|
const AchievementManager::Badge& AchievementManager::GetGameBadge() const
|
||||||
{
|
{
|
||||||
return m_game_badge.data.empty() ? m_default_game_badge : m_game_badge;
|
return m_game_badge.data.empty() ? m_default_game_badge : m_game_badge;
|
||||||
@ -736,12 +741,8 @@ void AchievementManager::CloseGame()
|
|||||||
if (Config::Get(Config::RA_DISCORD_PRESENCE_ENABLED))
|
if (Config::Get(Config::RA_DISCORD_PRESENCE_ENABLED))
|
||||||
Discord::UpdateDiscordPresence();
|
Discord::UpdateDiscordPresence();
|
||||||
if (rc_client_get_game_info(m_client))
|
if (rc_client_get_game_info(m_client))
|
||||||
{
|
|
||||||
rc_api_destroy_fetch_game_data_response(&m_game_data);
|
|
||||||
rc_client_unload_game(m_client);
|
rc_client_unload_game(m_client);
|
||||||
}
|
|
||||||
INFO_LOG_FMT(ACHIEVEMENTS, "Game closed.");
|
INFO_LOG_FMT(ACHIEVEMENTS, "Game closed.");
|
||||||
m_game_data = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_update_callback(UpdatedItems{.all = true});
|
m_update_callback(UpdatedItems{.all = true});
|
||||||
@ -995,36 +996,30 @@ void AchievementManager::LoadGameCallback(int result, const char* error_message,
|
|||||||
OSD::Color::RED);
|
OSD::Color::RED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (result == RC_NO_GAME_LOADED && instance.m_dll_found)
|
|
||||||
{
|
|
||||||
// Allow developer tools for unidentified games
|
|
||||||
rc_client_set_read_memory_function(instance.m_client, MemoryPeeker);
|
|
||||||
instance.m_system.store(&Core::System::GetInstance(), std::memory_order_release);
|
|
||||||
WARN_LOG_FMT(ACHIEVEMENTS, "Unrecognized title ready for development.");
|
|
||||||
OSD::AddMessage("Unrecognized title loaded for development.", OSD::Duration::VERY_LONG,
|
|
||||||
OSD::Color::YELLOW);
|
|
||||||
}
|
|
||||||
if (result != RC_OK)
|
|
||||||
{
|
|
||||||
WARN_LOG_FMT(ACHIEVEMENTS, "Failed to load data for current game.");
|
|
||||||
OSD::AddMessage("Achievements are not supported for this title.", OSD::Duration::VERY_LONG,
|
|
||||||
OSD::Color::RED);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* game = rc_client_get_game_info(client);
|
auto* game = rc_client_get_game_info(client);
|
||||||
|
if (result == RC_OK)
|
||||||
|
{
|
||||||
if (!game)
|
if (!game)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(ACHIEVEMENTS, "Failed to retrieve game information from client.");
|
ERROR_LOG_FMT(ACHIEVEMENTS, "Failed to retrieve game information from client.");
|
||||||
OSD::AddMessage("Failed to load achievements for this title.", OSD::Duration::VERY_LONG,
|
OSD::AddMessage("Failed to load achievements for this title.", OSD::Duration::VERY_LONG,
|
||||||
OSD::Color::RED);
|
OSD::Color::RED);
|
||||||
instance.CloseGame();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
INFO_LOG_FMT(ACHIEVEMENTS, "Loaded data for game ID {}.", game->id);
|
INFO_LOG_FMT(ACHIEVEMENTS, "Loaded data for game ID {}.", game->id);
|
||||||
|
instance.m_display_welcome_message = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WARN_LOG_FMT(ACHIEVEMENTS, "Failed to load data for current game.");
|
||||||
|
OSD::AddMessage("Achievements are not supported for this title.", OSD::Duration::VERY_LONG,
|
||||||
|
OSD::Color::RED);
|
||||||
|
}
|
||||||
|
|
||||||
rc_client_set_read_memory_function(instance.m_client, MemoryPeeker);
|
rc_client_set_read_memory_function(instance.m_client, MemoryPeeker);
|
||||||
instance.m_display_welcome_message = true;
|
|
||||||
instance.FetchGameBadges();
|
instance.FetchGameBadges();
|
||||||
instance.m_system.store(&Core::System::GetInstance(), std::memory_order_release);
|
instance.m_system.store(&Core::System::GetInstance(), std::memory_order_release);
|
||||||
instance.m_update_callback({.all = true});
|
instance.m_update_callback({.all = true});
|
||||||
|
@ -89,8 +89,8 @@ public:
|
|||||||
static constexpr std::string_view BLUE = "#0B71C1";
|
static constexpr std::string_view BLUE = "#0B71C1";
|
||||||
static constexpr std::string_view APPROVED_LIST_FILENAME = "ApprovedInis.json";
|
static constexpr std::string_view APPROVED_LIST_FILENAME = "ApprovedInis.json";
|
||||||
static const inline Common::SHA1::Digest APPROVED_LIST_HASH = {
|
static const inline Common::SHA1::Digest APPROVED_LIST_HASH = {
|
||||||
0xE1, 0x29, 0xD1, 0x33, 0x4D, 0xF2, 0xF8, 0xA8, 0x4E, 0xCA,
|
0x6D, 0x91, 0xF5, 0xC1, 0xE2, 0x4C, 0xC3, 0x39, 0xF5, 0x7F,
|
||||||
0xF6, 0x87, 0xE6, 0xEC, 0xEC, 0xB3, 0x18, 0x69, 0x34, 0x45};
|
0xEC, 0xA9, 0x8C, 0xA9, 0xBD, 0x61, 0x28, 0x54, 0x11, 0x62};
|
||||||
|
|
||||||
struct LeaderboardEntry
|
struct LeaderboardEntry
|
||||||
{
|
{
|
||||||
@ -160,7 +160,6 @@ public:
|
|||||||
const Badge& GetPlayerBadge() const;
|
const Badge& GetPlayerBadge() const;
|
||||||
std::string_view GetGameDisplayName() const;
|
std::string_view GetGameDisplayName() const;
|
||||||
rc_client_t* GetClient();
|
rc_client_t* GetClient();
|
||||||
rc_api_fetch_game_data_response_t* GetGameData();
|
|
||||||
const Badge& GetGameBadge() const;
|
const Badge& GetGameBadge() const;
|
||||||
const Badge& GetAchievementBadge(AchievementId id, bool locked) const;
|
const Badge& GetAchievementBadge(AchievementId id, bool locked) const;
|
||||||
const LeaderboardStatus* GetLeaderboardInfo(AchievementId leaderboard_id);
|
const LeaderboardStatus* GetLeaderboardInfo(AchievementId leaderboard_id);
|
||||||
@ -278,9 +277,6 @@ private:
|
|||||||
std::atomic_bool m_background_execution_allowed = true;
|
std::atomic_bool m_background_execution_allowed = true;
|
||||||
Badge m_player_badge;
|
Badge m_player_badge;
|
||||||
Hash m_game_hash{};
|
Hash m_game_hash{};
|
||||||
u32 m_game_id = 0;
|
|
||||||
rc_api_fetch_game_data_response_t m_game_data{};
|
|
||||||
bool m_is_game_loaded = false;
|
|
||||||
Badge m_game_badge;
|
Badge m_game_badge;
|
||||||
bool m_display_welcome_message = false;
|
bool m_display_welcome_message = false;
|
||||||
std::unordered_map<AchievementId, Badge> m_unlocked_badges;
|
std::unordered_map<AchievementId, Badge> m_unlocked_badges;
|
||||||
|
@ -603,6 +603,8 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AchievementManager::GetInstance().LoadGame(nullptr);
|
||||||
|
|
||||||
SConfig::OnTitleDirectlyBooted(guard);
|
SConfig::OnTitleDirectlyBooted(guard);
|
||||||
|
|
||||||
ppc_state.pc = executable.reader->GetEntryPoint();
|
ppc_state.pc = executable.reader->GetEntryPoint();
|
||||||
@ -635,6 +637,8 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
|
|||||||
if (!BootNANDTitle(system, nand_title.id))
|
if (!BootNANDTitle(system, nand_title.id))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
AchievementManager::GetInstance().LoadGame(nullptr);
|
||||||
|
|
||||||
SConfig::OnTitleDirectlyBooted(guard);
|
SConfig::OnTitleDirectlyBooted(guard);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -661,6 +665,8 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
|
|||||||
ipl.disc->auto_disc_change_paths);
|
ipl.disc->auto_disc_change_paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AchievementManager::GetInstance().LoadGame(nullptr);
|
||||||
|
|
||||||
SConfig::OnTitleDirectlyBooted(guard);
|
SConfig::OnTitleDirectlyBooted(guard);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -668,6 +674,7 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
|
|||||||
bool operator()(const BootParameters::DFF& dff) const
|
bool operator()(const BootParameters::DFF& dff) const
|
||||||
{
|
{
|
||||||
NOTICE_LOG_FMT(BOOT, "Booting DFF: {}", dff.dff_path);
|
NOTICE_LOG_FMT(BOOT, "Booting DFF: {}", dff.dff_path);
|
||||||
|
AchievementManager::GetInstance().LoadGame(nullptr);
|
||||||
return system.GetFifoPlayer().Open(dff.dff_path);
|
return system.GetFifoPlayer().Open(dff.dff_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ public:
|
|||||||
explicit DolReader(const std::string& filename);
|
explicit DolReader(const std::string& filename);
|
||||||
explicit DolReader(File::IOFile file);
|
explicit DolReader(File::IOFile file);
|
||||||
explicit DolReader(std::vector<u8> buffer);
|
explicit DolReader(std::vector<u8> buffer);
|
||||||
~DolReader();
|
~DolReader() override;
|
||||||
|
|
||||||
bool IsValid() const override { return m_is_valid; }
|
bool IsValid() const override { return m_is_valid; }
|
||||||
bool IsWii() const override { return m_is_wii; }
|
bool IsWii() const override { return m_is_wii; }
|
||||||
|
@ -28,7 +28,7 @@ public:
|
|||||||
explicit ElfReader(const std::string& filename);
|
explicit ElfReader(const std::string& filename);
|
||||||
explicit ElfReader(File::IOFile file);
|
explicit ElfReader(File::IOFile file);
|
||||||
explicit ElfReader(std::vector<u8> buffer);
|
explicit ElfReader(std::vector<u8> buffer);
|
||||||
~ElfReader();
|
~ElfReader() override;
|
||||||
u32 Read32(int off) const { return base32[off >> 2]; }
|
u32 Read32(int off) const { return base32[off >> 2]; }
|
||||||
// Quick accessors
|
// Quick accessors
|
||||||
ElfType GetType() const { return (ElfType)(header->e_type); }
|
ElfType GetType() const { return (ElfType)(header->e_type); }
|
||||||
|
@ -45,6 +45,7 @@ const Info<bool> MAIN_ACCURATE_CPU_CACHE{{System::Main, "Core", "AccurateCPUCach
|
|||||||
const Info<bool> MAIN_DSP_HLE{{System::Main, "Core", "DSPHLE"}, true};
|
const Info<bool> MAIN_DSP_HLE{{System::Main, "Core", "DSPHLE"}, true};
|
||||||
const Info<int> MAIN_MAX_FALLBACK{{System::Main, "Core", "MaxFallback"}, 100};
|
const Info<int> MAIN_MAX_FALLBACK{{System::Main, "Core", "MaxFallback"}, 100};
|
||||||
const Info<int> MAIN_TIMING_VARIANCE{{System::Main, "Core", "TimingVariance"}, 40};
|
const Info<int> MAIN_TIMING_VARIANCE{{System::Main, "Core", "TimingVariance"}, 40};
|
||||||
|
const Info<bool> MAIN_CORRECT_TIME_DRIFT{{System::Main, "Core", "CorrectTimeDrift"}, false};
|
||||||
const Info<bool> MAIN_CPU_THREAD{{System::Main, "Core", "CPUThread"}, true};
|
const Info<bool> MAIN_CPU_THREAD{{System::Main, "Core", "CPUThread"}, true};
|
||||||
const Info<bool> MAIN_SYNC_ON_SKIP_IDLE{{System::Main, "Core", "SyncOnSkipIdle"}, true};
|
const Info<bool> MAIN_SYNC_ON_SKIP_IDLE{{System::Main, "Core", "SyncOnSkipIdle"}, true};
|
||||||
const Info<std::string> MAIN_DEFAULT_ISO{{System::Main, "Core", "DefaultISO"}, ""};
|
const Info<std::string> MAIN_DEFAULT_ISO{{System::Main, "Core", "DefaultISO"}, ""};
|
||||||
|
@ -63,6 +63,7 @@ extern const Info<bool> MAIN_ACCURATE_CPU_CACHE;
|
|||||||
extern const Info<bool> MAIN_DSP_HLE;
|
extern const Info<bool> MAIN_DSP_HLE;
|
||||||
extern const Info<int> MAIN_MAX_FALLBACK;
|
extern const Info<int> MAIN_MAX_FALLBACK;
|
||||||
extern const Info<int> MAIN_TIMING_VARIANCE;
|
extern const Info<int> MAIN_TIMING_VARIANCE;
|
||||||
|
extern const Info<bool> MAIN_CORRECT_TIME_DRIFT;
|
||||||
extern const Info<bool> MAIN_CPU_THREAD;
|
extern const Info<bool> MAIN_CPU_THREAD;
|
||||||
extern const Info<bool> MAIN_SYNC_ON_SKIP_IDLE;
|
extern const Info<bool> MAIN_SYNC_ON_SKIP_IDLE;
|
||||||
extern const Info<std::string> MAIN_DEFAULT_ISO;
|
extern const Info<std::string> MAIN_DEFAULT_ISO;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
@ -34,6 +35,7 @@
|
|||||||
#include "Common/ScopeGuard.h"
|
#include "Common/ScopeGuard.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
#include "Common/Thread.h"
|
#include "Common/Thread.h"
|
||||||
|
#include "Common/TimeUtil.h"
|
||||||
#include "Common/Version.h"
|
#include "Common/Version.h"
|
||||||
|
|
||||||
#include "Core/AchievementManager.h"
|
#include "Core/AchievementManager.h"
|
||||||
@ -82,7 +84,6 @@
|
|||||||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||||
#include "InputCommon/GCAdapter.h"
|
#include "InputCommon/GCAdapter.h"
|
||||||
|
|
||||||
#include "VideoCommon/Assets/CustomAssetLoader.h"
|
|
||||||
#include "VideoCommon/AsyncRequests.h"
|
#include "VideoCommon/AsyncRequests.h"
|
||||||
#include "VideoCommon/Fifo.h"
|
#include "VideoCommon/Fifo.h"
|
||||||
#include "VideoCommon/FrameDumper.h"
|
#include "VideoCommon/FrameDumper.h"
|
||||||
@ -528,9 +529,6 @@ static void EmuThread(Core::System& system, std::unique_ptr<BootParameters> boot
|
|||||||
|
|
||||||
FreeLook::LoadInputConfig();
|
FreeLook::LoadInputConfig();
|
||||||
|
|
||||||
system.GetCustomAssetLoader().Init();
|
|
||||||
Common::ScopeGuard asset_loader_guard([&system] { system.GetCustomAssetLoader().Shutdown(); });
|
|
||||||
|
|
||||||
system.GetMovie().Init(*boot);
|
system.GetMovie().Init(*boot);
|
||||||
Common::ScopeGuard movie_guard([&system] { system.GetMovie().Shutdown(); });
|
Common::ScopeGuard movie_guard([&system] { system.GetMovie().Shutdown(); });
|
||||||
|
|
||||||
@ -737,15 +735,17 @@ static std::string GenerateScreenshotFolderPath()
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GenerateScreenshotName()
|
static std::optional<std::string> GenerateScreenshotName()
|
||||||
{
|
{
|
||||||
// append gameId, path only contains the folder here.
|
// append gameId, path only contains the folder here.
|
||||||
const std::string path_prefix =
|
const std::string path_prefix =
|
||||||
GenerateScreenshotFolderPath() + SConfig::GetInstance().GetGameID();
|
GenerateScreenshotFolderPath() + SConfig::GetInstance().GetGameID();
|
||||||
|
|
||||||
const std::time_t cur_time = std::time(nullptr);
|
const std::time_t cur_time = std::time(nullptr);
|
||||||
const std::string base_name =
|
const auto local_time = Common::LocalTime(cur_time);
|
||||||
fmt::format("{}_{:%Y-%m-%d_%H-%M-%S}", path_prefix, fmt::localtime(cur_time));
|
if (!local_time)
|
||||||
|
return std::nullopt;
|
||||||
|
const std::string base_name = fmt::format("{}_{:%Y-%m-%d_%H-%M-%S}", path_prefix, *local_time);
|
||||||
|
|
||||||
// First try a filename without any suffixes, if already exists then append increasing numbers
|
// First try a filename without any suffixes, if already exists then append increasing numbers
|
||||||
std::string name = fmt::format("{}.png", base_name);
|
std::string name = fmt::format("{}.png", base_name);
|
||||||
@ -761,7 +761,9 @@ static std::string GenerateScreenshotName()
|
|||||||
void SaveScreenShot()
|
void SaveScreenShot()
|
||||||
{
|
{
|
||||||
const Core::CPUThreadGuard guard(Core::System::GetInstance());
|
const Core::CPUThreadGuard guard(Core::System::GetInstance());
|
||||||
g_frame_dumper->SaveScreenshot(GenerateScreenshotName());
|
std::optional<std::string> name = GenerateScreenshotName();
|
||||||
|
if (name)
|
||||||
|
g_frame_dumper->SaveScreenshot(*name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveScreenShot(std::string_view name)
|
void SaveScreenShot(std::string_view name)
|
||||||
|
@ -105,10 +105,20 @@ void CoreTimingManager::Init()
|
|||||||
|
|
||||||
m_last_oc_factor = m_config_oc_factor;
|
m_last_oc_factor = m_config_oc_factor;
|
||||||
m_globals.last_OC_factor_inverted = m_config_oc_inv_factor;
|
m_globals.last_OC_factor_inverted = m_config_oc_inv_factor;
|
||||||
|
|
||||||
|
m_on_state_changed_handle = Core::AddOnStateChangedCallback([this](Core::State state) {
|
||||||
|
if (state == Core::State::Running)
|
||||||
|
{
|
||||||
|
// We don't want Throttle to attempt catch-up for all the time lost while paused.
|
||||||
|
ResetThrottle(GetTicks());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreTimingManager::Shutdown()
|
void CoreTimingManager::Shutdown()
|
||||||
{
|
{
|
||||||
|
Core::RemoveOnStateChangedCallback(&m_on_state_changed_handle);
|
||||||
|
|
||||||
std::lock_guard lk(m_ts_write_lock);
|
std::lock_guard lk(m_ts_write_lock);
|
||||||
MoveEvents();
|
MoveEvents();
|
||||||
ClearPendingEvents();
|
ClearPendingEvents();
|
||||||
@ -131,6 +141,8 @@ void CoreTimingManager::RefreshConfig()
|
|||||||
|
|
||||||
m_max_variance = std::chrono::duration_cast<DT>(DT_ms(Config::Get(Config::MAIN_TIMING_VARIANCE)));
|
m_max_variance = std::chrono::duration_cast<DT>(DT_ms(Config::Get(Config::MAIN_TIMING_VARIANCE)));
|
||||||
|
|
||||||
|
m_correct_time_drift = Config::Get(Config::MAIN_CORRECT_TIME_DRIFT);
|
||||||
|
|
||||||
if (AchievementManager::GetInstance().IsHardcoreModeActive() &&
|
if (AchievementManager::GetInstance().IsHardcoreModeActive() &&
|
||||||
Config::Get(Config::MAIN_EMULATION_SPEED) < 1.0f &&
|
Config::Get(Config::MAIN_EMULATION_SPEED) < 1.0f &&
|
||||||
Config::Get(Config::MAIN_EMULATION_SPEED) > 0.0f)
|
Config::Get(Config::MAIN_EMULATION_SPEED) > 0.0f)
|
||||||
@ -428,7 +440,9 @@ void CoreTimingManager::Throttle(const s64 target_cycle)
|
|||||||
const TimePoint time = Clock::now();
|
const TimePoint time = Clock::now();
|
||||||
|
|
||||||
const TimePoint min_target = time - m_max_fallback;
|
const TimePoint min_target = time - m_max_fallback;
|
||||||
if (target_time < min_target)
|
|
||||||
|
// "Correct Time Drift" setting prevents timing relaxing.
|
||||||
|
if (!m_correct_time_drift && target_time < min_target)
|
||||||
{
|
{
|
||||||
// Core is running too slow.. i.e. CPU bottleneck.
|
// Core is running too slow.. i.e. CPU bottleneck.
|
||||||
const DT adjustment = min_target - target_time;
|
const DT adjustment = min_target - target_time;
|
||||||
|
@ -211,6 +211,7 @@ private:
|
|||||||
|
|
||||||
DT m_max_fallback = {};
|
DT m_max_fallback = {};
|
||||||
DT m_max_variance = {};
|
DT m_max_variance = {};
|
||||||
|
bool m_correct_time_drift = false;
|
||||||
double m_emulation_speed = 1.0;
|
double m_emulation_speed = 1.0;
|
||||||
|
|
||||||
bool IsSpeedUnlimited() const;
|
bool IsSpeedUnlimited() const;
|
||||||
@ -225,6 +226,8 @@ private:
|
|||||||
std::atomic_bool m_use_precision_timer = false;
|
std::atomic_bool m_use_precision_timer = false;
|
||||||
Common::PrecisionTimer m_precision_cpu_timer;
|
Common::PrecisionTimer m_precision_cpu_timer;
|
||||||
Common::PrecisionTimer m_precision_gpu_timer;
|
Common::PrecisionTimer m_precision_gpu_timer;
|
||||||
|
|
||||||
|
int m_on_state_changed_handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CoreTiming
|
} // namespace CoreTiming
|
||||||
|
@ -135,9 +135,11 @@ void Analyzer::FindInstructionStarts(const SDSP& dsp, u16 start_addr, u16 end_ad
|
|||||||
|
|
||||||
// If an instruction potentially raises exceptions, mark the following
|
// If an instruction potentially raises exceptions, mark the following
|
||||||
// instruction as needing to check for exceptions
|
// instruction as needing to check for exceptions
|
||||||
if (opcode->opcode == 0x00c0 || opcode->opcode == 0x1800 || opcode->opcode == 0x1880 ||
|
if (opcode->opcode == 0x00c0 || opcode->opcode == 0x00e0 || opcode->opcode == 0x1600 ||
|
||||||
opcode->opcode == 0x1900 || opcode->opcode == 0x1980 || opcode->opcode == 0x2000 ||
|
opcode->opcode == 0x1800 || opcode->opcode == 0x1880 || opcode->opcode == 0x1900 ||
|
||||||
opcode->extended)
|
opcode->opcode == 0x1980 || opcode->opcode == 0x1a00 || opcode->opcode == 0x1a80 ||
|
||||||
|
opcode->opcode == 0x1b00 || opcode->opcode == 0x1b80 || opcode->opcode == 0x2000 ||
|
||||||
|
opcode->opcode == 0x2800 || opcode->opcode == 0x2c00 || opcode->extended)
|
||||||
{
|
{
|
||||||
m_code_flags[static_cast<u16>(addr + opcode->size)] |= CODE_CHECK_EXC;
|
m_code_flags[static_cast<u16>(addr + opcode->size)] |= CODE_CHECK_EXC;
|
||||||
}
|
}
|
||||||
|
@ -224,11 +224,11 @@ void SDSP::CheckExternalInterrupt()
|
|||||||
control_reg &= ~CR_EXTERNAL_INT;
|
control_reg &= ~CR_EXTERNAL_INT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDSP::CheckExceptions()
|
bool SDSP::CheckExceptions()
|
||||||
{
|
{
|
||||||
// Early out to skip the loop in the common case.
|
// Early out to skip the loop in the common case.
|
||||||
if (exceptions == 0)
|
if (exceptions == 0)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
for (int i = 7; i > 0; i--)
|
for (int i = 7; i > 0; i--)
|
||||||
{
|
{
|
||||||
@ -247,7 +247,7 @@ void SDSP::CheckExceptions()
|
|||||||
r.sr &= ~SR_EXT_INT_ENABLE;
|
r.sr &= ~SR_EXT_INT_ENABLE;
|
||||||
else
|
else
|
||||||
r.sr &= ~SR_INT_ENABLE;
|
r.sr &= ~SR_INT_ENABLE;
|
||||||
break;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -257,6 +257,8 @@ void SDSP::CheckExceptions()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 SDSP::ReadRegister(size_t reg) const
|
u16 SDSP::ReadRegister(size_t reg) const
|
||||||
@ -541,9 +543,9 @@ void DSPCore::CheckExternalInterrupt()
|
|||||||
m_dsp.CheckExternalInterrupt();
|
m_dsp.CheckExternalInterrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSPCore::CheckExceptions()
|
bool DSPCore::CheckExceptions()
|
||||||
{
|
{
|
||||||
m_dsp.CheckExceptions();
|
return m_dsp.CheckExceptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 DSPCore::ReadRegister(size_t reg) const
|
u16 DSPCore::ReadRegister(size_t reg) const
|
||||||
|
@ -383,7 +383,7 @@ struct SDSP
|
|||||||
void SetException(ExceptionType exception);
|
void SetException(ExceptionType exception);
|
||||||
|
|
||||||
// Checks if any exceptions occurred an updates the DSP state as appropriate.
|
// Checks if any exceptions occurred an updates the DSP state as appropriate.
|
||||||
void CheckExceptions();
|
bool CheckExceptions();
|
||||||
|
|
||||||
// Notify that an external interrupt is pending (used by thread mode)
|
// Notify that an external interrupt is pending (used by thread mode)
|
||||||
void SetExternalInterrupt(bool val);
|
void SetExternalInterrupt(bool val);
|
||||||
@ -530,7 +530,7 @@ public:
|
|||||||
void CheckExternalInterrupt();
|
void CheckExternalInterrupt();
|
||||||
|
|
||||||
// Checks if any exceptions occurred an updates the DSP state as appropriate.
|
// Checks if any exceptions occurred an updates the DSP state as appropriate.
|
||||||
void CheckExceptions();
|
bool CheckExceptions();
|
||||||
|
|
||||||
// Reads the current value from a particular register.
|
// Reads the current value from a particular register.
|
||||||
u16 ReadRegister(size_t reg) const;
|
u16 ReadRegister(size_t reg) const;
|
||||||
|
@ -99,9 +99,9 @@ void DSPEmitter::ClearIRAMandDSPJITCodespaceReset()
|
|||||||
m_dsp_core.DSPState().reset_dspjit_codespace = false;
|
m_dsp_core.DSPState().reset_dspjit_codespace = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CheckExceptionsThunk(DSPCore& dsp)
|
static u32 CheckExceptionsThunk(DSPCore& dsp)
|
||||||
{
|
{
|
||||||
dsp.CheckExceptions();
|
return dsp.CheckExceptions() ? 1u : 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must go out of block if exception is detected
|
// Must go out of block if exception is detected
|
||||||
@ -116,8 +116,11 @@ void DSPEmitter::checkExceptions(u32 retval)
|
|||||||
DSPJitRegCache c(m_gpr);
|
DSPJitRegCache c(m_gpr);
|
||||||
m_gpr.SaveRegs();
|
m_gpr.SaveRegs();
|
||||||
ABI_CallFunctionP(CheckExceptionsThunk, &m_dsp_core);
|
ABI_CallFunctionP(CheckExceptionsThunk, &m_dsp_core);
|
||||||
|
TEST(32, R(ABI_RETURN), R(ABI_RETURN));
|
||||||
|
FixupBranch skip_return = J_CC(CC_Z, Jump::Short);
|
||||||
MOV(32, R(EAX), Imm32(retval));
|
MOV(32, R(EAX), Imm32(retval));
|
||||||
JMP(m_return_dispatcher, Jump::Near);
|
JMP(m_return_dispatcher, Jump::Near);
|
||||||
|
SetJumpTarget(skip_return);
|
||||||
m_gpr.LoadRegs(false);
|
m_gpr.LoadRegs(false);
|
||||||
m_gpr.FlushRegs(c, false);
|
m_gpr.FlushRegs(c, false);
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ class OSThreadView : public Common::Debug::ThreadView
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit OSThreadView(const Core::CPUThreadGuard& guard, u32 addr);
|
explicit OSThreadView(const Core::CPUThreadGuard& guard, u32 addr);
|
||||||
~OSThreadView() = default;
|
~OSThreadView() override = default;
|
||||||
|
|
||||||
const OSThread& Data() const;
|
const OSThread& Data() const;
|
||||||
|
|
||||||
|
@ -220,7 +220,7 @@ class FifoPlayer::CPUCore final : public CPUCoreBase
|
|||||||
public:
|
public:
|
||||||
explicit CPUCore(FifoPlayer* parent) : m_parent(parent) {}
|
explicit CPUCore(FifoPlayer* parent) : m_parent(parent) {}
|
||||||
CPUCore(const CPUCore&) = delete;
|
CPUCore(const CPUCore&) = delete;
|
||||||
~CPUCore() {}
|
~CPUCore() override {}
|
||||||
CPUCore& operator=(const CPUCore&) = delete;
|
CPUCore& operator=(const CPUCore&) = delete;
|
||||||
|
|
||||||
void Init() override
|
void Init() override
|
||||||
|
@ -157,7 +157,7 @@ class VAListStruct : public VAList
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit VAListStruct(const Core::CPUThreadGuard& guard, u32 address);
|
explicit VAListStruct(const Core::CPUThreadGuard& guard, u32 address);
|
||||||
~VAListStruct() = default;
|
~VAListStruct() override = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct svr4_va_list
|
struct svr4_va_list
|
||||||
|
@ -28,7 +28,7 @@ public:
|
|||||||
DSPHLE(DSPHLE&& other) = delete;
|
DSPHLE(DSPHLE&& other) = delete;
|
||||||
DSPHLE& operator=(const DSPHLE& other) = delete;
|
DSPHLE& operator=(const DSPHLE& other) = delete;
|
||||||
DSPHLE& operator=(DSPHLE&& other) = delete;
|
DSPHLE& operator=(DSPHLE&& other) = delete;
|
||||||
~DSPHLE();
|
~DSPHLE() override;
|
||||||
|
|
||||||
bool Initialize(bool wii, bool dsp_thread) override;
|
bool Initialize(bool wii, bool dsp_thread) override;
|
||||||
void Shutdown() override;
|
void Shutdown() override;
|
||||||
|
@ -27,7 +27,7 @@ public:
|
|||||||
AESndAccelerator(AESndAccelerator&&) = delete;
|
AESndAccelerator(AESndAccelerator&&) = delete;
|
||||||
AESndAccelerator& operator=(const AESndAccelerator&) = delete;
|
AESndAccelerator& operator=(const AESndAccelerator&) = delete;
|
||||||
AESndAccelerator& operator=(AESndAccelerator&&) = delete;
|
AESndAccelerator& operator=(AESndAccelerator&&) = delete;
|
||||||
~AESndAccelerator();
|
~AESndAccelerator() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnRawReadEndException() override {}
|
void OnRawReadEndException() override {}
|
||||||
|
@ -129,7 +129,7 @@ public:
|
|||||||
HLEAccelerator(HLEAccelerator&&) = delete;
|
HLEAccelerator(HLEAccelerator&&) = delete;
|
||||||
HLEAccelerator& operator=(const HLEAccelerator&) = delete;
|
HLEAccelerator& operator=(const HLEAccelerator&) = delete;
|
||||||
HLEAccelerator& operator=(HLEAccelerator&&) = delete;
|
HLEAccelerator& operator=(HLEAccelerator&&) = delete;
|
||||||
~HLEAccelerator() = default;
|
~HLEAccelerator() override = default;
|
||||||
|
|
||||||
PB_TYPE* acc_pb = nullptr;
|
PB_TYPE* acc_pb = nullptr;
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ class DSPLLE : public DSPEmulator
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DSPLLE();
|
DSPLLE();
|
||||||
~DSPLLE();
|
~DSPLLE() override;
|
||||||
|
|
||||||
bool Initialize(bool wii, bool dsp_thread) override;
|
bool Initialize(bool wii, bool dsp_thread) override;
|
||||||
void Shutdown() override;
|
void Shutdown() override;
|
||||||
|
@ -18,7 +18,7 @@ class CEXIAgp : public IEXIDevice
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CEXIAgp(Core::System& system, const Slot slot);
|
CEXIAgp(Core::System& system, const Slot slot);
|
||||||
virtual ~CEXIAgp() override;
|
~CEXIAgp() override;
|
||||||
bool IsPresent() const override { return true; }
|
bool IsPresent() const override { return true; }
|
||||||
void ImmWrite(u32 _uData, u32 _uSize) override;
|
void ImmWrite(u32 _uData, u32 _uSize) override;
|
||||||
u32 ImmRead(u32 _uSize) override;
|
u32 ImmRead(u32 _uSize) override;
|
||||||
|
@ -216,7 +216,7 @@ class CEXIETHERNET : public IEXIDevice
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CEXIETHERNET(Core::System& system, BBADeviceType type);
|
CEXIETHERNET(Core::System& system, BBADeviceType type);
|
||||||
virtual ~CEXIETHERNET();
|
~CEXIETHERNET() override;
|
||||||
void SetCS(int cs) override;
|
void SetCS(int cs) override;
|
||||||
bool IsPresent() const override;
|
bool IsPresent() const override;
|
||||||
bool IsInterruptSet() override;
|
bool IsInterruptSet() override;
|
||||||
|
@ -18,7 +18,7 @@ class CEXIMic : public IEXIDevice
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CEXIMic(Core::System& system, const int index);
|
CEXIMic(Core::System& system, const int index);
|
||||||
virtual ~CEXIMic();
|
~CEXIMic() override;
|
||||||
void SetCS(int cs) override;
|
void SetCS(int cs) override;
|
||||||
bool IsInterruptSet() override;
|
bool IsInterruptSet() override;
|
||||||
bool IsPresent() const override;
|
bool IsPresent() const override;
|
||||||
|
@ -33,7 +33,7 @@ class CEXIModem : public IEXIDevice
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CEXIModem(Core::System& system, ModemDeviceType type);
|
CEXIModem(Core::System& system, ModemDeviceType type);
|
||||||
virtual ~CEXIModem();
|
~CEXIModem() override;
|
||||||
void SetCS(int cs) override;
|
void SetCS(int cs) override;
|
||||||
bool IsPresent() const override;
|
bool IsPresent() const override;
|
||||||
bool IsInterruptSet() override;
|
bool IsInterruptSet() override;
|
||||||
@ -136,13 +136,13 @@ private:
|
|||||||
TAPServerNetworkInterface(CEXIModem* modem_ref, const std::string& destination);
|
TAPServerNetworkInterface(CEXIModem* modem_ref, const std::string& destination);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual bool Activate() override;
|
bool Activate() override;
|
||||||
virtual void Deactivate() override;
|
void Deactivate() override;
|
||||||
virtual bool IsActivated() override;
|
bool IsActivated() override;
|
||||||
virtual bool SendAndRemoveAllHDLCFrames(std::string* send_buffer) override;
|
bool SendAndRemoveAllHDLCFrames(std::string* send_buffer) override;
|
||||||
virtual bool RecvInit() override;
|
bool RecvInit() override;
|
||||||
virtual void RecvStart() override;
|
void RecvStart() override;
|
||||||
virtual void RecvStop() override;
|
void RecvStop() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TAPServerConnection m_tapserver_if;
|
TAPServerConnection m_tapserver_if;
|
||||||
|
@ -12,6 +12,10 @@
|
|||||||
#include <mgba/core/timing.h>
|
#include <mgba/core/timing.h>
|
||||||
#include <mgba/internal/gb/gb.h>
|
#include <mgba/internal/gb/gb.h>
|
||||||
#include <mgba/internal/gba/gba.h>
|
#include <mgba/internal/gba/gba.h>
|
||||||
|
#include <mz.h>
|
||||||
|
#include <mz_strm.h>
|
||||||
|
#include <mz_zip.h>
|
||||||
|
#include <mz_zip_rw.h>
|
||||||
|
|
||||||
#include "AudioCommon/AudioCommon.h"
|
#include "AudioCommon/AudioCommon.h"
|
||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
@ -88,21 +92,26 @@ static VFile* OpenROM_Archive(const char* path)
|
|||||||
static VFile* OpenROM_Zip(const char* path)
|
static VFile* OpenROM_Zip(const char* path)
|
||||||
{
|
{
|
||||||
VFile* vf{};
|
VFile* vf{};
|
||||||
unzFile zip = unzOpen(path);
|
void* zip_reader = mz_zip_reader_create();
|
||||||
if (!zip)
|
if (!zip_reader)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
Common::ScopeGuard file_guard{[&] { mz_zip_reader_delete(&zip_reader); }};
|
||||||
|
|
||||||
|
if (mz_zip_reader_open_file(zip_reader, path) != MZ_OK)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
unz_file_info info{};
|
mz_zip_file* info;
|
||||||
if (unzGetCurrentFileInfo(zip, &info, nullptr, 0, nullptr, 0, nullptr, 0) != UNZ_OK ||
|
if (mz_zip_reader_entry_get_info(zip_reader, &info) != MZ_OK || !info->uncompressed_size)
|
||||||
!info.uncompressed_size)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::vector<u8> buffer(info.uncompressed_size);
|
std::vector<u8> buffer(info->uncompressed_size);
|
||||||
if (!Common::ReadFileFromZip(zip, &buffer))
|
if (!Common::ReadFileFromZip(zip_reader, &buffer))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
vf = VFileMemChunk(buffer.data(), info.uncompressed_size);
|
vf = VFileMemChunk(buffer.data(), info->uncompressed_size);
|
||||||
if (mCoreIsCompatible(vf) == mPLATFORM_GBA)
|
if (mCoreIsCompatible(vf) == mPLATFORM_GBA)
|
||||||
{
|
{
|
||||||
vf->seek(vf, 0, SEEK_SET);
|
vf->seek(vf, 0, SEEK_SET);
|
||||||
@ -111,8 +120,7 @@ static VFile* OpenROM_Zip(const char* path)
|
|||||||
|
|
||||||
vf->close(vf);
|
vf->close(vf);
|
||||||
vf = nullptr;
|
vf = nullptr;
|
||||||
} while (unzGoToNextFile(zip) == UNZ_OK);
|
} while (mz_zip_reader_goto_next_entry(zip_reader) != MZ_END_OF_LIST);
|
||||||
unzClose(zip);
|
|
||||||
return vf;
|
return vf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ class GCMemcardDirectory : public MemoryCardBase
|
|||||||
public:
|
public:
|
||||||
GCMemcardDirectory(const std::string& directory, ExpansionInterface::Slot slot,
|
GCMemcardDirectory(const std::string& directory, ExpansionInterface::Slot slot,
|
||||||
const Memcard::HeaderData& header_data, u32 game_id);
|
const Memcard::HeaderData& header_data, u32 game_id);
|
||||||
~GCMemcardDirectory();
|
~GCMemcardDirectory() override;
|
||||||
|
|
||||||
GCMemcardDirectory(const GCMemcardDirectory&) = delete;
|
GCMemcardDirectory(const GCMemcardDirectory&) = delete;
|
||||||
GCMemcardDirectory& operator=(const GCMemcardDirectory&) = delete;
|
GCMemcardDirectory& operator=(const GCMemcardDirectory&) = delete;
|
||||||
|
@ -19,7 +19,7 @@ class MemoryCard : public MemoryCardBase
|
|||||||
public:
|
public:
|
||||||
MemoryCard(const std::string& filename, ExpansionInterface::Slot card_slot,
|
MemoryCard(const std::string& filename, ExpansionInterface::Slot card_slot,
|
||||||
u16 size_mbits = Memcard::MBIT_SIZE_MEMORY_CARD_2043);
|
u16 size_mbits = Memcard::MBIT_SIZE_MEMORY_CARD_2043);
|
||||||
~MemoryCard();
|
~MemoryCard() override;
|
||||||
void FlushThread();
|
void FlushThread();
|
||||||
void MakeDirty();
|
void MakeDirty();
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ class ConstantHandlingMethod : public ReadHandlingMethod<T>
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ConstantHandlingMethod(T value) : value_(value) {}
|
explicit ConstantHandlingMethod(T value) : value_(value) {}
|
||||||
virtual ~ConstantHandlingMethod() = default;
|
~ConstantHandlingMethod() override = default;
|
||||||
void AcceptReadVisitor(ReadHandlingMethodVisitor<T>& v) const override
|
void AcceptReadVisitor(ReadHandlingMethodVisitor<T>& v) const override
|
||||||
{
|
{
|
||||||
v.VisitConstant(value_);
|
v.VisitConstant(value_);
|
||||||
@ -62,7 +62,7 @@ class NopHandlingMethod : public WriteHandlingMethod<T>
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NopHandlingMethod() {}
|
NopHandlingMethod() {}
|
||||||
virtual ~NopHandlingMethod() = default;
|
~NopHandlingMethod() override = default;
|
||||||
void AcceptWriteVisitor(WriteHandlingMethodVisitor<T>& v) const override { v.VisitNop(); }
|
void AcceptWriteVisitor(WriteHandlingMethodVisitor<T>& v) const override { v.VisitNop(); }
|
||||||
};
|
};
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -79,7 +79,7 @@ class DirectHandlingMethod : public ReadHandlingMethod<T>, public WriteHandlingM
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DirectHandlingMethod(T* addr, u32 mask) : addr_(addr), mask_(mask) {}
|
DirectHandlingMethod(T* addr, u32 mask) : addr_(addr), mask_(mask) {}
|
||||||
virtual ~DirectHandlingMethod() = default;
|
~DirectHandlingMethod() override = default;
|
||||||
void AcceptReadVisitor(ReadHandlingMethodVisitor<T>& v) const override
|
void AcceptReadVisitor(ReadHandlingMethodVisitor<T>& v) const override
|
||||||
{
|
{
|
||||||
v.VisitDirect(addr_, mask_);
|
v.VisitDirect(addr_, mask_);
|
||||||
@ -122,7 +122,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~ComplexHandlingMethod() = default;
|
~ComplexHandlingMethod() override = default;
|
||||||
void AcceptReadVisitor(ReadHandlingMethodVisitor<T>& v) const override
|
void AcceptReadVisitor(ReadHandlingMethodVisitor<T>& v) const override
|
||||||
{
|
{
|
||||||
v.VisitComplex(&read_lambda_);
|
v.VisitComplex(&read_lambda_);
|
||||||
|
@ -21,7 +21,7 @@ class CSIDevice_GBAEmu final : public ISIDevice
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CSIDevice_GBAEmu(Core::System& system, SIDevices device, int device_number);
|
CSIDevice_GBAEmu(Core::System& system, SIDevices device, int device_number);
|
||||||
~CSIDevice_GBAEmu();
|
~CSIDevice_GBAEmu() override;
|
||||||
|
|
||||||
int RunBuffer(u8* buffer, int request_length) override;
|
int RunBuffer(u8* buffer, int request_length) override;
|
||||||
int TransferInterval() override;
|
int TransferInterval() override;
|
||||||
|
@ -311,7 +311,7 @@ void EmulateIMUCursor(IMUCursorState* state, ControllerEmu::IMUCursor* imu_ir_gr
|
|||||||
const auto ang_vel = imu_gyroscope_group->GetState();
|
const auto ang_vel = imu_gyroscope_group->GetState();
|
||||||
|
|
||||||
// Reset if pointing is disabled or we have no gyro data.
|
// Reset if pointing is disabled or we have no gyro data.
|
||||||
if (!imu_ir_group->enabled || !ang_vel.has_value())
|
if (!imu_ir_group->enabled.GetValue() || !ang_vel.has_value())
|
||||||
{
|
{
|
||||||
*state = {};
|
*state = {};
|
||||||
return;
|
return;
|
||||||
|
@ -120,7 +120,7 @@ protected:
|
|||||||
using EncryptedExtension::EncryptedExtension;
|
using EncryptedExtension::EncryptedExtension;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateEncryptionKey() final override;
|
void UpdateEncryptionKey() final;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Extension3rdParty : public EncryptedExtension
|
class Extension3rdParty : public EncryptedExtension
|
||||||
@ -129,7 +129,7 @@ protected:
|
|||||||
using EncryptedExtension::EncryptedExtension;
|
using EncryptedExtension::EncryptedExtension;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateEncryptionKey() final override;
|
void UpdateEncryptionKey() final;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace WiimoteEmu
|
} // namespace WiimoteEmu
|
||||||
|
@ -497,7 +497,7 @@ void Wiimote::BuildDesiredWiimoteState(DesiredWiimoteState* target_state,
|
|||||||
ConvertAccelData(GetTotalAcceleration(), ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2);
|
ConvertAccelData(GetTotalAcceleration(), ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2);
|
||||||
|
|
||||||
// Calculate IR camera state.
|
// Calculate IR camera state.
|
||||||
if (m_ir_passthrough->enabled)
|
if (m_ir_passthrough->enabled.GetValue())
|
||||||
{
|
{
|
||||||
target_state->camera_points = GetPassthroughCameraPoints(m_ir_passthrough);
|
target_state->camera_points = GetPassthroughCameraPoints(m_ir_passthrough);
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ public:
|
|||||||
static constexpr const char* SIDEWAYS_OPTION = "Sideways Wiimote";
|
static constexpr const char* SIDEWAYS_OPTION = "Sideways Wiimote";
|
||||||
|
|
||||||
explicit Wiimote(unsigned int index);
|
explicit Wiimote(unsigned int index);
|
||||||
~Wiimote();
|
~Wiimote() override;
|
||||||
|
|
||||||
std::string GetName() const override;
|
std::string GetName() const override;
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ class WiimoteScannerHidapi final : public WiimoteScannerBackend
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WiimoteScannerHidapi();
|
WiimoteScannerHidapi();
|
||||||
~WiimoteScannerHidapi();
|
~WiimoteScannerHidapi() override;
|
||||||
bool IsReady() const override;
|
bool IsReady() const override;
|
||||||
void FindWiimotes(std::vector<Wiimote*>&, Wiimote*&) override;
|
void FindWiimotes(std::vector<Wiimote*>&, Wiimote*&) override;
|
||||||
void Update() override {} // not needed for hidapi
|
void Update() override {} // not needed for hidapi
|
||||||
|
@ -233,7 +233,7 @@ class HotkeyManager : public ControllerEmu::EmulatedController
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HotkeyManager();
|
HotkeyManager();
|
||||||
~HotkeyManager();
|
~HotkeyManager() override;
|
||||||
|
|
||||||
void GetInput(HotkeyStatus* hk, bool ignore_focus);
|
void GetInput(HotkeyStatus* hk, bool ignore_focus);
|
||||||
std::string GetName() const override;
|
std::string GetName() const override;
|
||||||
|
@ -479,9 +479,7 @@ bool ESDevice::LaunchPPCTitle(u64 title_id)
|
|||||||
if (!Core::IsRunning(system))
|
if (!Core::IsRunning(system))
|
||||||
return BootstrapPPC();
|
return BootstrapPPC();
|
||||||
|
|
||||||
INFO_LOG_FMT(ACHIEVEMENTS,
|
AchievementManager::GetInstance().LoadGame(nullptr);
|
||||||
"WAD and NAND formats not currently supported by Achievement Manager.");
|
|
||||||
AchievementManager::GetInstance().CloseGame();
|
|
||||||
|
|
||||||
core_timing.RemoveEvent(s_bootstrap_ppc_for_launch_event);
|
core_timing.RemoveEvent(s_bootstrap_ppc_for_launch_event);
|
||||||
core_timing.ScheduleEvent(ticks, s_bootstrap_ppc_for_launch_event);
|
core_timing.ScheduleEvent(ticks, s_bootstrap_ppc_for_launch_event);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user