Compare commits
490 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fbe6900b28 | |||
| 7fe9802f87 | |||
| 14aebeac58 | |||
| 76bbbe27f1 | |||
| 9af52d12a8 | |||
| 5eb314fbbb | |||
| 655f7ce8a2 | |||
| c11074a128 | |||
| ef6854ca46 | |||
| 7e590eaa2f | |||
| 94478ad4a0 | |||
| e28e51463b | |||
| cb252b1ce2 | |||
| d37e770497 | |||
| 5871c4e93f | |||
| 50f51be06a | |||
| 8e5a03f171 | |||
| f72971f19f | |||
| eb140c52a4 | |||
| 198c84cabf | |||
| 5a73943be6 | |||
| 34a0c3f488 | |||
| 8762f2a588 | |||
| d7dd4897f8 | |||
| a84077f174 | |||
| 08f3460365 | |||
| be0e4e9879 | |||
| 799c3f9708 | |||
| 490f58ff3c | |||
| cb047fcc75 | |||
| ac2581659a | |||
| f335d034fc | |||
| 05bb6e1545 | |||
| 65eeee0f4c | |||
| bf4bdf73b7 | |||
| 30f7c81cc5 | |||
| 08ab9c4b04 | |||
| 4474757162 | |||
| bacd1698fc | |||
| e133c7a7dc | |||
| 0eabfdcadd | |||
| d86241bbcd | |||
| 42a0512c66 | |||
| 556aba46b5 | |||
| 2b853cc8bc | |||
| 00b74fb951 | |||
| ecd68dfc70 | |||
| d0b2eecc9a | |||
| d5c85f308a | |||
| f71cdb4eb8 | |||
| ee46ad1ca9 | |||
| 762c106e19 | |||
| 93552a5958 | |||
| c0fbf3091e | |||
| 49294a3dd2 | |||
| abfa303e07 | |||
| 5094ab8283 | |||
| a0d2bc9769 | |||
| e102dc2a94 | |||
| 5e59f18720 | |||
| b35a5982e8 | |||
| 4d3cdca7f6 | |||
| 0d4f8ca234 | |||
| 569e1c2df6 | |||
| 6e9392fb45 | |||
| df1813b4e2 | |||
| ff16e678a5 | |||
| 982856e70d | |||
| 144c20649f | |||
| e719bcf338 | |||
| 3f4226b70e | |||
| 620cfd5063 | |||
| 69b2e746fa | |||
| 2341749485 | |||
| 33abcf74f2 | |||
| 4e33ae319b | |||
| b083edccd3 | |||
| b59bb16fad | |||
| 3f943945a7 | |||
| 136d769895 | |||
| 9c9c2eb2c9 | |||
| 318a364d09 | |||
| fa02a04baa | |||
| 7eebe06931 | |||
| cd40bc8c61 | |||
| f6ebd88687 | |||
| 13ef0cc8c4 | |||
| df5059b142 | |||
| f7666f44da | |||
| 7b49249f5f | |||
| 64ed2f1151 | |||
| 17f335648c | |||
| 1dc2eb1cc8 | |||
| 1a702de9e4 | |||
| f1241c572c | |||
| 522daf5eac | |||
| e772dde3cc | |||
| 8b4b859091 | |||
| 18db020b93 | |||
| 7069e7265f | |||
| fa0bf6a92c | |||
| 758902382d | |||
| cc71d2c4bf | |||
| 9b7d28b5dd | |||
| b9ee53d82a | |||
| 479a64c4e8 | |||
| 7b54d386f2 | |||
| 7eccbecb2f | |||
| 2bab3afae0 | |||
| fa3fde7a29 | |||
| 3aa293a7a3 | |||
| 4befa36365 | |||
| 96be40bf30 | |||
| 3001701059 | |||
| fa41297b27 | |||
| b8f51398b7 | |||
| cb2129c7e4 | |||
| 703ec9f896 | |||
| 19350d024b | |||
| 8e68427daf | |||
| 6220206cbc | |||
| 1df1ceb4ea | |||
| 6178a0ab25 | |||
| 6bb083a77c | |||
| 171e6c6e54 | |||
| 313b967217 | |||
| b47a8b9995 | |||
| c4a1c6f845 | |||
| 24d3e2b2b8 | |||
| 145b80d262 | |||
| 5e75a0c497 | |||
| 972e0ab31d | |||
| 54f2c27ba0 | |||
| 0ba1f8f4ef | |||
| 4d7e53d7a0 | |||
| 0c757222cb | |||
| 0ed87be47a | |||
| e005581dda | |||
| 312fc94daa | |||
| 0dd417e5f2 | |||
| dd85e733d3 | |||
| 9e9ddf42c9 | |||
| 4d1f818162 | |||
| 3e0e1f668c | |||
| 4662ee0255 | |||
| 2f255a528e | |||
| 987223da3f | |||
| 78cc36cdd8 | |||
| 580b5cda0e | |||
| 81f974125c | |||
| 48c47eede4 | |||
| da036de3e4 | |||
| 92e3eaf3ff | |||
| 771eff273b | |||
| 0cf35e3b22 | |||
| 70bcb1cd52 | |||
| 762c8d5430 | |||
| aa9055f4c3 | |||
| 9d1833c5a8 | |||
| 583220b95a | |||
| 85bde0f43f | |||
| b96f064868 | |||
| 6de91a1691 | |||
| 1aa11440e0 | |||
| df8d0cde4a | |||
| 57a9844279 | |||
| f02b4801b2 | |||
| 727d783959 | |||
| fad8b38b28 | |||
| 8a176de6a1 | |||
| 0ee2f761ae | |||
| c48ceafc15 | |||
| ee6494c14b | |||
| a1456da24e | |||
| f08c778d2c | |||
| 90f4023cb8 | |||
| ea9abe7701 | |||
| 5c42d29c98 | |||
| 950940febe | |||
| 6e7fbc5c5c | |||
| 6a1a0bf48d | |||
| 244e74ebe2 | |||
| aa14432846 | |||
| afb594c233 | |||
| 7a7ac625cd | |||
| fe75311be2 | |||
| 812d03894b | |||
| 5e6b1003ec | |||
| a08ed0d22e | |||
| b5ed73ebe0 | |||
| c1bdaccd8c | |||
| 4421831c8b | |||
| d03804b523 | |||
| 634c4355fe | |||
| ee54ba970a | |||
| 23f1515448 | |||
| 4018b833ad | |||
| ddf87864de | |||
| 299af768e8 | |||
| e645627b78 | |||
| 1cb1d14d0c | |||
| 1c2df15755 | |||
| 687bb1697b | |||
| 04e0bf2eff | |||
| eb8710d3c1 | |||
| e98fcfdf77 | |||
| cdda19c79f | |||
| fa9330d0e0 | |||
| 1d4595a349 | |||
| 9344b21484 | |||
| 07f300a14e | |||
| ddeb39d8de | |||
| 0d7aa5e310 | |||
| 606693a9f7 | |||
| 78c49e7331 | |||
| 9760053c8c | |||
| e8988faed5 | |||
| 7137142351 | |||
| bacd234258 | |||
| 3006b003c4 | |||
| e30637351e | |||
| d2b83c69bb | |||
| bcbe324534 | |||
| dcb30df7c8 | |||
| bdab26ec09 | |||
| f47333997f | |||
| 3787108ee7 | |||
| 30d176ac5e | |||
| 98f91457bf | |||
| 6847e52364 | |||
| 896d16ec7b | |||
| 6862790cf7 | |||
| 639245c071 | |||
| 034267adb2 | |||
| 6e47a6fb76 | |||
| 9569ae24e0 | |||
| 491526b421 | |||
| 5a41d75eb8 | |||
| 4bc431ec31 | |||
| 1bc9fd2863 | |||
| 5d82b0f4c4 | |||
| d3abff5486 | |||
| 77aa1fbeea | |||
| af9bc631cc | |||
| 762718002e | |||
| 16bbd93885 | |||
| 80eff58950 | |||
| 7ea4eb0095 | |||
| efc8c3f4a9 | |||
| 792c481f6d | |||
| 7973b01b1c | |||
| 11675d7645 | |||
| 1915fe75a4 | |||
| 9d1bb60ad7 | |||
| b7043ce000 | |||
| c64935f9dd | |||
| 629eddfb9f | |||
| 1f94c8f272 | |||
| 0c8611bd49 | |||
| 5dcb91b671 | |||
| 7abda27b46 | |||
| 901fc87bca | |||
| 54da9ac7e5 | |||
| e45360de2b | |||
| d59c449ff6 | |||
| 17df6c8878 | |||
| f901846acb | |||
| edcd2fc14a | |||
| 382bdcdcb7 | |||
| 1bbc60c3e7 | |||
| c13d345604 | |||
| efe907ffae | |||
| 0bba04ef8d | |||
| 43dae6c14d | |||
| 2b5c24b304 | |||
| 50b1e26b17 | |||
| 18e0559438 | |||
| 37513b1898 | |||
| fbbad7c851 | |||
| f8b3c48af7 | |||
| 3cc42c1bf8 | |||
| b6422c9a33 | |||
| 049e392a97 | |||
| 9a64d08c9f | |||
| c0f80cfe7a | |||
| 49e11b7cfd | |||
| 6a32ceaab5 | |||
| acc7320cae | |||
| 1a78e0e80c | |||
| e9e8f0c5b7 | |||
| cb52ee0a4d | |||
| 4488312e81 | |||
| 9d9b5c4d66 | |||
| b9ec012922 | |||
| d47a8b49a4 | |||
| 1759d6d90a | |||
| c4a01875d0 | |||
| f9a8efe406 | |||
| 7f4e546f19 | |||
| 0a2874405d | |||
| 87a5dd66ab | |||
| e57c01907e | |||
| 32df809626 | |||
| 7d2ed9200d | |||
| f6e90b4c72 | |||
| c1180d76dd | |||
| 6dfd97f0b6 | |||
| 327bb2d8f0 | |||
| 21f7b0ff0f | |||
| 15391f45d0 | |||
| 3c0bd821c8 | |||
| ec80932c21 | |||
| 3eca2d5d6c | |||
| d9a0619ddd | |||
| efafda2650 | |||
| 943368912b | |||
| 1d0f359406 | |||
| d5f019c3d3 | |||
| 67075dfc6c | |||
| a867522b16 | |||
| 26cccead6e | |||
| e6f7467f67 | |||
| 36d5db7f30 | |||
| e7b24461ec | |||
| 007a7a5859 | |||
| 59a0f810b9 | |||
| 9f678cc47a | |||
| aeebcfe141 | |||
| 48a847d1b6 | |||
| 232c6c3aaf | |||
| c9e35926f5 | |||
| 8ef69429d8 | |||
| 336cd6e33a | |||
| 360e484b08 | |||
| 92466165f6 | |||
| 1206a5d4b7 | |||
| c1d7b46235 | |||
| 795bc5d52b | |||
| ad8988afd3 | |||
| 7f07b79c04 | |||
| 610a6a1404 | |||
| a7aef22754 | |||
| 4e0070f16d | |||
| 7ae679adbe | |||
| d481c3c7fd | |||
| a9162a3f57 | |||
| b341113ad8 | |||
| 1e69de1205 | |||
| 79216917b3 | |||
| 698702cd4a | |||
| 1166ae19bb | |||
| 44f2cacf7b | |||
| 7a275eaa3a | |||
| 331c1a394a | |||
| e4ba096190 | |||
| 46df58b662 | |||
| 95ed2ef62e | |||
| 3f076d63e3 | |||
| 3e8a5c6395 | |||
| 18f167ddd0 | |||
| 1abdee242a | |||
| adcc3e9c4b | |||
| 949cfa7fdb | |||
| fe381b8581 | |||
| 160ddcf86b | |||
| f05a3da964 | |||
| ddda09607d | |||
| 9993df9b8b | |||
| 98a8eeaac2 | |||
| 0f87c6c7c3 | |||
| 0147bc2c72 | |||
| 1e7a02badb | |||
| 3617f12a1e | |||
| 63f67c88cc | |||
| 1b1b804d7e | |||
| 55cb96ab3b | |||
| 5ef3465f65 | |||
| 9a27cc9442 | |||
| 858ce014fd | |||
| 4dbad6cce6 | |||
| 485b22d664 | |||
| 30d5a849e3 | |||
| 9ef96e8274 | |||
| cbaa8f3329 | |||
| 807d6cfea4 | |||
| 22ca2827de | |||
| 5e0ca4c0c4 | |||
| 48407752a6 | |||
| bad4d1ff05 | |||
| 7453e46a7c | |||
| b07b5c9005 | |||
| 9d15083c61 | |||
| 14b99d9e8b | |||
| b36b9e4822 | |||
| 0a2b6a290d | |||
| ca5bc512ae | |||
| 449cbb7281 | |||
| e2512e78b6 | |||
| a005090d3d | |||
| 7fcc49004d | |||
| 833fbe015e | |||
| c9b0f0e734 | |||
| 9b34f00241 | |||
| 82af17beb1 | |||
| 47b196e9d0 | |||
| db014d8a58 | |||
| 621fab2ad9 | |||
| 086ecf4ba6 | |||
| 309251ce7a | |||
| 9084209cfc | |||
| 74ad525566 | |||
| 05e5e6058f | |||
| 556ac1cf22 | |||
| 85695c8bac | |||
| 2984300385 | |||
| ac4cadf538 | |||
| 175f78f5b3 | |||
| 3d96fe79cc | |||
| 1ccb3c4492 | |||
| 01035d35bd | |||
| 8bbda3dedb | |||
| a24514651c | |||
| 542d2ef8da | |||
| be2d225d96 | |||
| 765bd6b6c6 | |||
| aeed349a99 | |||
| 8447d75dda | |||
| fc6356a74c | |||
| 41f2ee7b6c | |||
| 87cd653c6e | |||
| 7e35fd54a8 | |||
| 582ee80552 | |||
| 0b4b87f069 | |||
| a8e1afa0af | |||
| 71df5044fc | |||
| db5d03c340 | |||
| 4a5559ee65 | |||
| 7523416a12 | |||
| 9075208c80 | |||
| d477889763 | |||
| ef3b0db7d8 | |||
| f5cb147f8d | |||
| 63e669c0cf | |||
| 9c54305e10 | |||
| f3d52de429 | |||
| 3f34a0196c | |||
| ecf00be155 | |||
| 071e73a68e | |||
| ad845861be | |||
| c51779d4d3 | |||
| 55f9a56e45 | |||
| 5bace118a7 | |||
| 28770c1580 | |||
| 192912131e | |||
| 94d2f97f27 | |||
| 632cc79c54 | |||
| e7845357e2 | |||
| 4450ae0c7a | |||
| 9fc0aec066 | |||
| bed2d558a6 | |||
| d5f0957558 | |||
| 7f09def94e | |||
| b88fb43acc | |||
| e7ddc5187a | |||
| 872be25ed1 | |||
| 9d2c9e5d62 | |||
| 28fb0d1741 | |||
| 5534c9e27c | |||
| 049f852a9c | |||
| 69f11d82d1 | |||
| f92794360d | |||
| bdb5115c7f | |||
| 3ada97d2d3 | |||
| 49d5ce3ba4 | |||
| 691a57a4da | |||
| 671ae20876 | |||
| 7af7e3cec1 | |||
| ca52c1e2d1 | |||
| 31b07fece5 | |||
| b3ad89cc8b | |||
| 5e7d25ad35 | |||
| d94d094a7e | |||
| c9aee27d48 | |||
| d12762414a | |||
| 7786681954 | |||
| 02ca8f0002 | |||
| 7af2ebb6f4 | |||
| 2c4ecc55af | |||
| c4e59b5115 | |||
| 4c20881f8f |
@@ -1,24 +0,0 @@
|
||||
<!---
|
||||
|
||||
THIS IS NOT A SUPPORT FORUM, FOR SUPPORT GO TO:
|
||||
https://forums.rpcs3.net
|
||||
or our discord:
|
||||
https://discord.me/RPCS3
|
||||
|
||||
PLEASE READ THE GUIDELINES BEFORE OPENING AN ISSUE:
|
||||
https://github.com/RPCS3/rpcs3/blob/master/.github/CONTRIBUTING.md
|
||||
|
||||
====================================================
|
||||
|
||||
When submitting an issue, please check the following:
|
||||
|
||||
- You have read the above.
|
||||
- You have provided the version (commit hash) of RPCS3 you are using.
|
||||
- You have provided sufficient detail for the issue to be reproduced.
|
||||
- You have provided system specs.
|
||||
- Please also provide:
|
||||
- For crashes, a backtrace.
|
||||
- For graphical issues, comparison screenshots with real hardware.
|
||||
|
||||
Remember that the GitHub Issue Tracker is not the place to ask for support or to submit Game Compatibility reports. You must use our forums for that.
|
||||
--->
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: Regression report
|
||||
about: If something worked before, but now it doesn't
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!---
|
||||
Please do not ask for help or report compatibility regressions here, use RPCS3 Discord server or forums instead.
|
||||
|
||||
Please read Contributing guide under Helpful resources on the right. →
|
||||
--->
|
||||
|
||||
## Quick summary
|
||||
Please describe what exactly has stopped working correctly
|
||||
|
||||
## Details
|
||||
Please provide _exact_ build (or commit) information that introduced the regression you're reporting.
|
||||
Please see How to find the build that caused a regression in wiki: https://wiki.rpcs3.net/index.php?title=Help:Using_different_versions_of_RPCS3#How_to_find_the_build_that_caused_a_regression.3F
|
||||
You can find old builds here: https://rpcs3.net/compatibility?b
|
||||
|
||||
Please remember to attach TWO logs: one for the build that exhibits regression, and one for the previous build that works as expected.
|
||||
|
||||
If the regression caused a graphical issue, please provide RSX capture and a Renderdoc capture that demonstrate the issue.
|
||||
To create an RSX capture, enable Debugger view (View → Show Debugger) and use the RSX Capture button. Captues will be stored in RPCS3 folder → captures.
|
||||
To create Renderdoc capture, please refer to Renderdoc documentation https://renderdoc.org/docs/how/how_capture_frame.html
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: If something doesn't work correctly in RPCS3
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!---
|
||||
Please do not ask for help or general inquiry here, use RPCS3 Discord server instead.
|
||||
|
||||
Please read Contributing guide under Helpful resources on the right. →
|
||||
--->
|
||||
|
||||
## Quick summary
|
||||
Please summarize the issue here
|
||||
|
||||
## Details
|
||||
Please provide as much detail as you can here, including
|
||||
- expected (real hw) and observed (emulator) behavior
|
||||
- full logs (not from UI)
|
||||
- back traces (for hard crashes)
|
||||
- screenshots, Renderdoc, and RSX captures (for visual issues)
|
||||
- your system configuration (OS, CPU, GPU, driver versions, etc)
|
||||
- anything else you deem to be important
|
||||
@@ -0,0 +1,11 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Quickstart guide
|
||||
url: https://rpcs3.net/quickstart
|
||||
about: Everything you need to know to install and configure emulator, and add games
|
||||
- name: Ask for help
|
||||
url: https://discord.me/RPCS3
|
||||
about: If you have some questions or need help, please use our Discord server instead of GitHub
|
||||
- name: Report game compatibility
|
||||
url: https://forums.rpcs3.net/thread-196671.html
|
||||
about: Please use RPCS3 forums to submit or update game compatibility status
|
||||
@@ -37,6 +37,7 @@
|
||||
/rpcs3/Debug
|
||||
/rpcs3/Release
|
||||
/llvm_build
|
||||
/3rdparty/llvm_build
|
||||
/Vulkan/Vulkan-build
|
||||
/Vulkan/glslang-build
|
||||
|
||||
@@ -71,10 +72,15 @@ Makefile
|
||||
*CMakeFiles*
|
||||
CMakeCache.txt
|
||||
*cmake_install.cmake*
|
||||
CPackConfig.cmake
|
||||
CPackSourceConfig.cmake
|
||||
compile_commands.json
|
||||
|
||||
# cotire
|
||||
rpcs3/cotire/*
|
||||
rpcs3/rpcs3_*_cotire.cmake
|
||||
rpcs3/Emu/rpcs3_emu_CXX_Release_cotire.cmake
|
||||
rpcs3/Emu/rpcs3_emu_CXX_cotire.cmake
|
||||
|
||||
# kdevelop
|
||||
*.kdev4
|
||||
@@ -99,3 +105,6 @@ CMakeLists.txt.user
|
||||
|
||||
# 7zlib
|
||||
/3rdparty/7z/**/*.lib
|
||||
|
||||
# yaml-cpp
|
||||
yaml-cpp.pc
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
[submodule "rpcs3-ffmpeg"]
|
||||
path = 3rdparty/ffmpeg
|
||||
url = https://github.com/hrydgard/ppsspp-ffmpeg
|
||||
url = https://github.com/RPCS3/ffmpeg-core
|
||||
ignore = dirty
|
||||
[submodule "asmjit"]
|
||||
path = asmjit
|
||||
@@ -9,7 +9,6 @@
|
||||
[submodule "llvm"]
|
||||
path = llvm
|
||||
url = https://github.com/RPCS3/llvm
|
||||
branch = release_60
|
||||
ignore = dirty
|
||||
[submodule "Vulkan/glslang"]
|
||||
path = Vulkan/glslang
|
||||
@@ -46,7 +45,7 @@
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/libusb"]
|
||||
path = 3rdparty/libusb
|
||||
url = https://github.com/RPCS3/libusb.git
|
||||
url = https://github.com/libusb/libusb.git
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/FAudio"]
|
||||
path = 3rdparty/FAudio
|
||||
@@ -55,3 +54,4 @@
|
||||
[submodule "3rdparty/span"]
|
||||
path = 3rdparty/span
|
||||
url = https://github.com/tcbrindle/span
|
||||
ignore = dirty
|
||||
|
||||
+18
-18
@@ -1,31 +1,29 @@
|
||||
language: cpp
|
||||
matrix:
|
||||
jobs:
|
||||
include:
|
||||
# - os: linux
|
||||
# env:
|
||||
# - NAME="Linux build"
|
||||
# - COMPILER="gcc"
|
||||
# services: docker
|
||||
# cache: ccache
|
||||
# install: "docker pull rpcs3/rpcs3-travis-xenial:1.0"
|
||||
# script: 'travis_wait docker run -v $(pwd):/rpcs3 -v "$HOME/.ccache":/root/.ccache --env-file .travis/travis.env rpcs3/rpcs3-travis-xenial:1.0 /bin/bash -ex /rpcs3/.travis/build-linux.bash'
|
||||
- os: linux
|
||||
dist: xenial
|
||||
env:
|
||||
- NAME="Linux build"
|
||||
- COMPILER="gcc"
|
||||
- DEPLOY_APPIMAGE="true"
|
||||
services: docker
|
||||
cache: ccache
|
||||
compiler: gcc
|
||||
install: "docker pull rpcs3/rpcs3-travis-xenial:1.2"
|
||||
script: 'travis_wait docker run -v $(pwd):/rpcs3 -v "$HOME/.ccache":/root/.ccache --env-file .travis/travis.env rpcs3/rpcs3-travis-xenial:1.2 /bin/bash -ex /rpcs3/.travis/build-linux.bash'
|
||||
- os: linux
|
||||
dist: xenial
|
||||
env:
|
||||
- NAME="Linux build"
|
||||
- COMPILER="clang"
|
||||
- DEPLOY_APPIMAGE="true"
|
||||
services: docker
|
||||
cache: ccache
|
||||
install: "docker pull rpcs3/rpcs3-travis-xenial:1.0"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libsdl2-2.0
|
||||
- libsdl2-dev
|
||||
script: 'travis_wait docker run -v $(pwd):/rpcs3 -v "$HOME/.ccache":/root/.ccache --env-file .travis/travis.env rpcs3/rpcs3-travis-xenial:1.0 /bin/bash -ex /rpcs3/.travis/build-linux.bash'
|
||||
compiler: clang
|
||||
install: "docker pull rpcs3/rpcs3-travis-xenial:1.2"
|
||||
script: 'travis_wait docker run -v $(pwd):/rpcs3 -v "$HOME/.ccache":/root/.ccache --env-file .travis/travis.env rpcs3/rpcs3-travis-xenial:1.2 /bin/bash -ex /rpcs3/.travis/build-linux.bash'
|
||||
- os: osx
|
||||
osx_image: xcode10.2
|
||||
osx_image: xcode11.3
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
@@ -35,6 +33,8 @@ matrix:
|
||||
- qt
|
||||
script: "/bin/bash -ex .travis/build-mac.bash"
|
||||
cache: ccache
|
||||
allow_failures:
|
||||
- os: osx
|
||||
|
||||
git:
|
||||
depth: false # Unshallow clone to obtain proper GIT_VERSION
|
||||
|
||||
@@ -26,7 +26,7 @@ else
|
||||
export CXX=${CLANGXX_BINARY}
|
||||
fi
|
||||
|
||||
cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_LLVM_SUBMODULE=OFF -DLLVM_DIR=llvmlibs/lib/cmake/llvm/ -DUSE_NATIVE_INSTRUCTIONS=OFF -G Ninja
|
||||
cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_LLVM_SUBMODULE=OFF -DUSE_COTIRE=OFF -DLLVM_DIR=llvmlibs/lib/cmake/llvm/ -DUSE_NATIVE_INSTRUCTIONS=OFF -G Ninja
|
||||
|
||||
ninja; build_status=$?;
|
||||
|
||||
|
||||
@@ -26,7 +26,8 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
|
||||
# This may need updating if you update the compiler or rpcs3 uses newer c++ features
|
||||
# See https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/config/abi/pre/gnu.ver
|
||||
# for which definitions correlate to which CXXABI version.
|
||||
printf "#include <memory>\nint main(){std::make_exception_ptr(0);}" | $CXX -x c++ -o ./appdir/usr/optional/checker -
|
||||
# Currently we target a minimum of GLIBCXX_3.4.26 and CXXABI_1.3.11
|
||||
printf "#include <bits/stdc++.h>\nint main(){std::make_exception_ptr(0);std::pmr::get_default_resource();}" | $CXX -x c++ -std=c++2a -o ./appdir/usr/optional/checker -
|
||||
|
||||
# Package it up and send it off
|
||||
./squashfs-root/usr/bin/appimagetool /rpcs3/build/appdir
|
||||
|
||||
Vendored
-1
@@ -204,7 +204,6 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
|
||||
Vendored
+20
-19
@@ -1,14 +1,6 @@
|
||||
find_package(PkgConfig)
|
||||
include(ExternalProject)
|
||||
|
||||
if(APPLE)
|
||||
set(PLATFORM_ARCH "macosx/x86_64")
|
||||
elseif(WIN32)
|
||||
set(PLATFORM_ARCH "Windows/x86_64")
|
||||
else()
|
||||
set(PLATFORM_ARCH "linux/x86_64")
|
||||
endif()
|
||||
|
||||
# Dummy target to use when lib isn't available
|
||||
add_library(3rdparty_dummy_lib INTERFACE)
|
||||
|
||||
@@ -146,9 +138,9 @@ if(CMAKE_SYSTEM MATCHES "DragonFly|FreeBSD")
|
||||
elseif(MSVC)
|
||||
# Windows time.h defines timespec but doesn't add any flag for it, which makes libusb attempt to define it again
|
||||
add_definitions(-DHAVE_STRUCT_TIMESPEC=1)
|
||||
add_subdirectory(libusb EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(libusb_cmake EXCLUDE_FROM_ALL)
|
||||
else()
|
||||
add_subdirectory(libusb EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(libusb_cmake EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -345,6 +337,7 @@ if(USE_FAUDIO)
|
||||
if (NOT SDL2_FOUND OR SDL2_VERSION VERSION_LESS 2.0.9)
|
||||
message("-- RPCS3: FAudio requires SDL 2.0.9 or newer.")
|
||||
else()
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared library")
|
||||
add_subdirectory(FAudio EXCLUDE_FROM_ALL)
|
||||
target_compile_definitions(FAudio INTERFACE -DHAVE_FAUDIO)
|
||||
set(FAUDIO_TARGET FAudio)
|
||||
@@ -362,8 +355,6 @@ if(USE_SYSTEM_FFMPEG)
|
||||
target_include_directories(3rdparty_ffmpeg INTERFACE ${FFMPEG_INCLUDE_DIR})
|
||||
target_link_libraries(3rdparty_ffmpeg INTERFACE ${FFMPEG_LIBRARIES})
|
||||
else()
|
||||
set(FFMPEG_PLATFORM_DIR "ffmpeg/${PLATFORM_ARCH}")
|
||||
|
||||
if (NOT MSVC AND WIN32)
|
||||
message("-- RPCS3: building ffmpeg submodule")
|
||||
|
||||
@@ -371,26 +362,36 @@ else()
|
||||
DOWNLOAD_COMMAND ""
|
||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ffmpeg
|
||||
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/ffmpeg
|
||||
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/ffmpeg/configure --prefix=./Windows/x86_64 --arch=x86_64 --disable-avdevice --disable-programs --disable-avfilter --disable-postproc --disable-doc --disable-pthreads --enable-w32threads --disable-network --disable-everything --disable-encoders --disable-muxers --disable-hwaccels --disable-parsers --disable-protocols --enable-dxva2 --enable-static --disable-shared --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=atrac3 --enable-decoder=atrac3p --enable-decoder=mp3 --enable-decoder=pcm_s16le --enable-decoder=pcm_s8 --enable-decoder=h264 --enable-decoder=mpeg4 --enable-decoder=mpeg2video --enable-decoder=mjpeg --enable-decoder=mjpegb --enable-encoder=pcm_s16le --enable-encoder=ffv1 --enable-encoder=mpeg4 --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=mpegvideo --enable-parser=mjpeg --enable-parser=aac --enable-parser=aac_latm --enable-muxer=avi --enable-demuxer=h264 --enable-demuxer=m4v --enable-demuxer=mp3 --enable-demuxer=mpegvideo --enable-demuxer=mpegps --enable-demuxer=mjpeg --enable-demuxer=avi --enable-demuxer=aac --enable-demuxer=pmp --enable-demuxer=oma --enable-demuxer=pcm_s16le --enable-demuxer=pcm_s8 --enable-demuxer=wav --enable-hwaccel=h264_dxva2 --enable-indev=dshow --enable-protocol=file
|
||||
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/ffmpeg/configure --prefix=./windows/x86_64 --arch=x86_64 --disable-avdevice --disable-programs --disable-avfilter --disable-postproc --disable-doc --disable-pthreads --enable-w32threads --disable-network --disable-everything --disable-encoders --disable-muxers --disable-hwaccels --disable-parsers --disable-protocols --enable-dxva2 --enable-static --disable-shared --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=atrac3 --enable-decoder=atrac3p --enable-decoder=mp3 --enable-decoder=pcm_s16le --enable-decoder=pcm_s8 --enable-decoder=h264 --enable-decoder=mpeg4 --enable-decoder=mpeg2video --enable-decoder=mjpeg --enable-decoder=mjpegb --enable-encoder=pcm_s16le --enable-encoder=ffv1 --enable-encoder=mpeg4 --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=mpegvideo --enable-parser=mjpeg --enable-parser=aac --enable-parser=aac_latm --enable-muxer=avi --enable-demuxer=h264 --enable-demuxer=m4v --enable-demuxer=mp3 --enable-demuxer=mpegvideo --enable-demuxer=mpegps --enable-demuxer=mjpeg --enable-demuxer=avi --enable-demuxer=aac --enable-demuxer=pmp --enable-demuxer=oma --enable-demuxer=pcm_s16le --enable-demuxer=pcm_s8 --enable-demuxer=wav --enable-hwaccel=h264_dxva2 --enable-indev=dshow --enable-protocol=file
|
||||
BUILD_COMMAND make -j 4
|
||||
INSTALL_COMMAND make install
|
||||
)
|
||||
|
||||
set(FFMPEG_LIB_AVFORMAT "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/${PLATFORM_ARCH}/lib/libavformat.a")
|
||||
set(FFMPEG_LIB_AVCODEC "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/${PLATFORM_ARCH}/lib/libavcodec.a")
|
||||
set(FFMPEG_LIB_AVUTIL "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/${PLATFORM_ARCH}/lib/libavutil.a")
|
||||
set(FFMPEG_LIB_SWSCALE "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/${PLATFORM_ARCH}/lib/libswscale.a")
|
||||
set(FFMPEG_LIB_AVFORMAT "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/windows/x86_64/lib/libavformat.a")
|
||||
set(FFMPEG_LIB_AVCODEC "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/windows/x86_64/lib/libavcodec.a")
|
||||
set(FFMPEG_LIB_AVUTIL "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/windows/x86_64/lib/libavutil.a")
|
||||
set(FFMPEG_LIB_SWSCALE "${CMAKE_CURRENT_BINARY_DIR}/ffmpeg/windows/x86_64/lib/libswscale.a")
|
||||
else()
|
||||
message("-- RPCS3: using builtin ffmpeg")
|
||||
|
||||
set(FFMPEG_LIB_DIR "${FFMPEG_PLATFORM_DIR}/lib")
|
||||
if (WIN32)
|
||||
set(FFMPEG_LIB_DIR "ffmpeg/windows/x86_64")
|
||||
target_link_libraries(3rdparty_ffmpeg INTERFACE "Bcrypt.lib")
|
||||
elseif(CMAKE_SYSTEM MATCHES "Linux")
|
||||
set(FFMPEG_LIB_DIR "ffmpeg/linux/x86_64")
|
||||
elseif(APPLE)
|
||||
set(FFMPEG_LIB_DIR "ffmpeg/macos/x86_64")
|
||||
else()
|
||||
message(FATAL_ERROR "Prebuilt ffmpeg is not available on this platform! Try USE_SYSTEM_FFMPEG=ON.")
|
||||
endif()
|
||||
|
||||
find_library(FFMPEG_LIB_AVFORMAT avformat PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
|
||||
find_library(FFMPEG_LIB_AVCODEC avcodec PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
|
||||
find_library(FFMPEG_LIB_AVUTIL avutil PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
|
||||
find_library(FFMPEG_LIB_SWSCALE swscale PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
target_include_directories(3rdparty_ffmpeg INTERFACE "${FFMPEG_PLATFORM_DIR}/include")
|
||||
target_include_directories(3rdparty_ffmpeg INTERFACE "ffmpeg/include")
|
||||
|
||||
target_link_libraries(3rdparty_ffmpeg
|
||||
INTERFACE
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/FAudio updated: f86adca2bd...9c7d2d1430
Vendored
+2
-2
@@ -31,9 +31,9 @@ extern "C" {
|
||||
#define ALC_VERSION_0_1 1
|
||||
|
||||
/** Opaque device handle */
|
||||
typedef struct ALCdevice_struct ALCdevice;
|
||||
typedef struct ALCdevice ALCdevice;
|
||||
/** Opaque context handle */
|
||||
typedef struct ALCcontext_struct ALCcontext;
|
||||
typedef struct ALCcontext ALCcontext;
|
||||
|
||||
/** 8-bit boolean */
|
||||
typedef char ALCboolean;
|
||||
|
||||
Vendored
+21
@@ -509,6 +509,27 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef AL_SOFT_direct_channels_remix
|
||||
#define AL_SOFT_direct_channels_remix 1
|
||||
#define AL_DROP_UNMATCHED_SOFT 0x0001
|
||||
#define AL_REMIX_UNMATCHED_SOFT 0x0002
|
||||
#endif
|
||||
|
||||
#ifndef AL_SOFT_bformat_ex
|
||||
#define AL_SOFT_bformat_ex 1
|
||||
#define AL_AMBISONIC_LAYOUT_SOFT 0x1997
|
||||
#define AL_AMBISONIC_SCALING_SOFT 0x1998
|
||||
|
||||
/* Ambisonic layouts */
|
||||
#define AL_FUMA_SOFT 0x0000
|
||||
#define AL_ACN_SOFT 0x0001
|
||||
|
||||
/* Ambisonic scalings (normalization) */
|
||||
/*#define AL_FUMA_SOFT*/
|
||||
#define AL_SN3D_SOFT 0x0001
|
||||
#define AL_N3D_SOFT 0x0002
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Vendored
+1
@@ -1,6 +1,7 @@
|
||||
#ifndef AL_EFX_H
|
||||
#define AL_EFX_H
|
||||
|
||||
#include <float.h>
|
||||
|
||||
#include "alc.h"
|
||||
#include "al.h"
|
||||
|
||||
BIN
Binary file not shown.
+127
-11
@@ -7,11 +7,31 @@
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef __XAUDIO2_INCLUDED__
|
||||
#define __XAUDIO2_INCLUDED__
|
||||
|
||||
#include <sdkddkver.h>
|
||||
|
||||
// Current name of the DLL shipped in the same SDK as this header.
|
||||
// The name reflects the current version
|
||||
#define XAUDIO2_DLL_A "xaudio2redist.dll"
|
||||
#define XAUDIO2_DLL_W L"xaudio2redist.dll"
|
||||
#define XAUDIO2D_DLL_A "xaudio2redist.dll"
|
||||
#define XAUDIO2D_DLL_W L"xaudio2redist.dll"
|
||||
|
||||
#ifdef UNICODE
|
||||
#define XAUDIO2_DLL XAUDIO2_DLL_W
|
||||
#define XAUDIO2D_DLL XAUDIO2D_DLL_W
|
||||
#else
|
||||
#define XAUDIO2_DLL XAUDIO2_DLL_A
|
||||
#define XAUDIO2D_DLL XAUDIO2D_DLL_A
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* XAudio2 COM object class and interface IDs.
|
||||
@@ -20,8 +40,19 @@
|
||||
|
||||
#include <basetyps.h>
|
||||
|
||||
// XAudio 2.8
|
||||
interface __declspec(uuid("60d8dac8-5aa1-4e8e-b597-2f5e2883d484")) IXAudio2;
|
||||
#ifdef __cplusplus
|
||||
// XAudio 2.9
|
||||
interface __declspec(uuid("2B02E3CF-2E0B-4ec3-BE45-1B2A3FE7210D")) IXAudio2;
|
||||
interface __declspec(uuid("84ac29bb-d619-44d2-b197-e4acf7df3ed6")) IXAudio2Extension;
|
||||
EXTERN_C const GUID DECLSPEC_SELECTANY IID_IXAudio2Extension = __uuidof(IXAudio2Extension);
|
||||
EXTERN_C const GUID DECLSPEC_SELECTANY IID_IXAudio2 = __uuidof(IXAudio2);
|
||||
|
||||
#else // #ifdef __cplusplus
|
||||
// Compiling with C for Windows 10 and later
|
||||
DEFINE_GUID(IID_IXAudio2, 0x2B02E3CF, 0x2E0B, 0x4ec3, 0xBE, 0x45, 0x1B, 0x2A, 0x3F, 0xE7, 0x21, 0x0D);
|
||||
DEFINE_GUID(IID_IXAudio2Extension, 0x84ac29bb, 0xd619, 0x44d2, 0xb1, 0x97, 0xe4, 0xac, 0xf7, 0xdf, 0x3e, 0xd6);
|
||||
#endif // #ifdef __cplusplus
|
||||
|
||||
|
||||
// Ignore the rest of this header if only the GUID definitions were requested
|
||||
#ifndef GUID_DEFS_ONLY
|
||||
@@ -31,6 +62,31 @@ interface __declspec(uuid("60d8dac8-5aa1-4e8e-b597-2f5e2883d484")) IXAudio2;
|
||||
#include <mmreg.h> // Basic data types and constants for audio work
|
||||
#include <audiosessiontypes.h> // For AUDIO_STREAM_CATEGORY
|
||||
|
||||
// The Windows 7 version of audiosessiontypes.h does not define AUDIO_STREAM_CATEGORY, so if we are targeting
|
||||
// Windows 7 we might have to define it here, depending on which SDK is used.
|
||||
#if _WIN32_WINNT < _WIN32_WINNT_WIN8
|
||||
|
||||
// If we are compiling for Windows 7, we might be using the Windows 7 Platform SDK, which does not have AUDIO_STREAM_CATEGORY.
|
||||
// But we might be using a newer SDK (such as the Win8 Platform SDK), which has AUDIO_STREAM_CATEGORY.
|
||||
// Determine if we are using the Windows 7 Platform SDK by checking if WAVE_FORMAT_WM9_SPECTRUM_ANALYZER is defined.
|
||||
#ifndef WAVE_FORMAT_WM9_SPECTRUM_ANALYZER
|
||||
typedef enum _AUDIO_STREAM_CATEGORY
|
||||
{
|
||||
AudioCategory_Other = 0,
|
||||
AudioCategory_ForegroundOnlyMedia = 1,
|
||||
AudioCategory_Communications = 3,
|
||||
AudioCategory_Alerts = 4,
|
||||
AudioCategory_SoundEffects = 5,
|
||||
AudioCategory_GameEffects = 6,
|
||||
AudioCategory_GameMedia = 7,
|
||||
AudioCategory_GameChat = 8,
|
||||
AudioCategory_Speech = 9,
|
||||
AudioCategory_Movie = 10,
|
||||
AudioCategory_Media = 11,
|
||||
} AUDIO_STREAM_CATEGORY;
|
||||
#endif /* WAVE_FORMAT_WM9_SPECTRUM_ANALYZER */
|
||||
#endif /* NTDDI_VERSION < NTDDI_WIN8 */
|
||||
|
||||
// All structures defined in this file use tight field packing
|
||||
#pragma pack(push, 1)
|
||||
|
||||
@@ -83,7 +139,7 @@ interface __declspec(uuid("60d8dac8-5aa1-4e8e-b597-2f5e2883d484")) IXAudio2;
|
||||
#define XAUDIO2_VOICE_NOSAMPLESPLAYED 0x0100 // Used in IXAudio2SourceVoice::GetState
|
||||
#define XAUDIO2_STOP_ENGINE_WHEN_IDLE 0x2000 // Used in XAudio2Create to force the engine to Stop when no source voices are Started, and Start when a voice is Started
|
||||
#define XAUDIO2_1024_QUANTUM 0x8000 // Used in XAudio2Create to specify nondefault processing quantum of 21.33 ms (1024 samples at 48KHz)
|
||||
#define XAUDIO2_NO_VIRTUAL_AUDIO_CLIENT 0x10000 // Used in CreateMasteringVoice to create a virtual audio client
|
||||
#define XAUDIO2_NO_VIRTUAL_AUDIO_CLIENT 0x10000 // Used in CreateMasteringVoice to create a virtual audio client
|
||||
|
||||
// Default parameters for the built-in filter
|
||||
#define XAUDIO2_DEFAULT_FILTER_TYPE LowPassFilter
|
||||
@@ -99,10 +155,10 @@ interface __declspec(uuid("60d8dac8-5aa1-4e8e-b597-2f5e2883d484")) IXAudio2;
|
||||
|
||||
// XAudio2 error codes
|
||||
#define FACILITY_XAUDIO2 0x896
|
||||
#define XAUDIO2_E_INVALID_CALL 0x88960001 // An API call or one of its arguments was illegal
|
||||
#define XAUDIO2_E_XMA_DECODER_ERROR 0x88960002 // The XMA hardware suffered an unrecoverable error
|
||||
#define XAUDIO2_E_XAPO_CREATION_FAILED 0x88960003 // XAudio2 failed to initialize an XAPO effect
|
||||
#define XAUDIO2_E_DEVICE_INVALIDATED 0x88960004 // An audio device became unusable (unplugged, etc)
|
||||
#define XAUDIO2_E_INVALID_CALL ((HRESULT)0x88960001) // An API call or one of its arguments was illegal
|
||||
#define XAUDIO2_E_XMA_DECODER_ERROR ((HRESULT)0x88960002) // The XMA hardware suffered an unrecoverable error
|
||||
#define XAUDIO2_E_XAPO_CREATION_FAILED ((HRESULT)0x88960003) // XAudio2 failed to initialize an XAPO effect
|
||||
#define XAUDIO2_E_DEVICE_INVALIDATED ((HRESULT)0x88960004) // An audio device became unusable (unplugged, etc)
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
@@ -166,6 +222,13 @@ typedef UINT32 XAUDIO2_PROCESSOR;
|
||||
#define Processor31 0x40000000
|
||||
#define Processor32 0x80000000
|
||||
#define XAUDIO2_ANY_PROCESSOR 0xffffffff
|
||||
|
||||
// This value indicates that XAudio2 will choose the default processor by itself. The actual value chosen
|
||||
// may vary depending on the hardware platform.
|
||||
#define XAUDIO2_USE_DEFAULT_PROCESSOR 0x00000000
|
||||
|
||||
// This definition is included for backwards compatibilty. New implementations should use
|
||||
// XAUDIO2_USE_DEFAULT_PROCESSOR instead to let XAudio2 select the appropriate default processor for the hardware platform.
|
||||
#define XAUDIO2_DEFAULT_PROCESSOR Processor1
|
||||
|
||||
// Returned by IXAudio2Voice::GetVoiceDetails
|
||||
@@ -359,13 +422,13 @@ DECLARE_INTERFACE_(IXAudio2, IUnknown)
|
||||
{
|
||||
// NAME: IXAudio2::QueryInterface
|
||||
// DESCRIPTION: Queries for a given COM interface on the XAudio2 object.
|
||||
// Only IID_IUnknown and IID_IXAudio2 are supported.
|
||||
// Only IID_IUnknown, IID_IXAudio2 and IID_IXaudio2Extension are supported.
|
||||
//
|
||||
// ARGUMENTS:
|
||||
// riid - IID of the interface to be obtained.
|
||||
// ppvInterface - Returns a pointer to the requested interface.
|
||||
//
|
||||
STDMETHOD(QueryInterface) (THIS_ REFIID riid, _Outptr_ void** ppvInterface) PURE;
|
||||
STDMETHOD(QueryInterface) (THIS_ REFIID riid, _COM_Outptr_ void** ppvInterface) PURE;
|
||||
|
||||
// NAME: IXAudio2::AddRef
|
||||
// DESCRIPTION: Adds a reference to the XAudio2 object.
|
||||
@@ -489,6 +552,50 @@ DECLARE_INTERFACE_(IXAudio2, IUnknown)
|
||||
_Reserved_ void* pReserved X2DEFAULT(NULL)) PURE;
|
||||
};
|
||||
|
||||
// This interface extends IXAudio2 with additional functionality.
|
||||
// Use IXAudio2::QueryInterface to obtain a pointer to this interface.
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IXAudio2Extension
|
||||
DECLARE_INTERFACE_(IXAudio2Extension, IUnknown)
|
||||
{
|
||||
// NAME: IXAudio2Extension::QueryInterface
|
||||
// DESCRIPTION: Queries for a given COM interface on the XAudio2 object.
|
||||
// Only IID_IUnknown, IID_IXAudio2 and IID_IXaudio2Extension are supported.
|
||||
//
|
||||
// ARGUMENTS:
|
||||
// riid - IID of the interface to be obtained.
|
||||
// ppvInterface - Returns a pointer to the requested interface.
|
||||
//
|
||||
STDMETHOD(QueryInterface) (THIS_ REFIID riid, _COM_Outptr_ void** ppvInterface) PURE;
|
||||
|
||||
// NAME: IXAudio2Extension::AddRef
|
||||
// DESCRIPTION: Adds a reference to the XAudio2 object.
|
||||
//
|
||||
STDMETHOD_(ULONG, AddRef) (THIS) PURE;
|
||||
|
||||
// NAME: IXAudio2Extension::Release
|
||||
// DESCRIPTION: Releases a reference to the XAudio2 object.
|
||||
//
|
||||
STDMETHOD_(ULONG, Release) (THIS) PURE;
|
||||
|
||||
// NAME: IXAudio2Extension::GetProcessingQuantum
|
||||
// DESCRIPTION: Returns the processing quantum
|
||||
// quantumMilliseconds = (1000.0f * quantumNumerator / quantumDenominator)
|
||||
//
|
||||
// ARGUMENTS:
|
||||
// quantumNumerator - Quantum numerator
|
||||
// quantumDenominator - Quantum denominator
|
||||
//
|
||||
STDMETHOD_(void, GetProcessingQuantum)(THIS_ _Out_ UINT32* quantumNumerator, _Out_range_(!= , 0) UINT32* quantumDenominator);
|
||||
|
||||
// NAME: IXAudio2Extension::GetProcessor
|
||||
// DESCRIPTION: Returns the number of the processor used by XAudio2
|
||||
//
|
||||
// ARGUMENTS:
|
||||
// processor - Non-zero Processor number
|
||||
//
|
||||
STDMETHOD_(void, GetProcessor)(THIS_ _Out_range_(!= , 0) XAUDIO2_PROCESSOR* processor);
|
||||
};
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
@@ -949,6 +1056,10 @@ DECLARE_INTERFACE(IXAudio2VoiceCallback)
|
||||
#define IXAudio2_GetPerformanceData(This,pPerfData) ((This)->lpVtbl->GetPerformanceData(This,pPerfData))
|
||||
#define IXAudio2_SetDebugConfiguration(This,pDebugConfiguration,pReserved) ((This)->lpVtbl->SetDebugConfiguration(This,pDebugConfiguration,pReserved))
|
||||
|
||||
// IXAudio2Extension
|
||||
#define IXAudio2Extension_GetProcessingQuantum(This,quantumNumerator,quantumDenominator) ((This)->lpVtbl->GetProcessingQuantum(This,quantumNumerator,quantumDenominator))
|
||||
#define IXAudio2Extension_GetProcessor(This,processor) ((This)->lpVtbl->GetProcessor(This,processor))
|
||||
|
||||
// IXAudio2Voice
|
||||
#define IXAudio2Voice_GetVoiceDetails(This,pVoiceDetails) ((This)->lpVtbl->GetVoiceDetails(This,pVoiceDetails))
|
||||
#define IXAudio2Voice_SetOutputVoices(This,pSendList) ((This)->lpVtbl->SetOutputVoices(This,pSendList))
|
||||
@@ -1143,12 +1254,16 @@ __inline float XAudio2CutoffFrequencyToOnePoleCoefficient(float CutoffFrequency,
|
||||
* will use. Note that XAudio2 supports concurrent processing on
|
||||
* multiple threads, using any combination of XAUDIO2_PROCESSOR
|
||||
* flags. The values are platform-specific; platform-independent
|
||||
* code can use XAUDIO2_DEFAULT_PROCESSOR to use the default on
|
||||
* code can use XAUDIO2_USE_DEFAULT_PROCESSOR to use the default on
|
||||
* each platform.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
typedef HRESULT(*XAudio2Create)(_Outptr_ IXAudio2** ppXAudio2, UINT32 Flags, XAUDIO2_PROCESSOR XAudio2Processor);
|
||||
// We're an xaudio2 client
|
||||
#define XAUDIO2_STDAPI EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE
|
||||
|
||||
XAUDIO2_STDAPI XAudio2Create(_Outptr_ IXAudio2** ppXAudio2, UINT32 Flags X2DEFAULT(0),
|
||||
XAUDIO2_PROCESSOR XAudio2Processor X2DEFAULT(XAUDIO2_USE_DEFAULT_PROCESSOR));
|
||||
|
||||
// Undo the #pragma pack(push, 1) directive at the top of this file
|
||||
#pragma pack(pop)
|
||||
@@ -1156,3 +1271,4 @@ typedef HRESULT(*XAudio2Create)(_Outptr_ IXAudio2** ppXAudio2, UINT32 Flags, XAU
|
||||
#endif // #ifndef GUID_DEFS_ONLY
|
||||
|
||||
#endif // #ifndef __XAUDIO2_INCLUDED__
|
||||
|
||||
BIN
Binary file not shown.
Vendored
-1295
File diff suppressed because it is too large
Load Diff
Vendored
-263
@@ -1,263 +0,0 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
*
|
||||
* File: audiodefs.h
|
||||
* Content: Basic constants and data types for audio work.
|
||||
*
|
||||
* Remarks: This header file defines all of the audio format constants and
|
||||
* structures required for XAudio2 and XACT work. Providing these
|
||||
* in a single location avoids certain dependency problems in the
|
||||
* legacy audio headers (mmreg.h, mmsystem.h, ksmedia.h).
|
||||
*
|
||||
* NOTE: Including the legacy headers after this one may cause a
|
||||
* compilation error, because they define some of the same types
|
||||
* defined here without preprocessor guards to avoid multiple
|
||||
* definitions. If a source file needs one of the old headers,
|
||||
* it must include it before including audiodefs.h.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __AUDIODEFS_INCLUDED__
|
||||
#define __AUDIODEFS_INCLUDED__
|
||||
|
||||
#include <windef.h> // For WORD, DWORD, etc.
|
||||
|
||||
#pragma pack(push, 1) // Pack structures to 1-byte boundaries
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* WAVEFORMATEX: Base structure for many audio formats. Format-specific
|
||||
* extensions can be defined for particular formats by using a non-zero
|
||||
* cbSize value and adding extra fields to the end of this structure.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef _WAVEFORMATEX_
|
||||
|
||||
#define _WAVEFORMATEX_
|
||||
typedef struct tWAVEFORMATEX
|
||||
{
|
||||
WORD wFormatTag; // Integer identifier of the format
|
||||
WORD nChannels; // Number of audio channels
|
||||
DWORD nSamplesPerSec; // Audio sample rate
|
||||
DWORD nAvgBytesPerSec; // Bytes per second (possibly approximate)
|
||||
WORD nBlockAlign; // Size in bytes of a sample block (all channels)
|
||||
WORD wBitsPerSample; // Size in bits of a single per-channel sample
|
||||
WORD cbSize; // Bytes of extra data appended to this struct
|
||||
} WAVEFORMATEX;
|
||||
|
||||
#endif
|
||||
|
||||
// Defining pointer types outside of the #if block to make sure they are
|
||||
// defined even if mmreg.h or mmsystem.h is #included before this file
|
||||
|
||||
typedef WAVEFORMATEX *PWAVEFORMATEX, *NPWAVEFORMATEX, *LPWAVEFORMATEX;
|
||||
typedef const WAVEFORMATEX *PCWAVEFORMATEX, *LPCWAVEFORMATEX;
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* WAVEFORMATEXTENSIBLE: Extended version of WAVEFORMATEX that should be
|
||||
* used as a basis for all new audio formats. The format tag is replaced
|
||||
* with a GUID, allowing new formats to be defined without registering a
|
||||
* format tag with Microsoft. There are also new fields that can be used
|
||||
* to specify the spatial positions for each channel and the bit packing
|
||||
* used for wide samples (e.g. 24-bit PCM samples in 32-bit containers).
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef _WAVEFORMATEXTENSIBLE_
|
||||
|
||||
#define _WAVEFORMATEXTENSIBLE_
|
||||
typedef struct
|
||||
{
|
||||
WAVEFORMATEX Format; // Base WAVEFORMATEX data
|
||||
union
|
||||
{
|
||||
WORD wValidBitsPerSample; // Valid bits in each sample container
|
||||
WORD wSamplesPerBlock; // Samples per block of audio data; valid
|
||||
// if wBitsPerSample=0 (but rarely used).
|
||||
WORD wReserved; // Zero if neither case above applies.
|
||||
} Samples;
|
||||
DWORD dwChannelMask; // Positions of the audio channels
|
||||
GUID SubFormat; // Format identifier GUID
|
||||
} WAVEFORMATEXTENSIBLE;
|
||||
|
||||
#endif
|
||||
|
||||
typedef WAVEFORMATEXTENSIBLE *PWAVEFORMATEXTENSIBLE, *LPWAVEFORMATEXTENSIBLE;
|
||||
typedef const WAVEFORMATEXTENSIBLE *PCWAVEFORMATEXTENSIBLE, *LPCWAVEFORMATEXTENSIBLE;
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* Define the most common wave format tags used in WAVEFORMATEX formats.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef WAVE_FORMAT_PCM // Pulse Code Modulation
|
||||
|
||||
// If WAVE_FORMAT_PCM is not defined, we need to define some legacy types
|
||||
// for compatibility with the Windows mmreg.h / mmsystem.h header files.
|
||||
|
||||
// Old general format structure (information common to all formats)
|
||||
typedef struct waveformat_tag
|
||||
{
|
||||
WORD wFormatTag;
|
||||
WORD nChannels;
|
||||
DWORD nSamplesPerSec;
|
||||
DWORD nAvgBytesPerSec;
|
||||
WORD nBlockAlign;
|
||||
} WAVEFORMAT, *PWAVEFORMAT, NEAR *NPWAVEFORMAT, FAR *LPWAVEFORMAT;
|
||||
|
||||
// Specific format structure for PCM data
|
||||
typedef struct pcmwaveformat_tag
|
||||
{
|
||||
WAVEFORMAT wf;
|
||||
WORD wBitsPerSample;
|
||||
} PCMWAVEFORMAT, *PPCMWAVEFORMAT, NEAR *NPPCMWAVEFORMAT, FAR *LPPCMWAVEFORMAT;
|
||||
|
||||
#define WAVE_FORMAT_PCM 0x0001
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_ADPCM // Microsoft Adaptive Differental PCM
|
||||
|
||||
// Replicate the Microsoft ADPCM type definitions from mmreg.h.
|
||||
|
||||
typedef struct adpcmcoef_tag
|
||||
{
|
||||
short iCoef1;
|
||||
short iCoef2;
|
||||
} ADPCMCOEFSET;
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4200) // Disable zero-sized array warnings
|
||||
|
||||
typedef struct adpcmwaveformat_tag {
|
||||
WAVEFORMATEX wfx;
|
||||
WORD wSamplesPerBlock;
|
||||
WORD wNumCoef;
|
||||
ADPCMCOEFSET aCoef[]; // Always 7 coefficient pairs for MS ADPCM
|
||||
} ADPCMWAVEFORMAT;
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
#define WAVE_FORMAT_ADPCM 0x0002
|
||||
|
||||
#endif
|
||||
|
||||
// Other frequently used format tags
|
||||
|
||||
#ifndef WAVE_FORMAT_UNKNOWN
|
||||
#define WAVE_FORMAT_UNKNOWN 0x0000 // Unknown or invalid format tag
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_IEEE_FLOAT
|
||||
#define WAVE_FORMAT_IEEE_FLOAT 0x0003 // 32-bit floating-point
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_MPEGLAYER3
|
||||
#define WAVE_FORMAT_MPEGLAYER3 0x0055 // ISO/MPEG Layer3
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
|
||||
#define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092 // Dolby Audio Codec 3 over S/PDIF
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_WMAUDIO2
|
||||
#define WAVE_FORMAT_WMAUDIO2 0x0161 // Windows Media Audio
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_WMAUDIO3
|
||||
#define WAVE_FORMAT_WMAUDIO3 0x0162 // Windows Media Audio Pro
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_WMASPDIF
|
||||
#define WAVE_FORMAT_WMASPDIF 0x0164 // Windows Media Audio over S/PDIF
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_EXTENSIBLE
|
||||
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE // All WAVEFORMATEXTENSIBLE formats
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* Define the most common wave format GUIDs used in WAVEFORMATEXTENSIBLE
|
||||
* formats. Note that including the Windows ksmedia.h header after this
|
||||
* one will cause build problems; this cannot be avoided, since ksmedia.h
|
||||
* defines these macros without preprocessor guards.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef __cplusplus // uuid() and __uuidof() are only available in C++
|
||||
|
||||
#ifndef KSDATAFORMAT_SUBTYPE_PCM
|
||||
struct __declspec(uuid("00000001-0000-0010-8000-00aa00389b71")) KSDATAFORMAT_SUBTYPE_PCM_STRUCT;
|
||||
#define KSDATAFORMAT_SUBTYPE_PCM __uuidof(KSDATAFORMAT_SUBTYPE_PCM_STRUCT)
|
||||
#endif
|
||||
|
||||
#ifndef KSDATAFORMAT_SUBTYPE_ADPCM
|
||||
struct __declspec(uuid("00000002-0000-0010-8000-00aa00389b71")) KSDATAFORMAT_SUBTYPE_ADPCM_STRUCT;
|
||||
#define KSDATAFORMAT_SUBTYPE_ADPCM __uuidof(KSDATAFORMAT_SUBTYPE_ADPCM_STRUCT)
|
||||
#endif
|
||||
|
||||
#ifndef KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
|
||||
struct __declspec(uuid("00000003-0000-0010-8000-00aa00389b71")) KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_STRUCT;
|
||||
#define KSDATAFORMAT_SUBTYPE_IEEE_FLOAT __uuidof(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_STRUCT)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* Speaker positions used in the WAVEFORMATEXTENSIBLE dwChannelMask field.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef SPEAKER_FRONT_LEFT
|
||||
#define SPEAKER_FRONT_LEFT 0x00000001
|
||||
#define SPEAKER_FRONT_RIGHT 0x00000002
|
||||
#define SPEAKER_FRONT_CENTER 0x00000004
|
||||
#define SPEAKER_LOW_FREQUENCY 0x00000008
|
||||
#define SPEAKER_BACK_LEFT 0x00000010
|
||||
#define SPEAKER_BACK_RIGHT 0x00000020
|
||||
#define SPEAKER_FRONT_LEFT_OF_CENTER 0x00000040
|
||||
#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x00000080
|
||||
#define SPEAKER_BACK_CENTER 0x00000100
|
||||
#define SPEAKER_SIDE_LEFT 0x00000200
|
||||
#define SPEAKER_SIDE_RIGHT 0x00000400
|
||||
#define SPEAKER_TOP_CENTER 0x00000800
|
||||
#define SPEAKER_TOP_FRONT_LEFT 0x00001000
|
||||
#define SPEAKER_TOP_FRONT_CENTER 0x00002000
|
||||
#define SPEAKER_TOP_FRONT_RIGHT 0x00004000
|
||||
#define SPEAKER_TOP_BACK_LEFT 0x00008000
|
||||
#define SPEAKER_TOP_BACK_CENTER 0x00010000
|
||||
#define SPEAKER_TOP_BACK_RIGHT 0x00020000
|
||||
#define SPEAKER_RESERVED 0x7FFC0000
|
||||
#define SPEAKER_ALL 0x80000000
|
||||
#define _SPEAKER_POSITIONS_
|
||||
#endif
|
||||
|
||||
#ifndef SPEAKER_STEREO
|
||||
#define SPEAKER_MONO (SPEAKER_FRONT_CENTER)
|
||||
#define SPEAKER_STEREO (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT)
|
||||
#define SPEAKER_2POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY)
|
||||
#define SPEAKER_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER)
|
||||
#define SPEAKER_QUAD (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)
|
||||
#define SPEAKER_4POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)
|
||||
#define SPEAKER_5POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)
|
||||
#define SPEAKER_7POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER)
|
||||
#define SPEAKER_5POINT1_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT)
|
||||
#define SPEAKER_7POINT1_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT)
|
||||
#endif
|
||||
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // #ifndef __AUDIODEFS_INCLUDED__
|
||||
Vendored
-65
@@ -1,65 +0,0 @@
|
||||
// comdecl.h: Macros to facilitate COM interface and GUID declarations.
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
#ifndef _COMDECL_H_
|
||||
#define _COMDECL_H_
|
||||
|
||||
#ifndef _XBOX
|
||||
#include <basetyps.h> // For standard COM interface macros
|
||||
#else
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4061)
|
||||
#include <xtl.h> // Required by xobjbase.h
|
||||
#include <xobjbase.h> // Special definitions for Xbox build
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
// The DEFINE_CLSID() and DEFINE_IID() macros defined below allow COM GUIDs to
|
||||
// be declared and defined in such a way that clients can obtain the GUIDs using
|
||||
// either the __uuidof() extension or the old-style CLSID_Foo / IID_IFoo names.
|
||||
// If using the latter approach, the client can also choose whether to get the
|
||||
// GUID definitions by defining the INITGUID preprocessor constant or by linking
|
||||
// to a GUID library. This works in either C or C++.
|
||||
|
||||
#ifndef _MSC_VER
|
||||
|
||||
#define DEFINE_UUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) __CRT_UUID_DECL(name, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
|
||||
#define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) class className; DEFINE_UUID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8)
|
||||
#define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) struct interfaceName; DEFINE_UUID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8)
|
||||
|
||||
#elif __cplusplus
|
||||
|
||||
#define DECLSPEC_UUID_WRAPPER(x) __declspec(uuid(#x))
|
||||
#ifdef INITGUID
|
||||
|
||||
#define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
class DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) className; \
|
||||
EXTERN_C const GUID DECLSPEC_SELECTANY CLSID_##className = __uuidof(className)
|
||||
|
||||
#define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
interface DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) interfaceName; \
|
||||
EXTERN_C const GUID DECLSPEC_SELECTANY IID_##interfaceName = __uuidof(interfaceName)
|
||||
|
||||
#else // INITGUID
|
||||
|
||||
#define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
class DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) className; \
|
||||
EXTERN_C const GUID CLSID_##className
|
||||
|
||||
#define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
interface DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) interfaceName; \
|
||||
EXTERN_C const GUID IID_##interfaceName
|
||||
|
||||
#endif // INITGUID
|
||||
|
||||
#else // __cplusplus
|
||||
|
||||
#define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
DEFINE_GUID(CLSID_##className, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
|
||||
|
||||
#define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
DEFINE_GUID(IID_##interfaceName, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // #ifndef _COMDECL_H_
|
||||
Vendored
-18
@@ -1,18 +0,0 @@
|
||||
/*==========================================================================;
|
||||
*
|
||||
*
|
||||
* File: dxsdkver.h
|
||||
* Content: DirectX SDK Version Include File
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _DXSDKVER_H_
|
||||
#define _DXSDKVER_H_
|
||||
|
||||
#define _DXSDK_PRODUCT_MAJOR 9
|
||||
#define _DXSDK_PRODUCT_MINOR 29
|
||||
#define _DXSDK_BUILD_MAJOR 1962
|
||||
#define _DXSDK_BUILD_MINOR 0
|
||||
|
||||
#endif // _DXSDKVER_H_
|
||||
|
||||
Vendored
-718
@@ -1,718 +0,0 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
*
|
||||
* File: xma2defs.h
|
||||
* Content: Constants, data types and functions for XMA2 compressed audio.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __XMA2DEFS_INCLUDED__
|
||||
#define __XMA2DEFS_INCLUDED__
|
||||
|
||||
#include <sal.h> // Markers for documenting API semantics
|
||||
#include <winerror.h> // For S_OK, E_FAIL
|
||||
#include <audiodefs.h> // Basic data types and constants for audio work
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* Overview
|
||||
***************************************************************************/
|
||||
|
||||
// A typical XMA2 file contains these RIFF chunks:
|
||||
//
|
||||
// 'fmt' or 'XMA2' chunk (or both): A description of the XMA data's structure
|
||||
// and characteristics (length, channels, sample rate, loops, block size, etc).
|
||||
//
|
||||
// 'seek' chunk: A seek table to help navigate the XMA data.
|
||||
//
|
||||
// 'data' chunk: The encoded XMA2 data.
|
||||
//
|
||||
// The encoded XMA2 data is structured as a set of BLOCKS, which contain PACKETS,
|
||||
// which contain FRAMES, which contain SUBFRAMES (roughly speaking). The frames
|
||||
// in a file may also be divided into several subsets, called STREAMS.
|
||||
//
|
||||
// FRAME: A variable-sized segment of XMA data that decodes to exactly 512 mono
|
||||
// or stereo PCM samples. This is the smallest unit of XMA data that can
|
||||
// be decoded in isolation. Frames are an arbitrary number of bits in
|
||||
// length, and need not be byte-aligned. See "XMA frame structure" below.
|
||||
//
|
||||
// SUBFRAME: A region of bits in an XMA frame that decodes to 128 mono or stereo
|
||||
// samples. The XMA decoder cannot decode a subframe in isolation; it needs
|
||||
// a whole frame to work with. However, it can begin emitting the frame's
|
||||
// decoded samples at any one of the four subframe boundaries. Subframes
|
||||
// can be addressed for seeking and looping purposes.
|
||||
//
|
||||
// PACKET: A 2Kb region containing a 32-bit header and some XMA frames. Frames
|
||||
// can (and usually do) span packets. A packet's header includes the offset
|
||||
// in bits of the first frame that begins within that packet. All of the
|
||||
// frames that begin in a given packet belong to the same "stream" (see the
|
||||
// Multichannel Audio section below).
|
||||
//
|
||||
// STREAM: A set of packets within an XMA file that all contain data for the
|
||||
// same mono or stereo component of a PCM file with more than two channels.
|
||||
// The packets comprising a given stream may be interleaved with each other
|
||||
// more or less arbitrarily; see Multichannel Audio.
|
||||
//
|
||||
// BLOCK: An array of XMA packets; or, to break it down differently, a series of
|
||||
// consecutive XMA frames, padded at the end with reserved data. A block
|
||||
// must contain at least one 2Kb packet per stream, and it can hold up to
|
||||
// 4095 packets (8190Kb), but its size is typically in the 32Kb-128Kb range.
|
||||
// (The size chosen involves a trade-off between memory use and efficiency
|
||||
// of reading from permanent storage.)
|
||||
//
|
||||
// XMA frames do not span blocks, so a block is guaranteed to begin with a
|
||||
// set of complete frames, one per stream. Also, a block in a multi-stream
|
||||
// XMA2 file always contains the same number of samples for each stream;
|
||||
// see Multichannel Audio.
|
||||
//
|
||||
// The 'data' chunk in an XMA2 file is an array of XMA2WAVEFORMAT.BlockCount XMA
|
||||
// blocks, all the same size (as specified in XMA2WAVEFORMAT.BlockSizeInBytes)
|
||||
// except for the last one, which may be shorter.
|
||||
|
||||
|
||||
// MULTICHANNEL AUDIO: the XMA decoder can only decode raw XMA data into either
|
||||
// mono or stereo PCM data. In order to encode a 6-channel file (say), the file
|
||||
// must be deinterleaved into 3 stereo streams that are encoded independently,
|
||||
// producing 3 encoded XMA data streams. Then the packets in these 3 streams
|
||||
// are interleaved to produce a single XMA2 file, and some information is added
|
||||
// to the file so that the original 6-channel audio can be reconstructed at
|
||||
// decode time. This works using the concept of an XMA stream (see above).
|
||||
//
|
||||
// The frames for all the streams in an XMA file are interleaved in an arbitrary
|
||||
// order. To locate a frame that belongs to a given stream in a given XMA block,
|
||||
// you must examine the first few packets in the block. Here (and only here) the
|
||||
// packets are guaranteed to be presented in stream order, so that all frames
|
||||
// beginning in packet 0 belong to stream 0 (the first stereo pair), etc.
|
||||
//
|
||||
// (This means that when decoding multi-stream XMA files, only entire XMA blocks
|
||||
// should be submitted to the decoder; otherwise it cannot know which frames
|
||||
// belong to which stream.)
|
||||
//
|
||||
// Once you have one frame that belongs to a given stream, you can find the next
|
||||
// one by looking at the frame's 'NextFrameOffsetBits' value (which is stored in
|
||||
// its first 15 bits; see XMAFRAME below). The GetXmaFrameBitPosition function
|
||||
// uses this technique.
|
||||
|
||||
|
||||
// SEEKING IN XMA2 FILES: Here is some pseudocode to find the byte position and
|
||||
// subframe in an XMA2 file which will contain sample S when decoded.
|
||||
//
|
||||
// 1. Traverse the seek table to find the XMA2 block containing sample S. The
|
||||
// seek table is an array of big-endian DWORDs, one per block in the file.
|
||||
// The Nth DWORD is the total number of PCM samples that would be obtained
|
||||
// by decoding the entire XMA file up to the end of block N. Hence, the
|
||||
// block we want is the first one whose seek table entry is greater than S.
|
||||
// (See the GetXmaBlockContainingSample helper function.)
|
||||
//
|
||||
// 2. Calculate which frame F within the block found above contains sample S.
|
||||
// Since each frame decodes to 512 samples, this is straightforward. The
|
||||
// first frame in the block produces samples X to X + 512, where X is the
|
||||
// seek table entry for the prior block. So F is (S - X) / 512.
|
||||
//
|
||||
// 3. Find the bit offset within the block where frame F starts. Since frames
|
||||
// are variable-sized, this can only be done by traversing all the frames in
|
||||
// the block until we reach frame F. (See GetXmaFrameBitPosition.)
|
||||
//
|
||||
// 4. Frame F has four 128-sample subframes. To find the subframe containing S,
|
||||
// we can use the formula (S % 512) / 128.
|
||||
//
|
||||
// In the case of multi-stream XMA files, sample S is a multichannel sample with
|
||||
// parts coming from several frames, one per stream. To find all these frames,
|
||||
// steps 2-4 need to be repeated for each stream N, using the knowledge that the
|
||||
// first packets in a block are presented in stream order. The frame traversal
|
||||
// in step 3 must be started at the first frame in the Nth packet of the block,
|
||||
// which will be the first frame for stream N. (And the packet header will tell
|
||||
// you the first frame's start position within the packet.)
|
||||
//
|
||||
// Step 1 can be performed using the GetXmaBlockContainingSample function below,
|
||||
// and steps 2-4 by calling GetXmaDecodePositionForSample once for each stream.
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* XMA constants
|
||||
***************************************************************************/
|
||||
|
||||
// Size of the PCM samples produced by the XMA decoder
|
||||
#define XMA_OUTPUT_SAMPLE_BYTES 2u
|
||||
#define XMA_OUTPUT_SAMPLE_BITS (XMA_OUTPUT_SAMPLE_BYTES * 8u)
|
||||
|
||||
// Size of an XMA packet
|
||||
#define XMA_BYTES_PER_PACKET 2048u
|
||||
#define XMA_BITS_PER_PACKET (XMA_BYTES_PER_PACKET * 8u)
|
||||
|
||||
// Size of an XMA packet header
|
||||
#define XMA_PACKET_HEADER_BYTES 4u
|
||||
#define XMA_PACKET_HEADER_BITS (XMA_PACKET_HEADER_BYTES * 8u)
|
||||
|
||||
// Sample blocks in a decoded XMA frame
|
||||
#define XMA_SAMPLES_PER_FRAME 512u
|
||||
|
||||
// Sample blocks in a decoded XMA subframe
|
||||
#define XMA_SAMPLES_PER_SUBFRAME 128u
|
||||
|
||||
// Maximum encoded data that can be submitted to the XMA decoder at a time
|
||||
#define XMA_READBUFFER_MAX_PACKETS 4095u
|
||||
#define XMA_READBUFFER_MAX_BYTES (XMA_READBUFFER_MAX_PACKETS * XMA_BYTES_PER_PACKET)
|
||||
|
||||
// Maximum size allowed for the XMA decoder's output buffers
|
||||
#define XMA_WRITEBUFFER_MAX_BYTES (31u * 256u)
|
||||
|
||||
// Required byte alignment of the XMA decoder's output buffers
|
||||
#define XMA_WRITEBUFFER_BYTE_ALIGNMENT 256u
|
||||
|
||||
// Decode chunk sizes for the XMA_PLAYBACK_INIT.subframesToDecode field
|
||||
#define XMA_MIN_SUBFRAMES_TO_DECODE 1u
|
||||
#define XMA_MAX_SUBFRAMES_TO_DECODE 8u
|
||||
#define XMA_OPTIMAL_SUBFRAMES_TO_DECODE 4u
|
||||
|
||||
// LoopCount<255 means finite repetitions; LoopCount=255 means infinite looping
|
||||
#define XMA_MAX_LOOPCOUNT 254u
|
||||
#define XMA_INFINITE_LOOP 255u
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* XMA format structures
|
||||
***************************************************************************/
|
||||
|
||||
// The currently recommended way to express format information for XMA2 files
|
||||
// is the XMA2WAVEFORMATEX structure. This structure is fully compliant with
|
||||
// the WAVEFORMATEX standard and contains all the information needed to parse
|
||||
// and manage XMA2 files in a compact way.
|
||||
|
||||
#define WAVE_FORMAT_XMA2 0x166
|
||||
|
||||
typedef struct XMA2WAVEFORMATEX
|
||||
{
|
||||
WAVEFORMATEX wfx;
|
||||
// Meaning of the WAVEFORMATEX fields here:
|
||||
// wFormatTag; // Audio format type; always WAVE_FORMAT_XMA2
|
||||
// nChannels; // Channel count of the decoded audio
|
||||
// nSamplesPerSec; // Sample rate of the decoded audio
|
||||
// nAvgBytesPerSec; // Used internally by the XMA encoder
|
||||
// nBlockAlign; // Decoded sample size; channels * wBitsPerSample / 8
|
||||
// wBitsPerSample; // Bits per decoded mono sample; always 16 for XMA
|
||||
// cbSize; // Size in bytes of the rest of this structure (34)
|
||||
|
||||
WORD NumStreams; // Number of audio streams (1 or 2 channels each)
|
||||
DWORD ChannelMask; // Spatial positions of the channels in this file,
|
||||
// stored as SPEAKER_xxx values (see audiodefs.h)
|
||||
DWORD SamplesEncoded; // Total number of PCM samples the file decodes to
|
||||
DWORD BytesPerBlock; // XMA block size (but the last one may be shorter)
|
||||
DWORD PlayBegin; // First valid sample in the decoded audio
|
||||
DWORD PlayLength; // Length of the valid part of the decoded audio
|
||||
DWORD LoopBegin; // Beginning of the loop region in decoded sample terms
|
||||
DWORD LoopLength; // Length of the loop region in decoded sample terms
|
||||
BYTE LoopCount; // Number of loop repetitions; 255 = infinite
|
||||
BYTE EncoderVersion; // Version of XMA encoder that generated the file
|
||||
WORD BlockCount; // XMA blocks in file (and entries in its seek table)
|
||||
} XMA2WAVEFORMATEX, *PXMA2WAVEFORMATEX;
|
||||
|
||||
|
||||
// The legacy XMA format structures are described here for reference, but they
|
||||
// should not be used in new content. XMAWAVEFORMAT was the structure used in
|
||||
// XMA version 1 files. XMA2WAVEFORMAT was used in early XMA2 files; it is not
|
||||
// placed in the usual 'fmt' RIFF chunk but in its own 'XMA2' chunk.
|
||||
|
||||
#ifndef WAVE_FORMAT_XMA
|
||||
#define WAVE_FORMAT_XMA 0x0165
|
||||
|
||||
// Values used in the ChannelMask fields below. Similar to the SPEAKER_xxx
|
||||
// values defined in audiodefs.h, but modified to fit in a single byte.
|
||||
#ifndef XMA_SPEAKER_LEFT
|
||||
#define XMA_SPEAKER_LEFT 0x01
|
||||
#define XMA_SPEAKER_RIGHT 0x02
|
||||
#define XMA_SPEAKER_CENTER 0x04
|
||||
#define XMA_SPEAKER_LFE 0x08
|
||||
#define XMA_SPEAKER_LEFT_SURROUND 0x10
|
||||
#define XMA_SPEAKER_RIGHT_SURROUND 0x20
|
||||
#define XMA_SPEAKER_LEFT_BACK 0x40
|
||||
#define XMA_SPEAKER_RIGHT_BACK 0x80
|
||||
#endif
|
||||
|
||||
|
||||
// Used in XMAWAVEFORMAT for per-stream data
|
||||
typedef struct XMASTREAMFORMAT
|
||||
{
|
||||
DWORD PsuedoBytesPerSec; // Used by the XMA encoder (typo preserved for legacy reasons)
|
||||
DWORD SampleRate; // The stream's decoded sample rate (in XMA2 files,
|
||||
// this is the same for all streams in the file).
|
||||
DWORD LoopStart; // Bit offset of the frame containing the loop start
|
||||
// point, relative to the beginning of the stream.
|
||||
DWORD LoopEnd; // Bit offset of the frame containing the loop end.
|
||||
BYTE SubframeData; // Two 4-bit numbers specifying the exact location of
|
||||
// the loop points within the frames that contain them.
|
||||
// SubframeEnd: Subframe of the loop end frame where
|
||||
// the loop ends. Ranges from 0 to 3.
|
||||
// SubframeSkip: Subframes to skip in the start frame to
|
||||
// reach the loop. Ranges from 0 to 4.
|
||||
BYTE Channels; // Number of channels in the stream (1 or 2)
|
||||
WORD ChannelMask; // Spatial positions of the channels in the stream
|
||||
} XMASTREAMFORMAT;
|
||||
|
||||
// Legacy XMA1 format structure
|
||||
typedef struct XMAWAVEFORMAT
|
||||
{
|
||||
WORD FormatTag; // Audio format type (always WAVE_FORMAT_XMA)
|
||||
WORD BitsPerSample; // Bit depth (currently required to be 16)
|
||||
WORD EncodeOptions; // Options for XMA encoder/decoder
|
||||
WORD LargestSkip; // Largest skip used in interleaving streams
|
||||
WORD NumStreams; // Number of interleaved audio streams
|
||||
BYTE LoopCount; // Number of loop repetitions; 255 = infinite
|
||||
BYTE Version; // XMA encoder version that generated the file.
|
||||
// Always 3 or higher for XMA2 files.
|
||||
XMASTREAMFORMAT XmaStreams[1]; // Per-stream format information; the actual
|
||||
// array length is in the NumStreams field.
|
||||
} XMAWAVEFORMAT;
|
||||
|
||||
|
||||
// Used in XMA2WAVEFORMAT for per-stream data
|
||||
typedef struct XMA2STREAMFORMAT
|
||||
{
|
||||
BYTE Channels; // Number of channels in the stream (1 or 2)
|
||||
BYTE RESERVED; // Reserved for future use
|
||||
WORD ChannelMask; // Spatial positions of the channels in the stream
|
||||
} XMA2STREAMFORMAT;
|
||||
|
||||
// Legacy XMA2 format structure (big-endian byte ordering)
|
||||
typedef struct XMA2WAVEFORMAT
|
||||
{
|
||||
BYTE Version; // XMA encoder version that generated the file.
|
||||
// Always 3 or higher for XMA2 files.
|
||||
BYTE NumStreams; // Number of interleaved audio streams
|
||||
BYTE RESERVED; // Reserved for future use
|
||||
BYTE LoopCount; // Number of loop repetitions; 255 = infinite
|
||||
DWORD LoopBegin; // Loop begin point, in samples
|
||||
DWORD LoopEnd; // Loop end point, in samples
|
||||
DWORD SampleRate; // The file's decoded sample rate
|
||||
DWORD EncodeOptions; // Options for the XMA encoder/decoder
|
||||
DWORD PsuedoBytesPerSec; // Used internally by the XMA encoder
|
||||
DWORD BlockSizeInBytes; // Size in bytes of this file's XMA blocks (except
|
||||
// possibly the last one). Always a multiple of
|
||||
// 2Kb, since XMA blocks are arrays of 2Kb packets.
|
||||
DWORD SamplesEncoded; // Total number of PCM samples encoded in this file
|
||||
DWORD SamplesInSource; // Actual number of PCM samples in the source
|
||||
// material used to generate this file
|
||||
DWORD BlockCount; // Number of XMA blocks in this file (and hence
|
||||
// also the number of entries in its seek table)
|
||||
XMA2STREAMFORMAT Streams[1]; // Per-stream format information; the actual
|
||||
// array length is in the NumStreams field.
|
||||
} XMA2WAVEFORMAT;
|
||||
|
||||
#endif // #ifndef WAVE_FORMAT_XMA
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* XMA packet structure (in big-endian form)
|
||||
***************************************************************************/
|
||||
|
||||
typedef struct XMA2PACKET
|
||||
{
|
||||
int FrameCount : 6; // Number of XMA frames that begin in this packet
|
||||
int FrameOffsetInBits : 15; // Bit of XmaData where the first complete frame begins
|
||||
int PacketMetaData : 3; // Metadata stored in the packet (always 1 for XMA2)
|
||||
int PacketSkipCount : 8; // How many packets belonging to other streams must be
|
||||
// skipped to find the next packet belonging to this one
|
||||
BYTE XmaData[XMA_BYTES_PER_PACKET - sizeof(DWORD)]; // XMA encoded data
|
||||
} XMA2PACKET;
|
||||
|
||||
// E.g. if the first DWORD of a packet is 0x30107902:
|
||||
//
|
||||
// 001100 000001000001111 001 00000010
|
||||
// | | | |____ Skip 2 packets to find the next one for this stream
|
||||
// | | |___________ XMA2 signature (always 001)
|
||||
// | |_____________________ First frame starts 527 bits into packet
|
||||
// |________________________________ Packet contains 12 frames
|
||||
|
||||
|
||||
// Helper functions to extract the fields above from an XMA packet. (Note that
|
||||
// the bitfields cannot be read directly on little-endian architectures such as
|
||||
// the Intel x86, as they are laid out in big-endian form.)
|
||||
|
||||
__inline DWORD GetXmaPacketFrameCount(__in_bcount(1) const BYTE* pPacket)
|
||||
{
|
||||
return (DWORD)(pPacket[0] >> 2);
|
||||
}
|
||||
|
||||
__inline DWORD GetXmaPacketFirstFrameOffsetInBits(__in_bcount(3) const BYTE* pPacket)
|
||||
{
|
||||
return ((DWORD)(pPacket[0] & 0x3) << 13) |
|
||||
((DWORD)(pPacket[1]) << 5) |
|
||||
((DWORD)(pPacket[2]) >> 3);
|
||||
}
|
||||
|
||||
__inline DWORD GetXmaPacketMetadata(__in_bcount(3) const BYTE* pPacket)
|
||||
{
|
||||
return (DWORD)(pPacket[2] & 0x7);
|
||||
}
|
||||
|
||||
__inline DWORD GetXmaPacketSkipCount(__in_bcount(4) const BYTE* pPacket)
|
||||
{
|
||||
return (DWORD)(pPacket[3]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* XMA frame structure
|
||||
***************************************************************************/
|
||||
|
||||
// There is no way to represent the XMA frame as a C struct, since it is a
|
||||
// variable-sized string of bits that need not be stored at a byte-aligned
|
||||
// position in memory. This is the layout:
|
||||
//
|
||||
// XMAFRAME
|
||||
// {
|
||||
// LengthInBits: A 15-bit number representing the length of this frame.
|
||||
// XmaData: Encoded XMA data; its size in bits is (LengthInBits - 15).
|
||||
// }
|
||||
|
||||
// Size in bits of the frame's initial LengthInBits field
|
||||
#define XMA_BITS_IN_FRAME_LENGTH_FIELD 15
|
||||
|
||||
// Special LengthInBits value that marks an invalid final frame
|
||||
#define XMA_FINAL_FRAME_MARKER 0x7FFF
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* XMA helper functions
|
||||
***************************************************************************/
|
||||
|
||||
// We define a local ASSERT macro to equal the global one if it exists.
|
||||
// You can define XMA2DEFS_ASSERT in advance to override this default.
|
||||
#ifndef XMA2DEFS_ASSERT
|
||||
#ifdef ASSERT
|
||||
#define XMA2DEFS_ASSERT ASSERT
|
||||
#else
|
||||
#define XMA2DEFS_ASSERT(a) /* No-op by default */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// GetXmaBlockContainingSample: Use a given seek table to find the XMA block
|
||||
// containing a given decoded sample. Note that the seek table entries in an
|
||||
// XMA file are stored in big-endian form and may need to be converted prior
|
||||
// to calling this function.
|
||||
|
||||
__inline HRESULT GetXmaBlockContainingSample
|
||||
(
|
||||
DWORD nBlockCount, // Blocks in the file (= seek table entries)
|
||||
__in_ecount(nBlockCount) const DWORD* pSeekTable, // Pointer to the seek table data
|
||||
DWORD nDesiredSample, // Decoded sample to locate
|
||||
__out DWORD* pnBlockContainingSample, // Index of the block containing the sample
|
||||
__out DWORD* pnSampleOffsetWithinBlock // Position of the sample in this block
|
||||
)
|
||||
{
|
||||
DWORD nPreviousTotalSamples = 0;
|
||||
DWORD nBlock;
|
||||
DWORD nTotalSamplesSoFar;
|
||||
|
||||
XMA2DEFS_ASSERT(pSeekTable);
|
||||
XMA2DEFS_ASSERT(pnBlockContainingSample);
|
||||
XMA2DEFS_ASSERT(pnSampleOffsetWithinBlock);
|
||||
|
||||
for (nBlock = 0; nBlock < nBlockCount; ++nBlock)
|
||||
{
|
||||
nTotalSamplesSoFar = pSeekTable[nBlock];
|
||||
if (nTotalSamplesSoFar > nDesiredSample)
|
||||
{
|
||||
*pnBlockContainingSample = nBlock;
|
||||
*pnSampleOffsetWithinBlock = nDesiredSample - nPreviousTotalSamples;
|
||||
return S_OK;
|
||||
}
|
||||
nPreviousTotalSamples = nTotalSamplesSoFar;
|
||||
}
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
|
||||
// GetXmaFrameLengthInBits: Reads a given frame's LengthInBits field.
|
||||
|
||||
__inline DWORD GetXmaFrameLengthInBits
|
||||
(
|
||||
__in_bcount(nBitPosition / 8 + 3)
|
||||
__in const BYTE* pPacket, // Pointer to XMA packet[s] containing the frame
|
||||
DWORD nBitPosition // Bit offset of the frame within this packet
|
||||
)
|
||||
{
|
||||
DWORD nRegion;
|
||||
DWORD nBytePosition = nBitPosition / 8;
|
||||
DWORD nBitOffset = nBitPosition % 8;
|
||||
|
||||
if (nBitOffset < 2) // Only need to read 2 bytes (and might not be safe to read more)
|
||||
{
|
||||
nRegion = (DWORD)(pPacket[nBytePosition+0]) << 8 |
|
||||
(DWORD)(pPacket[nBytePosition+1]);
|
||||
return (nRegion >> (1 - nBitOffset)) & 0x7FFF; // Last 15 bits
|
||||
}
|
||||
else // Need to read 3 bytes
|
||||
{
|
||||
nRegion = (DWORD)(pPacket[nBytePosition+0]) << 16 |
|
||||
(DWORD)(pPacket[nBytePosition+1]) << 8 |
|
||||
(DWORD)(pPacket[nBytePosition+2]);
|
||||
return (nRegion >> (9 - nBitOffset)) & 0x7FFF; // Last 15 bits
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// GetXmaFrameBitPosition: Calculates the bit offset of a given frame within
|
||||
// an XMA block or set of blocks. Returns 0 on failure.
|
||||
|
||||
__inline DWORD GetXmaFrameBitPosition
|
||||
(
|
||||
__in_bcount(nXmaDataBytes) const BYTE* pXmaData, // Pointer to XMA block[s]
|
||||
DWORD nXmaDataBytes, // Size of pXmaData in bytes
|
||||
DWORD nStreamIndex, // Stream within which to seek
|
||||
DWORD nDesiredFrame // Frame sought
|
||||
)
|
||||
{
|
||||
const BYTE* pCurrentPacket;
|
||||
DWORD nPacketsExamined = 0;
|
||||
DWORD nFrameCountSoFar = 0;
|
||||
DWORD nFramesToSkip;
|
||||
DWORD nFrameBitOffset;
|
||||
|
||||
XMA2DEFS_ASSERT(pXmaData);
|
||||
XMA2DEFS_ASSERT(nXmaDataBytes % XMA_BYTES_PER_PACKET == 0);
|
||||
|
||||
// Get the first XMA packet belonging to the desired stream, relying on the
|
||||
// fact that the first packets for each stream are in consecutive order at
|
||||
// the beginning of an XMA block.
|
||||
|
||||
pCurrentPacket = pXmaData + nStreamIndex * XMA_BYTES_PER_PACKET;
|
||||
for (;;)
|
||||
{
|
||||
// If we have exceeded the size of the XMA data, return failure
|
||||
if (pCurrentPacket + XMA_BYTES_PER_PACKET > pXmaData + nXmaDataBytes)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If the current packet contains the frame we are looking for...
|
||||
if (nFrameCountSoFar + GetXmaPacketFrameCount(pCurrentPacket) > nDesiredFrame)
|
||||
{
|
||||
// See how many frames in this packet we need to skip to get to it
|
||||
XMA2DEFS_ASSERT(nDesiredFrame >= nFrameCountSoFar);
|
||||
nFramesToSkip = nDesiredFrame - nFrameCountSoFar;
|
||||
|
||||
// Get the bit offset of the first frame in this packet
|
||||
nFrameBitOffset = XMA_PACKET_HEADER_BITS + GetXmaPacketFirstFrameOffsetInBits(pCurrentPacket);
|
||||
|
||||
// Advance nFrameBitOffset to the frame of interest
|
||||
while (nFramesToSkip--)
|
||||
{
|
||||
nFrameBitOffset += GetXmaFrameLengthInBits(pCurrentPacket, nFrameBitOffset);
|
||||
}
|
||||
|
||||
// The bit offset to return is the number of bits from pXmaData to
|
||||
// pCurrentPacket plus the bit offset of the frame of interest
|
||||
return (DWORD)(pCurrentPacket - pXmaData) * 8 + nFrameBitOffset;
|
||||
}
|
||||
|
||||
// If we haven't found the right packet yet, advance our counters
|
||||
++nPacketsExamined;
|
||||
nFrameCountSoFar += GetXmaPacketFrameCount(pCurrentPacket);
|
||||
|
||||
// And skip to the next packet belonging to the same stream
|
||||
pCurrentPacket += XMA_BYTES_PER_PACKET * (GetXmaPacketSkipCount(pCurrentPacket) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// GetLastXmaFrameBitPosition: Calculates the bit offset of the last complete
|
||||
// frame in an XMA block or set of blocks.
|
||||
|
||||
__inline DWORD GetLastXmaFrameBitPosition
|
||||
(
|
||||
__in_bcount(nXmaDataBytes) const BYTE* pXmaData, // Pointer to XMA block[s]
|
||||
DWORD nXmaDataBytes, // Size of pXmaData in bytes
|
||||
DWORD nStreamIndex // Stream within which to seek
|
||||
)
|
||||
{
|
||||
const BYTE* pLastPacket;
|
||||
DWORD nBytesToNextPacket;
|
||||
DWORD nFrameBitOffset;
|
||||
DWORD nFramesInLastPacket;
|
||||
|
||||
XMA2DEFS_ASSERT(pXmaData);
|
||||
XMA2DEFS_ASSERT(nXmaDataBytes % XMA_BYTES_PER_PACKET == 0);
|
||||
XMA2DEFS_ASSERT(nXmaDataBytes >= XMA_BYTES_PER_PACKET * (nStreamIndex + 1));
|
||||
|
||||
// Get the first XMA packet belonging to the desired stream, relying on the
|
||||
// fact that the first packets for each stream are in consecutive order at
|
||||
// the beginning of an XMA block.
|
||||
pLastPacket = pXmaData + nStreamIndex * XMA_BYTES_PER_PACKET;
|
||||
|
||||
// Search for the last packet belonging to the desired stream
|
||||
for (;;)
|
||||
{
|
||||
nBytesToNextPacket = XMA_BYTES_PER_PACKET * (GetXmaPacketSkipCount(pLastPacket) + 1);
|
||||
XMA2DEFS_ASSERT(nBytesToNextPacket);
|
||||
if (pLastPacket + nBytesToNextPacket + XMA_BYTES_PER_PACKET > pXmaData + nXmaDataBytes)
|
||||
{
|
||||
break; // The next packet would extend beyond the end of pXmaData
|
||||
}
|
||||
pLastPacket += nBytesToNextPacket;
|
||||
}
|
||||
|
||||
// The last packet can sometimes have no seekable frames, in which case we
|
||||
// have to use the previous one
|
||||
if (GetXmaPacketFrameCount(pLastPacket) == 0)
|
||||
{
|
||||
pLastPacket -= nBytesToNextPacket;
|
||||
}
|
||||
|
||||
// Found the last packet. Get the bit offset of its first frame.
|
||||
nFrameBitOffset = XMA_PACKET_HEADER_BITS + GetXmaPacketFirstFrameOffsetInBits(pLastPacket);
|
||||
|
||||
// Traverse frames until we reach the last one
|
||||
nFramesInLastPacket = GetXmaPacketFrameCount(pLastPacket);
|
||||
while (--nFramesInLastPacket)
|
||||
{
|
||||
nFrameBitOffset += GetXmaFrameLengthInBits(pLastPacket, nFrameBitOffset);
|
||||
}
|
||||
|
||||
// The bit offset to return is the number of bits from pXmaData to
|
||||
// pLastPacket plus the offset of the last frame in this packet.
|
||||
return (DWORD)(pLastPacket - pXmaData) * 8 + nFrameBitOffset;
|
||||
}
|
||||
|
||||
|
||||
// GetXmaDecodePositionForSample: Obtains the information needed to make the
|
||||
// decoder generate audio starting at a given sample position relative to the
|
||||
// beginning of the given XMA block: the bit offset of the appropriate frame,
|
||||
// and the right subframe within that frame. This data can be passed directly
|
||||
// to the XMAPlaybackSetDecodePosition function.
|
||||
|
||||
__inline HRESULT GetXmaDecodePositionForSample
|
||||
(
|
||||
__in_bcount(nXmaDataBytes) const BYTE* pXmaData, // Pointer to XMA block[s]
|
||||
DWORD nXmaDataBytes, // Size of pXmaData in bytes
|
||||
DWORD nStreamIndex, // Stream within which to seek
|
||||
DWORD nDesiredSample, // Sample sought
|
||||
__out DWORD* pnBitOffset, // Returns the bit offset within pXmaData of
|
||||
// the frame containing the sample sought
|
||||
__out DWORD* pnSubFrame // Returns the subframe containing the sample
|
||||
)
|
||||
{
|
||||
DWORD nDesiredFrame = nDesiredSample / XMA_SAMPLES_PER_FRAME;
|
||||
DWORD nSubFrame = (nDesiredSample % XMA_SAMPLES_PER_FRAME) / XMA_SAMPLES_PER_SUBFRAME;
|
||||
DWORD nBitOffset = GetXmaFrameBitPosition(pXmaData, nXmaDataBytes, nStreamIndex, nDesiredFrame);
|
||||
|
||||
XMA2DEFS_ASSERT(pnBitOffset);
|
||||
XMA2DEFS_ASSERT(pnSubFrame);
|
||||
|
||||
if (nBitOffset)
|
||||
{
|
||||
*pnBitOffset = nBitOffset;
|
||||
*pnSubFrame = nSubFrame;
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// GetXmaSampleRate: Obtains the legal XMA sample rate (24, 32, 44.1 or 48Khz)
|
||||
// corresponding to a generic sample rate.
|
||||
|
||||
__inline DWORD GetXmaSampleRate(DWORD dwGeneralRate)
|
||||
{
|
||||
DWORD dwXmaRate = 48000; // Default XMA rate for all rates above 44100Hz
|
||||
|
||||
if (dwGeneralRate <= 24000) dwXmaRate = 24000;
|
||||
else if (dwGeneralRate <= 32000) dwXmaRate = 32000;
|
||||
else if (dwGeneralRate <= 44100) dwXmaRate = 44100;
|
||||
|
||||
return dwXmaRate;
|
||||
}
|
||||
|
||||
|
||||
// Functions to convert between WAVEFORMATEXTENSIBLE channel masks (combinations
|
||||
// of the SPEAKER_xxx flags defined in audiodefs.h) and XMA channel masks (which
|
||||
// are limited to eight possible speaker positions: left, right, center, low
|
||||
// frequency, side left, side right, back left and back right).
|
||||
|
||||
__inline DWORD GetStandardChannelMaskFromXmaMask(BYTE bXmaMask)
|
||||
{
|
||||
DWORD dwStandardMask = 0;
|
||||
|
||||
if (bXmaMask & XMA_SPEAKER_LEFT) dwStandardMask |= SPEAKER_FRONT_LEFT;
|
||||
if (bXmaMask & XMA_SPEAKER_RIGHT) dwStandardMask |= SPEAKER_FRONT_RIGHT;
|
||||
if (bXmaMask & XMA_SPEAKER_CENTER) dwStandardMask |= SPEAKER_FRONT_CENTER;
|
||||
if (bXmaMask & XMA_SPEAKER_LFE) dwStandardMask |= SPEAKER_LOW_FREQUENCY;
|
||||
if (bXmaMask & XMA_SPEAKER_LEFT_SURROUND) dwStandardMask |= SPEAKER_SIDE_LEFT;
|
||||
if (bXmaMask & XMA_SPEAKER_RIGHT_SURROUND) dwStandardMask |= SPEAKER_SIDE_RIGHT;
|
||||
if (bXmaMask & XMA_SPEAKER_LEFT_BACK) dwStandardMask |= SPEAKER_BACK_LEFT;
|
||||
if (bXmaMask & XMA_SPEAKER_RIGHT_BACK) dwStandardMask |= SPEAKER_BACK_RIGHT;
|
||||
|
||||
return dwStandardMask;
|
||||
}
|
||||
|
||||
__inline BYTE GetXmaChannelMaskFromStandardMask(DWORD dwStandardMask)
|
||||
{
|
||||
BYTE bXmaMask = 0;
|
||||
|
||||
if (dwStandardMask & SPEAKER_FRONT_LEFT) bXmaMask |= XMA_SPEAKER_LEFT;
|
||||
if (dwStandardMask & SPEAKER_FRONT_RIGHT) bXmaMask |= XMA_SPEAKER_RIGHT;
|
||||
if (dwStandardMask & SPEAKER_FRONT_CENTER) bXmaMask |= XMA_SPEAKER_CENTER;
|
||||
if (dwStandardMask & SPEAKER_LOW_FREQUENCY) bXmaMask |= XMA_SPEAKER_LFE;
|
||||
if (dwStandardMask & SPEAKER_SIDE_LEFT) bXmaMask |= XMA_SPEAKER_LEFT_SURROUND;
|
||||
if (dwStandardMask & SPEAKER_SIDE_RIGHT) bXmaMask |= XMA_SPEAKER_RIGHT_SURROUND;
|
||||
if (dwStandardMask & SPEAKER_BACK_LEFT) bXmaMask |= XMA_SPEAKER_LEFT_BACK;
|
||||
if (dwStandardMask & SPEAKER_BACK_RIGHT) bXmaMask |= XMA_SPEAKER_RIGHT_BACK;
|
||||
|
||||
return bXmaMask;
|
||||
}
|
||||
|
||||
|
||||
// LocalizeXma2Format: Modifies a XMA2WAVEFORMATEX structure in place to comply
|
||||
// with the current platform's byte-ordering rules (little- or big-endian).
|
||||
|
||||
__inline HRESULT LocalizeXma2Format(__inout XMA2WAVEFORMATEX* pXma2Format)
|
||||
{
|
||||
#define XMASWAP2BYTES(n) ((WORD)(((n) >> 8) | (((n) & 0xff) << 8)))
|
||||
#define XMASWAP4BYTES(n) ((DWORD)((n) >> 24 | (n) << 24 | ((n) & 0xff00) << 8 | ((n) & 0xff0000) >> 8))
|
||||
|
||||
if (pXma2Format->wfx.wFormatTag == WAVE_FORMAT_XMA2)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
else if (XMASWAP2BYTES(pXma2Format->wfx.wFormatTag) == WAVE_FORMAT_XMA2)
|
||||
{
|
||||
pXma2Format->wfx.wFormatTag = XMASWAP2BYTES(pXma2Format->wfx.wFormatTag);
|
||||
pXma2Format->wfx.nChannels = XMASWAP2BYTES(pXma2Format->wfx.nChannels);
|
||||
pXma2Format->wfx.nSamplesPerSec = XMASWAP4BYTES(pXma2Format->wfx.nSamplesPerSec);
|
||||
pXma2Format->wfx.nAvgBytesPerSec = XMASWAP4BYTES(pXma2Format->wfx.nAvgBytesPerSec);
|
||||
pXma2Format->wfx.nBlockAlign = XMASWAP2BYTES(pXma2Format->wfx.nBlockAlign);
|
||||
pXma2Format->wfx.wBitsPerSample = XMASWAP2BYTES(pXma2Format->wfx.wBitsPerSample);
|
||||
pXma2Format->wfx.cbSize = XMASWAP2BYTES(pXma2Format->wfx.cbSize);
|
||||
pXma2Format->NumStreams = XMASWAP2BYTES(pXma2Format->NumStreams);
|
||||
pXma2Format->ChannelMask = XMASWAP4BYTES(pXma2Format->ChannelMask);
|
||||
pXma2Format->SamplesEncoded = XMASWAP4BYTES(pXma2Format->SamplesEncoded);
|
||||
pXma2Format->BytesPerBlock = XMASWAP4BYTES(pXma2Format->BytesPerBlock);
|
||||
pXma2Format->PlayBegin = XMASWAP4BYTES(pXma2Format->PlayBegin);
|
||||
pXma2Format->PlayLength = XMASWAP4BYTES(pXma2Format->PlayLength);
|
||||
pXma2Format->LoopBegin = XMASWAP4BYTES(pXma2Format->LoopBegin);
|
||||
pXma2Format->LoopLength = XMASWAP4BYTES(pXma2Format->LoopLength);
|
||||
pXma2Format->BlockCount = XMASWAP2BYTES(pXma2Format->BlockCount);
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return E_FAIL; // Not a recognizable XMA2 format
|
||||
}
|
||||
|
||||
#undef XMASWAP2BYTES
|
||||
#undef XMASWAP4BYTES
|
||||
}
|
||||
|
||||
|
||||
#endif // #ifndef __XMA2DEFS_INCLUDED__
|
||||
Vendored
+1
-1
Submodule 3rdparty/ffmpeg updated: 7b7ae7b067...e5fb13bbb0
Vendored
+1
-1
Submodule 3rdparty/libusb updated: 7cfa00e9d7...e782eeb251
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
cmake_minimum_required(VERSION 2.8.4)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_BINARY_DIR}/cmake/modules")
|
||||
|
||||
set(LIBUSB_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../libusb/)
|
||||
|
||||
project(libusb)
|
||||
|
||||
option(WITH_DEBUG_LOG "enable debug logging" OFF)
|
||||
# if debug logging is enabled, by default enable logging
|
||||
option(WITH_LOGGING "if false, disable all logging" ON)
|
||||
option(WITHOUT_PTHREADS "force pthreads to not be used. if on, then they are used based on detection logic" OFF)
|
||||
|
||||
set(LIBUSB_MAJOR 1)
|
||||
set(LIBUSB_MINOR 0)
|
||||
set(LIBUSB_MICRO 23)
|
||||
|
||||
macro(append_compiler_flags)
|
||||
foreach(FLAG IN ITEMS ${ARGN})
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAG}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAG}")
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
include(libusb.cmake)
|
||||
@@ -0,0 +1,17 @@
|
||||
# CoreFoundation_INCLUDE_DIR
|
||||
# CoreFoundation_LIBRARIES
|
||||
# CoreFoundation_FOUND
|
||||
include(LibFindMacros)
|
||||
|
||||
find_path(CoreFoundation_INCLUDE_DIR
|
||||
CoreFoundation.h
|
||||
PATH_SUFFIXES CoreFoundation
|
||||
)
|
||||
|
||||
find_library(CoreFoundation_LIBRARY
|
||||
NAMES CoreFoundation
|
||||
)
|
||||
|
||||
set(CoreFoundation_PROCESS_INCLUDES CoreFoundation_INCLUDE_DIR)
|
||||
set(CoreFoundation_PROCESS_LIBS CoreFoundation_LIBRARY)
|
||||
libfind_process(CoreFoundation)
|
||||
@@ -0,0 +1,20 @@
|
||||
# IOKit_INCLUDE_DIR
|
||||
# IOKit_LIBRARIES
|
||||
# IOKit_FOUND
|
||||
include(LibFindMacros)
|
||||
|
||||
# IOKit depends on CoreFoundation
|
||||
find_package(CoreFoundation REQUIRED)
|
||||
|
||||
find_path(IOKit_INCLUDE_DIR
|
||||
IOKitLib.h
|
||||
PATH_SUFFIXES IOKit
|
||||
)
|
||||
|
||||
find_library(IOKit_LIBRARY
|
||||
NAMES IOKit
|
||||
)
|
||||
|
||||
set(IOKit_PROCESS_INCLUDES IOKit_INCLUDE_DIR CoreFoundation_INCLUDE_DIR)
|
||||
set(IOKit_PROCESS_LIBS IOKit_LIBRARY CoreFoundation_LIBRARIES)
|
||||
libfind_process(IOKit)
|
||||
@@ -0,0 +1,99 @@
|
||||
# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments
|
||||
# used for the current package. For this to work, the first parameter must be the
|
||||
# prefix of the current package, then the prefix of the new package etc, which are
|
||||
# passed to find_package.
|
||||
macro (libfind_package PREFIX)
|
||||
set (LIBFIND_PACKAGE_ARGS ${ARGN})
|
||||
if (${PREFIX}_FIND_QUIETLY)
|
||||
set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} QUIET)
|
||||
endif (${PREFIX}_FIND_QUIETLY)
|
||||
if (${PREFIX}_FIND_REQUIRED)
|
||||
set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED)
|
||||
endif (${PREFIX}_FIND_REQUIRED)
|
||||
find_package(${LIBFIND_PACKAGE_ARGS})
|
||||
endmacro (libfind_package)
|
||||
|
||||
# CMake developers made the UsePkgConfig system deprecated in the same release (2.6)
|
||||
# where they added pkg_check_modules. Consequently I need to support both in my scripts
|
||||
# to avoid those deprecated warnings. Here's a helper that does just that.
|
||||
# Works identically to pkg_check_modules, except that no checks are needed prior to use.
|
||||
macro (libfind_pkg_check_modules PREFIX PKGNAME)
|
||||
if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
|
||||
include(UsePkgConfig)
|
||||
pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS)
|
||||
else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
|
||||
find_package(PkgConfig)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(${PREFIX} ${PKGNAME})
|
||||
endif (PKG_CONFIG_FOUND)
|
||||
endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
|
||||
endmacro (libfind_pkg_check_modules)
|
||||
|
||||
# Do the final processing once the paths have been detected.
|
||||
# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain
|
||||
# all the variables, each of which contain one include directory.
|
||||
# Ditto for ${PREFIX}_PROCESS_LIBS and library files.
|
||||
# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES.
|
||||
# Also handles errors in case library detection was required, etc.
|
||||
macro (libfind_process PREFIX)
|
||||
# Skip processing if already processed during this run
|
||||
if (NOT ${PREFIX}_FOUND)
|
||||
# Start with the assumption that the library was found
|
||||
set (${PREFIX}_FOUND TRUE)
|
||||
|
||||
# Process all includes and set _FOUND to false if any are missing
|
||||
foreach (i ${${PREFIX}_PROCESS_INCLUDES})
|
||||
if (${i})
|
||||
set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}})
|
||||
mark_as_advanced(${i})
|
||||
else (${i})
|
||||
set (${PREFIX}_FOUND FALSE)
|
||||
endif (${i})
|
||||
endforeach (i)
|
||||
|
||||
# Process all libraries and set _FOUND to false if any are missing
|
||||
foreach (i ${${PREFIX}_PROCESS_LIBS})
|
||||
if (${i})
|
||||
set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}})
|
||||
mark_as_advanced(${i})
|
||||
else (${i})
|
||||
set (${PREFIX}_FOUND FALSE)
|
||||
endif (${i})
|
||||
endforeach (i)
|
||||
|
||||
# Print message and/or exit on fatal error
|
||||
if (${PREFIX}_FOUND)
|
||||
if (NOT ${PREFIX}_FIND_QUIETLY)
|
||||
message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}")
|
||||
endif (NOT ${PREFIX}_FIND_QUIETLY)
|
||||
else (${PREFIX}_FOUND)
|
||||
if (${PREFIX}_FIND_REQUIRED)
|
||||
foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS})
|
||||
message("${i}=${${i}}")
|
||||
endforeach (i)
|
||||
message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.")
|
||||
endif (${PREFIX}_FIND_REQUIRED)
|
||||
endif (${PREFIX}_FOUND)
|
||||
endif (NOT ${PREFIX}_FOUND)
|
||||
endmacro (libfind_process)
|
||||
|
||||
macro(libfind_library PREFIX basename)
|
||||
set(TMP "")
|
||||
if(MSVC80)
|
||||
set(TMP -vc80)
|
||||
endif(MSVC80)
|
||||
if(MSVC90)
|
||||
set(TMP -vc90)
|
||||
endif(MSVC90)
|
||||
set(${PREFIX}_LIBNAMES ${basename}${TMP})
|
||||
if(${ARGC} GREATER 2)
|
||||
set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2})
|
||||
string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES})
|
||||
set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP})
|
||||
endif(${ARGC} GREATER 2)
|
||||
find_library(${PREFIX}_LIBRARY
|
||||
NAMES ${${PREFIX}_LIBNAMES}
|
||||
PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS}
|
||||
)
|
||||
endmacro(libfind_library)
|
||||
|
||||
Vendored
+96
@@ -0,0 +1,96 @@
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckTypeSize)
|
||||
|
||||
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||
if (NOT OS_WINDOWS)
|
||||
# mingw appears to print a bunch of warnings about this
|
||||
check_cxx_compiler_flag("-fvisibility=hidden" HAVE_VISIBILITY)
|
||||
endif()
|
||||
check_cxx_compiler_flag("-Wno-pointer-sign" HAVE_WARN_NO_POINTER_SIGN)
|
||||
|
||||
set(_GNU_SOURCE 1 CACHE INTERNAL "" FORCE)
|
||||
|
||||
unset(ADDITIONAL_CC_FLAGS)
|
||||
|
||||
if (HAVE_VISIBILITY)
|
||||
list(APPEND ADDITIONAL_CC_FLAGS -fvisibility=hidden)
|
||||
endif()
|
||||
|
||||
if (HAVE_WARN_NO_POINTER_SIGN)
|
||||
list(APPEND ADDITIONAL_CC_FLAGS -Wno-pointer-sign)
|
||||
endif()
|
||||
|
||||
append_compiler_flags(
|
||||
-std=gnu99
|
||||
-Wall
|
||||
-Wundef
|
||||
-Wunused
|
||||
-Wstrict-prototypes
|
||||
-Werror-implicit-function-declaration
|
||||
-Wshadow
|
||||
${ADDITIONAL_CC_FLAGS}
|
||||
)
|
||||
elseif(MSVC)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
check_include_files(sys/timerfd.h USBI_TIMERFD_AVAILABLE)
|
||||
#check_type_size(struct timespec STRUCT_TIMESPEC)
|
||||
|
||||
if (HAVE_VISIBILITY)
|
||||
set(DEFAULT_VISIBILITY "__attribute__((visibility(\"default\")))" CACHE INTERNAL "visibility attribute to function decl" FORCE)
|
||||
else()
|
||||
set(DEFAULT_VISIBILITY "" CACHE INTERNAL "visibility attribute to function decl" FORCE)
|
||||
endif()
|
||||
|
||||
if (NOT WITHOUT_POLL_H)
|
||||
check_include_files(poll.h HAVE_POLL_H)
|
||||
else()
|
||||
set(HAVE_POLL_H FALSE CACHE INTERNAL "poll.h explicitely disabled" FORCE)
|
||||
endif()
|
||||
|
||||
if (HAVE_POLL_H)
|
||||
list(APPEND CMAKE_EXTRA_INCLUDE_FILES "poll.h")
|
||||
check_type_size(nfds_t NFDS_T)
|
||||
unset(CMAKE_EXTRA_INCLUDE_FILES)
|
||||
else()
|
||||
set(HAVE_NFDS_T FALSE CACHE INTERNAL "poll.h not found - assuming no nfds_t (windows)" FORCE)
|
||||
set(NFDS_T "" CACHE INTERNAL "" FORCE)
|
||||
endif()
|
||||
|
||||
if (HAVE_NFDS_T)
|
||||
set(POLL_NFDS_TYPE nfds_t CACHE INTERNAL "the poll nfds types for this platform" FORCE)
|
||||
else()
|
||||
set(POLL_NFDS_TYPE "unsigned int" CACHE INTERNAL "the poll nfds for this platform" FORCE)
|
||||
endif()
|
||||
|
||||
if (OS_WINDOWS)
|
||||
macro(copy_header_if_missing HEADER VARIABLE ALTERNATIVE_DIR)
|
||||
check_include_files(${HEADER} ${VARIABLE})
|
||||
if (NOT ${VARIABLE})
|
||||
message(STATUS "Missing ${HEADER} - grabbing from ${ALTERNATIVE_DIR}")
|
||||
file(COPY "${ALTERNATIVE_DIR}/${HEADER}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Only VS 2010 has stdint.h
|
||||
copy_header_if_missing(stdint.h HAVE_STDINT_H ../msvc)
|
||||
copy_header_if_missing(inttypes.h HAVE_INTTYPES_H ../msvc)
|
||||
endif()
|
||||
|
||||
set(ENABLE_DEBUG_LOGGING ${WITH_DEBUG_LOG} CACHE INTERNAL "enable debug logging (WITH_DEBUG_LOGGING)" FORCE)
|
||||
set(ENABLE_LOGGING ${WITH_LOGGING} CACHE INTERNAL "enable logging (WITH_LOGGING)" FORCE)
|
||||
set(PACKAGE "libusb" CACHE INTERNAL "The package name" FORCE)
|
||||
set(PACKAGE_BUGREPORT "libusb-devel@lists.sourceforge.net" CACHE INTERNAL "Where to send bug reports" FORCE)
|
||||
set(PACKAGE_VERSION "${LIBUSB_MAJOR}.${LIBUSB_MINOR}.${LIBUSB_MICRO}" CACHE INTERNAL "package version" FORCE)
|
||||
set(PACKAGE_STRING "${PACKAGE} ${PACKAGE_VERSION}" CACHE INTERNAL "package string" FORCE)
|
||||
set(PACKAGE_URL "http://www.libusb.org" CACHE INTERNAL "package url" FORCE)
|
||||
set(PACKAGE_TARNAME "libusb" CACHE INTERNAL "tarball name" FORCE)
|
||||
set(VERSION "${PACKAGE_VERSION}" CACHE INTERNAL "version" FORCE)
|
||||
|
||||
configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h @ONLY)
|
||||
message(STATUS "Generated configuration file in ${CMAKE_CURRENT_BINARY_DIR}/config.h")
|
||||
|
||||
# for generated config.h
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
#ifndef LIBUSB_CONFIG_H
|
||||
#define LIBUSB_CONFIG_H
|
||||
|
||||
#define DEFAULT_VISIBILITY @DEFAULT_VISIBILITY@
|
||||
|
||||
#cmakedefine ENABLE_DEBUG_LOGGING
|
||||
|
||||
#cmakedefine ENABLE_LOGGING
|
||||
|
||||
#define LIBUSB_MAJOR @LIBUSB_MAJOR@
|
||||
|
||||
#define LIBUSB_MINOR @LIBUSB_MINOR@
|
||||
|
||||
#define LIBUSB_MICRO @LIBUSB_MINOR@
|
||||
|
||||
#define _GNU_SOURCE 1
|
||||
|
||||
#define PACKAGE @PACKAGE@
|
||||
#define PACKAGE_BUGREPORT @PACKAGE_BUGREPORT@
|
||||
#define PACKAGE_STRING @PACKAGE_STRING@
|
||||
#define PACKAGE_URL @PACKAGE_URL@
|
||||
#define PACKAGE_VERSION @PACKAGE_VERSION@
|
||||
#define PACKAGE_TARNAME @PACKAGE_TARNAME@
|
||||
|
||||
#define VERSION @VERSION@
|
||||
|
||||
#cmakedefine OS_LINUX
|
||||
#cmakedefine OS_DARWIN
|
||||
#cmakedefine OS_WINDOWS
|
||||
#cmakedefine THREADS_POSIX
|
||||
#cmakedefine USBI_TIMERFD_AVAILABLE
|
||||
#cmakedefine HAVE_STRUCT_TIMESPEC
|
||||
#cmakedefine HAVE_POLL_H
|
||||
#cmakedefine HAVE_SYS_TIME_H
|
||||
#define POLL_NFDS_TYPE @POLL_NFDS_TYPE@
|
||||
|
||||
#endif /* LIBUSB_CONFIG_H */
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
libdir=@CMAKE_INSTALL_PREFIX@/lib@
|
||||
includedir=@CMAKE_INSTALL_PREFIX@/include@
|
||||
|
||||
Name: libusb-1.0
|
||||
Description: C API for USB device access from Linux, Mac OS X and Windows userspace
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lusb-1.0
|
||||
Libs.private: @LIBUSB_LIB_DEPENDS@
|
||||
Cflags: -I${includedir}/libusb-1.0
|
||||
|
||||
Vendored
+76
@@ -0,0 +1,76 @@
|
||||
include(os.cmake)
|
||||
|
||||
include(config.cmake)
|
||||
include(FindThreads)
|
||||
|
||||
set (LIBUSB_COMMON
|
||||
core.c
|
||||
descriptor.c
|
||||
io.c
|
||||
sync.c
|
||||
hotplug.c
|
||||
strerror.c
|
||||
libusb-1.0.rc
|
||||
libusb-1.0.def
|
||||
)
|
||||
|
||||
foreach(SRC IN LISTS LIBUSB_COMMON)
|
||||
list(APPEND LIBUSB_COMMON_FINAL ${LIBUSB_SOURCE_DIR}/libusb/${SRC})
|
||||
endforeach()
|
||||
|
||||
|
||||
include_directories(${LIBUSB_SOURCE_DIR}/libusb)
|
||||
include_directories(${LIBUSB_SOURCE_DIR}/libusb/os)
|
||||
|
||||
if (CMAKE_THREAD_LIBS_INIT)
|
||||
list(APPEND LIBUSB_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
|
||||
add_library(usb-1.0-static
|
||||
STATIC
|
||||
${LIBUSB_COMMON_FINAL}
|
||||
${LIBUSB_PLATFORM}
|
||||
)
|
||||
|
||||
target_include_directories(usb-1.0-static PUBLIC $<BUILD_INTERFACE:${LIBUSB_SOURCE_DIR}/libusb>)
|
||||
|
||||
set_target_properties(usb-1.0-static PROPERTIES
|
||||
PREFIX "lib"
|
||||
OUTPUT_NAME "usb-1.0"
|
||||
CLEAN_DIRECT_OUTPUT 1
|
||||
PUBLIC_HEADER libusb.h
|
||||
VERSION "${LIBUSB_MAJOR}.${LIBUSB_MINOR}.${LIBUSB_MICRO}"
|
||||
SOVERSION "${LIBUSB_MAJOR}.${LIBUSB_MINOR}.${LIBUSB_MICRO}"
|
||||
)
|
||||
|
||||
if (DEFINED LIBUSB_LIBRARIES)
|
||||
target_link_libraries(usb-1.0-static
|
||||
${LIBUSB_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND LIBUSB_LIBTARGETS usb-1.0-static)
|
||||
|
||||
install(TARGETS ${LIBUSB_LIBTARGETS} EXPORT libusb-1
|
||||
PUBLIC_HEADER DESTINATION include/libusb-1.0
|
||||
ARCHIVE DESTINATION lib
|
||||
LIBRARY DESTINATION lib
|
||||
RUNTIME DESTINATION lib
|
||||
)
|
||||
install(EXPORT libusb-1 DESTINATION lib/libusb)
|
||||
|
||||
foreach(LIB IN LISTS LIBUSB_LIBRARIES)
|
||||
if (LIB MATCHES .framework$)
|
||||
get_filename_component(LIB "${LIB}" NAME)
|
||||
set(LIB "-Wl,-framework,${LIB}")
|
||||
elseif (LIB MATCHES .dylib$)
|
||||
get_filename_component(LIBDIR "${LIB}" PATH)
|
||||
get_filename_component(LIB "${LIB}" NAME)
|
||||
string(REGEX REPLACE "lib(.*).dylib$" "\\1" LIB "${LIB}")
|
||||
set(LIB "-L${LIBDIR} -l${LIB}")
|
||||
endif()
|
||||
set(LIBUSB_LIB_DEPENDS "${LIBUSB_LIB_DEPENDS} ${LIB}")
|
||||
endforeach()
|
||||
|
||||
configure_file(libusb-1.0.pc.cmake "${CMAKE_CURRENT_BINARY_DIR}/libusb-1.0.pc" @ONLY)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libusb-1.0.pc" DESTINATION lib/pkgconfig)
|
||||
Vendored
+107
@@ -0,0 +1,107 @@
|
||||
include(FindThreads)
|
||||
|
||||
set(PTHREADS_ENABLED FALSE)
|
||||
if (CMAKE_USE_PTHREADS_INIT)
|
||||
set(PTHREADS_ENABLED TRUE)
|
||||
endif()
|
||||
|
||||
if (WIN32 OR "${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN")
|
||||
set(OS_WINDOWS 1 CACHE INTERNAL "controls config.h macro definition" FORCE)
|
||||
|
||||
# Enable MingW support for RC language (for CMake pre-2.8)
|
||||
if (MINGW)
|
||||
set(CMAKE_RC_COMPILER_INIT windres)
|
||||
set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> <FLAGS> -O coff <DEFINES> -i <SOURCE> -o <OBJECT>")
|
||||
endif()
|
||||
enable_language(RC)
|
||||
|
||||
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "CYGWIN")
|
||||
message(STATUS "Detected cygwin")
|
||||
set(PTHREADS_ENABLED TRUE)
|
||||
set(WITHOUT_POLL_H TRUE CACHE INTERNAL "Disable using poll.h even if it's available - use windows poll instead fo cygwin's" FORCE)
|
||||
endif()
|
||||
|
||||
list(APPEND PLATFORM_SRC
|
||||
poll_windows.c
|
||||
windows_usbdk.c
|
||||
windows_nt_common.c
|
||||
windows_winusb.c
|
||||
threads_windows.c
|
||||
)
|
||||
|
||||
if (PTHREADS_ENABLED AND NOT WITHOUT_PTHREADS)
|
||||
list(APPEND PLATFORM_SRC threads_posix)
|
||||
else()
|
||||
list(APPEND PLATFORM_SRC threads_windows.c)
|
||||
endif()
|
||||
elseif (APPLE)
|
||||
# Apple != OSX alone
|
||||
set(OS_DARWIN 1 CACHE INTERNAL "controls config.h macro definition" FORCE)
|
||||
|
||||
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
|
||||
set(PLATFORM_SRC
|
||||
darwin_usb.c
|
||||
threads_posix.c
|
||||
poll_posix.c
|
||||
)
|
||||
|
||||
find_package(IOKit REQUIRED)
|
||||
list(APPEND LIBUSB_LIBRARIES ${IOKit_LIBRARIES})
|
||||
|
||||
# Currently only objc_registerThreadWithCollector requires linking against it
|
||||
# which is only for MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
|
||||
include(CheckCSourceCompiles)
|
||||
check_c_source_compiles(
|
||||
"#include <AvailabilityMacros.h>
|
||||
int main()
|
||||
{
|
||||
#if !(MAC_OS_X_VERSION_MIN_REQUIRED >= 1060)
|
||||
#error \"Don't need objc\"
|
||||
#endif
|
||||
}
|
||||
" NEED_OBJC_REGISTER_THREAD_WITH_COLLECTOR)
|
||||
|
||||
if (NEED_OBJC_REGISTER_THREAD_WITH_COLLECTOR)
|
||||
find_library(LIBOBJC objc)
|
||||
if (NOT LIBOBJC)
|
||||
message(SEND_ERROR "Need objc library but can't find it")
|
||||
else()
|
||||
list(APPEND LIBUSB_LIBRARIES ${LIBOBJC})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
elseif (UNIX)
|
||||
# Unix is for all *NIX systems including OSX
|
||||
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
|
||||
set(OS_LINUX 1 CACHE INTERNAL "controls config.h macro definition" FORCE)
|
||||
|
||||
set(PLATFORM_SRC
|
||||
linux_usbfs.c
|
||||
linux_netlink.c
|
||||
threads_posix.c
|
||||
poll_posix.c
|
||||
)
|
||||
|
||||
list(APPEND LIBUSB_LIBRARIES rt)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT PLATFORM_SRC)
|
||||
message(FATAL_ERROR "Unsupported platform ${CMAKE_SYSTEM_NAME}. Currently only support Windows, OSX, & Linux.")
|
||||
endif()
|
||||
|
||||
# the paths are relative to this directory but used in the parent directory,
|
||||
# so we have to adjust the paths
|
||||
foreach(SRC IN LISTS PLATFORM_SRC)
|
||||
list(APPEND LIBUSB_PLATFORM ${LIBUSB_SOURCE_DIR}/libusb/os/${SRC})
|
||||
endforeach()
|
||||
|
||||
# export one level up so that the generic
|
||||
# libusb parts know what the platform bits are supposed to be
|
||||
set(LIBUSB_PLATFORM ${LIBUSB_PLATFORM} PARENT_SCOPE)
|
||||
set(LIBUSB_LIBRARIES ${LIBUSB_LIBRARIES} PARENT_SCOPE)
|
||||
|
||||
if (WITHOUT_PTHREADS)
|
||||
set(PTHREADS_ENABLED FALSE)
|
||||
endif()
|
||||
set(THREADS_POSIX ${PTHREADS_ENABLED} CACHE INTERNAL "use pthreads" FORCE)
|
||||
Vendored
+9
-9
@@ -1,11 +1,11 @@
|
||||
add_library(3rdparty_qt5 INTERFACE)
|
||||
|
||||
find_package(Qt5 5.11 CONFIG COMPONENTS Widgets Network Qml Concurrent)
|
||||
find_package(Qt5 5.14 CONFIG COMPONENTS Widgets Network Qml Concurrent)
|
||||
if(WIN32)
|
||||
find_package(Qt5 5.11 COMPONENTS WinExtras REQUIRED)
|
||||
find_package(Qt5 5.14 COMPONENTS WinExtras REQUIRED)
|
||||
target_link_libraries(3rdparty_qt5 INTERFACE Qt5::Widgets Qt5::WinExtras Qt5::Network Qt5::Qml Qt5::Concurrent)
|
||||
else()
|
||||
find_package(Qt5 5.11 COMPONENTS DBus Gui)
|
||||
find_package(Qt5 5.14 COMPONENTS DBus Gui)
|
||||
if(Qt5DBus_FOUND)
|
||||
target_link_libraries(3rdparty_qt5 INTERFACE Qt5::Widgets Qt5::DBus Qt5::Network Qt5::Qml Qt5::Concurrent)
|
||||
target_compile_definitions(3rdparty_qt5 INTERFACE -DHAVE_QTDBUS)
|
||||
@@ -16,15 +16,15 @@ else()
|
||||
endif()
|
||||
|
||||
if(NOT Qt5Widgets_FOUND)
|
||||
if(Qt5Widgets_VERSION VERSION_LESS 5.11.0)
|
||||
message("Minimum supported Qt5 version is 5.11.0! You have version ${Qt5Widgets_VERSION} installed, please upgrade!")
|
||||
if(Qt5Widgets_VERSION VERSION_LESS 5.14.0)
|
||||
message("Minimum supported Qt5 version is 5.14.0! You have version ${Qt5Widgets_VERSION} installed, please upgrade!")
|
||||
if(CMAKE_SYSTEM MATCHES "Linux")
|
||||
message(FATAL_ERROR "Most distros do not provide an up-to-date version of Qt.
|
||||
If you're on Ubuntu or Linux Mint, there are PPAs you can use to install one of the latest qt5 versions.
|
||||
https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.11.0-bionic
|
||||
https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.11.0-xenial
|
||||
https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.14.1-bionic
|
||||
https://launchpad.net/~beineri/+archive/ubuntu/opt-qt-5.14.1-xenial
|
||||
just make sure to run
|
||||
source /opt/qt511/bin/qt511-env.sh
|
||||
source /opt/qt514/bin/qt514-env.sh
|
||||
before re-running cmake")
|
||||
elseif(WIN32)
|
||||
message(FATAL_ERROR "You can download the latest version of Qt5 here: https://www.qt.io/download-open-source/")
|
||||
@@ -35,7 +35,7 @@ before re-running cmake")
|
||||
|
||||
message("CMake was unable to find Qt5!")
|
||||
if(WIN32)
|
||||
message(FATAL_ERROR "Make sure the QTDIR env variable has been set properly. (for example C:\\Qt\\5.11.1\\msvc2017_64\\)
|
||||
message(FATAL_ERROR "Make sure the QTDIR env variable has been set properly. (for example C:\\Qt\\5.14.1\\msvc2017_64\\)
|
||||
You can also try setting the Qt5_DIR preprocessor definiton.")
|
||||
elseif(CMAKE_SYSTEM MATCHES "Linux")
|
||||
message(FATAL_ERROR "Make sure to install your distro's qt5 package!")
|
||||
|
||||
+36
-25
@@ -9,20 +9,20 @@ Other instructions may be found [here](https://wiki.rpcs3.net/index.php?title=Bu
|
||||
|
||||
* [CMake 3.14.1+](https://www.cmake.org/download/) (add to PATH)
|
||||
* [Python 3.3+](https://www.python.org/downloads/) (add to PATH)
|
||||
* [Qt 5.11+](https://www.qt.io/download-qt-installer) (Avoid 5.11.1, due to a bug)
|
||||
* [Qt 5.14+](https://www.qt.io/download-qt-installer)
|
||||
* [Visual Studio 2019](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community)
|
||||
* [Vulkan SDK 1.1.97.0+](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html))
|
||||
* [Vulkan SDK 1.1.126+](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html))
|
||||
|
||||
**Either add the** `QTDIR` **environment variable, e.g.** `<QtInstallFolder>\5.11.0\msvc2017_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools-19123)**
|
||||
**Either add the** `QTDIR` **environment variable, e.g.** `<QtInstallFolder>\5.14.1\msvc2017_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools-19123)**
|
||||
|
||||
### Linux
|
||||
|
||||
These are the essentials tools to build RPCS3 on Linux. Some of them can be installed through your favorite package manager.
|
||||
|
||||
* Clang 5.0+ or GCC 8.1+
|
||||
* [CMake 3.8.2+](https://www.cmake.org/download/)
|
||||
* [Qt 5.11+](https://www.qt.io/download-qt-installer) (Avoid 5.11.1, due to a bug)
|
||||
* [Vulkan SDK 1.1.97.0+](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html))
|
||||
* Clang 9+ or GCC 9+
|
||||
* [CMake 3.14.1+](https://www.cmake.org/download/)
|
||||
* [Qt 5.14+](https://www.qt.io/download-qt-installer)
|
||||
* [Vulkan SDK 1.1.126+](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html))
|
||||
* [SDL2](https://www.libsdl.org/download-2.0.php) (for the FAudio backend)
|
||||
|
||||
**If you have an NVIDIA GPU, you may need to install the libglvnd package.**
|
||||
@@ -33,40 +33,51 @@ These are the essentials tools to build RPCS3 on Linux. Some of them can be inst
|
||||
|
||||
#### Debian & Ubuntu
|
||||
|
||||
sudo apt-get install cmake build-essential libasound2-dev libpulse-dev libopenal-dev libglew-dev zlib1g-dev libedit-dev libvulkan-dev libudev-dev git qt5-default libevdev-dev qtdeclarative5-dev qtbase5-private-dev libsdl2-2.0 libsdl2-dev
|
||||
sudo apt-get install build-essential libasound2-dev libpulse-dev libopenal-dev libglew-dev zlib1g-dev libedit-dev libvulkan-dev libudev-dev git libevdev-dev libsdl2-2.0 libsdl2-dev
|
||||
|
||||
##### GCC 8.x installation
|
||||
Ubuntu is usually horrendously out of date, and some packages need to be downloaded by hand. This part is for Qt, GCC, Vulkan, and CMake
|
||||
##### Qt PPA
|
||||
|
||||
If the `gcc-8` package is not available on your system, use the following command
|
||||
Ubuntu usually does not have a new enough Qt package to suit rpcs3's needs. There is a PPA available to work around this. Run the following:
|
||||
```
|
||||
ucodename=$(lsb_release -sc)
|
||||
sudo add-apt-repository ppa:beineri/opt-qt-5.14.1-$ucodename
|
||||
sudo apt-get update
|
||||
. /opt/qt514/bin/qt514-env.sh >/dev/null 2>&1
|
||||
sudo apt-get install qt514-meta-minimal qt514svg
|
||||
```
|
||||
|
||||
##### GCC 9.x installation
|
||||
|
||||
If the `gcc-9` package is not available on your system, use the following commands
|
||||
```
|
||||
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
|
||||
```
|
||||
Then
|
||||
```
|
||||
sudo apt-get update
|
||||
sudo apt-get install gcc-8 g++-8
|
||||
sudo apt-get install gcc-9 g++-9
|
||||
```
|
||||
|
||||
You can either use `update-alternatives` to setup `gcc-8`/`g++-8` as your default compilers or prefix any `cmake` command by `CXX=g++-8 CC=gcc-8 ` to use it.
|
||||
You can either use `update-alternatives` to setup `gcc-9`/`g++-9` as your default compilers or prefix any `cmake` command by `CXX=g++-9 CC=gcc-9 ` to use it.
|
||||
|
||||
##### Vulkan SDK
|
||||
|
||||
For Ubuntu systems, it is strongly recommended to use the PPA from [LunarG](https://packages.lunarg.com/) which will provide a compatible Vulkan SDK to compile RPCS3. If your Vulkan SDK is older, it can lead to compilation errors.
|
||||
|
||||
Ubuntu 18.04 (Bionic Beaver)
|
||||
```
|
||||
ucodename=$(lsb_release -sc)
|
||||
wget -qO - http://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add -
|
||||
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-1.1.106-bionic.list http://packages.lunarg.com/vulkan/1.1.106/lunarg-vulkan-1.1.106-bionic.list
|
||||
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-1.1.126-$ucodename.list http://packages.lunarg.com/vulkan/1.1.126/lunarg-vulkan-1.1.126-$ucodename.list
|
||||
sudo apt update
|
||||
sudo apt install vulkan-sdk
|
||||
```
|
||||
|
||||
Ubuntu 16.04 (Xenial Xerus)
|
||||
##### CMake
|
||||
```
|
||||
wget -qO - http://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add -
|
||||
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-1.1.106-xenial.list http://packages.lunarg.com/vulkan/1.1.106/lunarg-vulkan-1.1.106-xenial.list
|
||||
sudo apt update
|
||||
sudo apt install vulkan-sdk
|
||||
wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | sudo apt-key add -
|
||||
sudo apt-add-repository "deb https://apt.kitware.com/ubuntu/ $(lsb_release -sc) main"
|
||||
sudo apt-get update
|
||||
sudo apt-get install kitware-archive-keyring
|
||||
sudo apt-key --keyring /etc/apt/trusted.gpg del C1F34CDD40CD72DA
|
||||
sudo apt-get install cmake
|
||||
|
||||
```
|
||||
|
||||
#### Fedora
|
||||
@@ -92,7 +103,7 @@ git submodule update --init
|
||||
#### Configuring the Qt plugin (if used)
|
||||
|
||||
1) Go to the Qt5 menu and edit Qt5 options.
|
||||
2) Add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\5.11.0\msvc2017_64`.
|
||||
2) Add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\5.14.1\msvc2017_64`.
|
||||
3) While selecting the rpcs3qt project, go to Qt5->Project Setting and select the version you added.
|
||||
|
||||
#### Building the projects
|
||||
@@ -110,7 +121,7 @@ If you're not using precompiled libs, build the projects in *__BUILD_BEFORE* fol
|
||||
While still in the project root:
|
||||
|
||||
1) `cd .. && mkdir rpcs3_build && cd rpcs3_build`
|
||||
2) `cmake ../rpcs3/ && make` or `CXX=g++-8 CC=gcc-8 cmake ../rpcs3/ && make` to force these compilers
|
||||
2) `cmake ../rpcs3/ && make` or `CXX=g++-9 CC=gcc-9 cmake ../rpcs3/ && make` to force these compilers
|
||||
3) Run RPCS3 with `./bin/rpcs3`
|
||||
|
||||
When using GDB, configure it to ignore SIGSEGV signal (`handle SIGSEGV nostop noprint`).
|
||||
|
||||
+7
-6
@@ -1,14 +1,14 @@
|
||||
cmake_minimum_required(VERSION 3.8.2)
|
||||
cmake_minimum_required(VERSION 3.14.1)
|
||||
|
||||
project(rpcs3)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8)
|
||||
message(FATAL_ERROR "RPCS3 requires at least gcc-8.")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9)
|
||||
message(FATAL_ERROR "RPCS3 requires at least gcc-9.")
|
||||
endif()
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
|
||||
message(FATAL_ERROR "RPCS3 requires at least clang-5.0.")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0)
|
||||
message(FATAL_ERROR "RPCS3 requires at least clang-9.0.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -22,10 +22,11 @@ option(USE_LIBEVDEV "libevdev-based joystick support" ON)
|
||||
option(USE_DISCORD_RPC "Discord rich presence integration" ON)
|
||||
option(USE_SYSTEM_ZLIB "Prefer system ZLIB instead of the builtin one" ON)
|
||||
option(USE_VULKAN "Vulkan render backend" ON)
|
||||
option(USE_COTIRE "Use precompiled headers" ON)
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/rpcs3/cmake_modules")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
+28
-20
@@ -4,6 +4,12 @@
|
||||
#include "util/endian.hpp"
|
||||
#include <cstring>
|
||||
|
||||
#if __has_include(<bit>)
|
||||
#include <bit>
|
||||
#else
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
// 128-bit vector type and also se_storage<> storage type
|
||||
union alignas(16) v128
|
||||
{
|
||||
@@ -26,12 +32,10 @@ union alignas(16) v128
|
||||
}
|
||||
};
|
||||
|
||||
#if IS_LE_MACHINE == 1
|
||||
template <typename T, std::size_t N = 16 / sizeof(T)>
|
||||
using normal_array_t = masked_array_t<T, N, 0>;
|
||||
using normal_array_t = masked_array_t<T, N, std::endian::little == std::endian::native ? 0 : N - 1>;
|
||||
template <typename T, std::size_t N = 16 / sizeof(T)>
|
||||
using reversed_array_t = masked_array_t<T, N, N - 1>;
|
||||
#endif
|
||||
using reversed_array_t = masked_array_t<T, N, std::endian::little == std::endian::native ? N - 1 : 0>;
|
||||
|
||||
normal_array_t<u64> _u64;
|
||||
normal_array_t<s64> _s64;
|
||||
@@ -114,17 +118,27 @@ union alignas(16) v128
|
||||
// Index 0 returns the MSB and index 127 returns the LSB
|
||||
bit_element operator[](u32 index)
|
||||
{
|
||||
#if IS_LE_MACHINE == 1
|
||||
return bit_element(m_data[1 - (index >> 6)], 0x8000000000000000ull >> (index & 0x3F));
|
||||
#endif
|
||||
if constexpr (std::endian::little == std::endian::native)
|
||||
{
|
||||
return bit_element(m_data[1 - (index >> 6)], 0x8000000000000000ull >> (index & 0x3F));
|
||||
}
|
||||
else
|
||||
{
|
||||
return bit_element(m_data[index >> 6], 0x8000000000000000ull >> (index & 0x3F));
|
||||
}
|
||||
}
|
||||
|
||||
// Index 0 returns the MSB and index 127 returns the LSB
|
||||
bool operator[](u32 index) const
|
||||
{
|
||||
#if IS_LE_MACHINE == 1
|
||||
return (m_data[1 - (index >> 6)] & (0x8000000000000000ull >> (index & 0x3F))) != 0;
|
||||
#endif
|
||||
if constexpr (std::endian::little == std::endian::native)
|
||||
{
|
||||
return (m_data[1 - (index >> 6)] & (0x8000000000000000ull >> (index & 0x3F))) != 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (m_data[index >> 6] & (0x8000000000000000ull >> (index & 0x3F))) != 0;
|
||||
}
|
||||
}
|
||||
} _bit;
|
||||
|
||||
@@ -340,12 +354,10 @@ using stx::se_storage;
|
||||
template <typename T, std::size_t Align = alignof(T)>
|
||||
using nse_t = se_t<T, false, Align>;
|
||||
|
||||
#if IS_LE_MACHINE == 1
|
||||
template <typename T, std::size_t Align = alignof(T)>
|
||||
using be_t = se_t<T, true, Align>;
|
||||
using be_t = se_t<T, std::endian::little == std::endian::native, Align>;
|
||||
template <typename T, std::size_t Align = alignof(T)>
|
||||
using le_t = se_t<T, false, Align>;
|
||||
#endif
|
||||
using le_t = se_t<T, std::endian::big == std::endian::native, Align>;
|
||||
|
||||
// Type converter: converts native endianness arithmetic/enum types to appropriate se_t<> type
|
||||
template <typename T, bool Se, typename = void>
|
||||
@@ -414,20 +426,16 @@ struct to_se<T[N], Se>
|
||||
};
|
||||
|
||||
// BE/LE aliases for to_se<>
|
||||
#if IS_LE_MACHINE == 1
|
||||
template <typename T>
|
||||
using to_be_t = typename to_se<T, true>::type;
|
||||
using to_be_t = typename to_se<T, std::endian::little == std::endian::native>::type;
|
||||
template <typename T>
|
||||
using to_le_t = typename to_se<T, false>::type;
|
||||
#endif
|
||||
using to_le_t = typename to_se<T, std::endian::big == std::endian::native>::type;
|
||||
|
||||
// BE/LE aliases for atomic_t
|
||||
#if IS_LE_MACHINE == 1
|
||||
template <typename T>
|
||||
using atomic_be_t = atomic_t<be_t<T>>;
|
||||
template <typename T>
|
||||
using atomic_le_t = atomic_t<le_t<T>>;
|
||||
#endif
|
||||
|
||||
template <typename T, bool Se, std::size_t Align>
|
||||
struct fmt_unveil<se_t<T, Se, Align>, void>
|
||||
|
||||
@@ -11,7 +11,7 @@ struct bf_base
|
||||
|
||||
// Datatype bitsize
|
||||
static constexpr uint bitmax = sizeof(T) * 8; static_assert(N - 1 < bitmax, "bf_base<> error: N out of bounds");
|
||||
|
||||
|
||||
// Field bitsize
|
||||
static constexpr uint bitsize = N;
|
||||
|
||||
@@ -96,7 +96,7 @@ struct bf_t : bf_base<T, N>
|
||||
// Optimized bool conversion (must be removed if inappropriate)
|
||||
explicit constexpr operator bool() const
|
||||
{
|
||||
return unshifted() != 0;
|
||||
return unshifted() != 0u;
|
||||
}
|
||||
|
||||
// Store bitfield value
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
#include "Config.h"
|
||||
|
||||
#include "yaml-cpp/yaml.h"
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <typeinfo>
|
||||
#include <charconv>
|
||||
|
||||
LOG_CHANNEL(cfg_log, "CFG");
|
||||
|
||||
namespace cfg
|
||||
{
|
||||
_base::_base(type _type)
|
||||
@@ -72,13 +74,13 @@ bool cfg::try_to_int64(s64* out, const std::string& value, s64 min, s64 max)
|
||||
|
||||
if (ret.ec != std::errc() || ret.ptr != end)
|
||||
{
|
||||
if (out) LOG_ERROR(GENERAL, "cfg::try_to_int('%s'): invalid integer", value);
|
||||
if (out) cfg_log.error("cfg::try_to_int('%s'): invalid integer", value);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result < min || result > max)
|
||||
{
|
||||
if (out) LOG_ERROR(GENERAL, "cfg::try_to_int('%s'): out of bounds (%lld..%lld)", value, min, max);
|
||||
if (out) cfg_log.error("cfg::try_to_int('%s'): out of bounds (%lld..%lld)", value, min, max);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -127,13 +129,13 @@ bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) f
|
||||
|
||||
if (ret.ec != std::errc() || ret.ptr != end)
|
||||
{
|
||||
if (out) LOG_ERROR(GENERAL, "cfg::try_to_enum_value('%s'): invalid enum or integer", value);
|
||||
if (out) cfg_log.error("cfg::try_to_enum_value('%s'): invalid enum or integer", value);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result > max)
|
||||
{
|
||||
if (out) LOG_ERROR(GENERAL, "cfg::try_to_enum_value('%s'): out of bounds(0..%u)", value, max);
|
||||
if (out) cfg_log.error("cfg::try_to_enum_value('%s'): out of bounds(0..%u)", value, max);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -307,7 +309,7 @@ bool cfg::node::from_string(const std::string& value, bool dynamic) try
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_FATAL(GENERAL, "%s thrown: %s", typeid(e).name(), e.what());
|
||||
cfg_log.fatal("%s thrown: %s", typeid(e).name(), e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -326,7 +328,7 @@ void cfg::_bool::from_default()
|
||||
|
||||
void cfg::string::from_default()
|
||||
{
|
||||
m_value = def;
|
||||
m_value = m_value.make(def);
|
||||
}
|
||||
|
||||
void cfg::set_entry::from_default()
|
||||
|
||||
+33
-25
@@ -3,6 +3,8 @@
|
||||
#include "Utilities/types.h"
|
||||
#include "Utilities/StrFmt.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "util/atomic.hpp"
|
||||
#include "util/shared_cptr.hpp"
|
||||
|
||||
#include <utility>
|
||||
#include <string>
|
||||
@@ -121,10 +123,10 @@ namespace cfg
|
||||
|
||||
class _bool final : public _base
|
||||
{
|
||||
bool m_value;
|
||||
atomic_t<bool> m_value;
|
||||
|
||||
public:
|
||||
bool def;
|
||||
const bool def;
|
||||
|
||||
_bool(node* owner, const std::string& name, bool def = false, bool dynamic = false)
|
||||
: _base(type::_bool, owner, name, dynamic)
|
||||
@@ -138,7 +140,7 @@ namespace cfg
|
||||
return m_value;
|
||||
}
|
||||
|
||||
const bool& get() const
|
||||
bool get() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
@@ -172,7 +174,7 @@ namespace cfg
|
||||
template <typename T>
|
||||
class _enum final : public _base
|
||||
{
|
||||
T m_value;
|
||||
atomic_t<T> m_value;
|
||||
|
||||
public:
|
||||
const T def;
|
||||
@@ -189,7 +191,7 @@ namespace cfg
|
||||
return m_value;
|
||||
}
|
||||
|
||||
const T& get() const
|
||||
T get() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
@@ -202,7 +204,7 @@ namespace cfg
|
||||
std::string to_string() const override
|
||||
{
|
||||
std::string result;
|
||||
fmt_class_string<T>::format(result, fmt_unveil<T>::get(m_value));
|
||||
fmt_class_string<T>::format(result, fmt_unveil<T>::get(m_value.load()));
|
||||
return result; // TODO: ???
|
||||
}
|
||||
|
||||
@@ -235,7 +237,7 @@ namespace cfg
|
||||
// Prefer 32 bit type if possible
|
||||
using int_type = std::conditional_t<Min >= INT32_MIN && Max <= INT32_MAX, s32, s64>;
|
||||
|
||||
int_type m_value;
|
||||
atomic_t<int_type> m_value;
|
||||
|
||||
public:
|
||||
int_type def;
|
||||
@@ -256,7 +258,7 @@ namespace cfg
|
||||
return m_value;
|
||||
}
|
||||
|
||||
const int_type& get() const
|
||||
int_type get() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
@@ -303,50 +305,56 @@ namespace cfg
|
||||
// Simple string entry with mutex
|
||||
class string final : public _base
|
||||
{
|
||||
std::string m_name;
|
||||
std::string m_value;
|
||||
const std::string m_name;
|
||||
|
||||
stx::atomic_cptr<std::string> m_value;
|
||||
|
||||
public:
|
||||
std::string def;
|
||||
|
||||
string(node* owner, const std::string& name, const std::string& def = {}, bool dynamic = false)
|
||||
string(node* owner, std::string name, std::string def = {}, bool dynamic = false)
|
||||
: _base(type::string, owner, name, dynamic)
|
||||
, m_name(name)
|
||||
, m_value(def)
|
||||
, def(def)
|
||||
, m_name(std::move(name))
|
||||
, m_value(m_value.make(def))
|
||||
, def(std::move(def))
|
||||
{
|
||||
}
|
||||
|
||||
operator std::string() const
|
||||
{
|
||||
return m_value;
|
||||
return *m_value.load().get();
|
||||
}
|
||||
|
||||
const std::string& get() const
|
||||
std::pair<const std::string&, stx::shared_cptr<std::string>> get() const
|
||||
{
|
||||
return m_value;
|
||||
auto v = m_value.load();
|
||||
|
||||
if (auto s = v.get())
|
||||
{
|
||||
return {*s, std::move(v)};
|
||||
}
|
||||
else
|
||||
{
|
||||
static const std::string _empty;
|
||||
return {_empty, {}};
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_name() const
|
||||
const std::string& get_name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
std::size_t size() const
|
||||
{
|
||||
return m_value.size();
|
||||
}
|
||||
|
||||
void from_default() override;
|
||||
|
||||
std::string to_string() const override
|
||||
{
|
||||
return m_value;
|
||||
return *m_value.load().get();
|
||||
}
|
||||
|
||||
bool from_string(const std::string& value, bool /*dynamic*/ = false) override
|
||||
{
|
||||
m_value = value;
|
||||
m_value = m_value.make(value);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
+19
-5
@@ -304,7 +304,7 @@ std::shared_ptr<fs::device_base> fs::device_manager::set_device(const std::strin
|
||||
std::shared_ptr<fs::device_base> fs::get_virtual_device(const std::string& path)
|
||||
{
|
||||
// Every virtual device path must have "//" at the beginning
|
||||
if (path.size() > 2 && reinterpret_cast<const u16&>(path.front()) == "//"_u16)
|
||||
if (path.starts_with("//"))
|
||||
{
|
||||
return get_device_manager().get_device(path);
|
||||
}
|
||||
@@ -314,7 +314,7 @@ std::shared_ptr<fs::device_base> fs::get_virtual_device(const std::string& path)
|
||||
|
||||
std::shared_ptr<fs::device_base> fs::set_virtual_device(const std::string& name, const std::shared_ptr<device_base>& device)
|
||||
{
|
||||
verify(HERE), name.size() > 2, name[0] == '/', name[1] == '/', name.find('/', 2) == -1;
|
||||
verify(HERE), name.starts_with("//"), name[2] != '/';
|
||||
|
||||
return get_device_manager().set_device(name, device);
|
||||
}
|
||||
@@ -338,7 +338,7 @@ std::string fs::get_parent_dir(const std::string& path)
|
||||
if (std::exchange(last, pos - 1) != pos)
|
||||
{
|
||||
// Return empty string if the path doesn't contain at least 2 elements
|
||||
return path.substr(0, pos != -1 && path.find_last_not_of(delim, pos, sizeof(delim) - 1) != -1 ? pos : 0);
|
||||
return path.substr(0, pos != umax && path.find_last_not_of(delim, pos, sizeof(delim) - 1) != umax ? pos : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1639,7 +1639,14 @@ u64 fs::get_dir_size(const std::string& path, u64 rounding_alignment)
|
||||
{
|
||||
u64 result = 0;
|
||||
|
||||
for (const auto entry : dir(path))
|
||||
const auto root_dir = dir(path);
|
||||
|
||||
if (!root_dir)
|
||||
{
|
||||
return static_cast<u64>(umax);
|
||||
}
|
||||
|
||||
for (const auto& entry : root_dir)
|
||||
{
|
||||
if (entry.name == "." || entry.name == "..")
|
||||
{
|
||||
@@ -1653,7 +1660,14 @@ u64 fs::get_dir_size(const std::string& path, u64 rounding_alignment)
|
||||
|
||||
if (entry.is_directory == true)
|
||||
{
|
||||
result += get_dir_size(path_append(path, entry.name), rounding_alignment);
|
||||
const u64 size = get_dir_size(path_append(path, entry.name), rounding_alignment);
|
||||
|
||||
if (size == umax)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
result += size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+38
-24
@@ -14,6 +14,8 @@
|
||||
#define CAN_OVERCOMMIT
|
||||
#endif
|
||||
|
||||
LOG_CHANNEL(jit_log, "JIT");
|
||||
|
||||
static u8* get_jit_memory()
|
||||
{
|
||||
// Reserve 2G memory (magic static)
|
||||
@@ -43,7 +45,7 @@ static u8* add_jit_memory(std::size_t size, uint align)
|
||||
// Select subrange
|
||||
u8* pointer = get_jit_memory() + Off;
|
||||
|
||||
if (UNLIKELY(!size && !align))
|
||||
if (!size && !align) [[unlikely]]
|
||||
{
|
||||
// Return subrange info
|
||||
return pointer;
|
||||
@@ -57,7 +59,7 @@ static u8* add_jit_memory(std::size_t size, uint align)
|
||||
const u64 _pos = ::align(ctr & 0xffff'ffff, align);
|
||||
const u64 _new = ::align(_pos + size, align);
|
||||
|
||||
if (UNLIKELY(_new > 0x40000000))
|
||||
if (_new > 0x40000000) [[unlikely]]
|
||||
{
|
||||
// Sorry, we failed, and further attempts should fail too.
|
||||
ctr |= 0x40000000;
|
||||
@@ -69,7 +71,7 @@ static u8* add_jit_memory(std::size_t size, uint align)
|
||||
newa = olda;
|
||||
|
||||
// Check the necessity to commit more memory
|
||||
if (UNLIKELY(_new > olda))
|
||||
if (_new > olda) [[unlikely]]
|
||||
{
|
||||
newa = ::align(_new, 0x100000);
|
||||
}
|
||||
@@ -78,13 +80,13 @@ static u8* add_jit_memory(std::size_t size, uint align)
|
||||
return _pos;
|
||||
});
|
||||
|
||||
if (UNLIKELY(pos == -1))
|
||||
if (pos == umax) [[unlikely]]
|
||||
{
|
||||
LOG_WARNING(GENERAL, "JIT: Out of memory (size=0x%x, align=0x%x, off=0x%x)", size, align, Off);
|
||||
jit_log.warning("JIT: Out of memory (size=0x%x, align=0x%x, off=0x%x)", size, align, Off);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (UNLIKELY(olda != newa))
|
||||
if (olda != newa) [[unlikely]]
|
||||
{
|
||||
#ifdef CAN_OVERCOMMIT
|
||||
madvise(pointer + olda, newa - olda, MADV_WILLNEED);
|
||||
@@ -117,21 +119,21 @@ jit_runtime::~jit_runtime()
|
||||
asmjit::Error jit_runtime::_add(void** dst, asmjit::CodeHolder* code) noexcept
|
||||
{
|
||||
std::size_t codeSize = code->getCodeSize();
|
||||
if (UNLIKELY(!codeSize))
|
||||
if (!codeSize) [[unlikely]]
|
||||
{
|
||||
*dst = nullptr;
|
||||
return asmjit::kErrorNoCodeGenerated;
|
||||
}
|
||||
|
||||
void* p = jit_runtime::alloc(codeSize, 16);
|
||||
if (UNLIKELY(!p))
|
||||
if (!p) [[unlikely]]
|
||||
{
|
||||
*dst = nullptr;
|
||||
return asmjit::kErrorNoVirtualMemory;
|
||||
}
|
||||
|
||||
std::size_t relocSize = code->relocate(p);
|
||||
if (UNLIKELY(!relocSize))
|
||||
if (!relocSize) [[unlikely]]
|
||||
{
|
||||
*dst = nullptr;
|
||||
return asmjit::kErrorInvalidState;
|
||||
@@ -431,7 +433,7 @@ public:
|
||||
|
||||
void reset()
|
||||
{
|
||||
if (!m_segs.size())
|
||||
if (m_segs.empty())
|
||||
{
|
||||
if (m_curr.addr != nullptr)
|
||||
{
|
||||
@@ -532,7 +534,7 @@ extern void jit_finalize()
|
||||
{
|
||||
if (!RtlDeleteFunctionTable(unwind.data()))
|
||||
{
|
||||
LOG_FATAL(GENERAL, "RtlDeleteFunctionTable() failed! Error %u", GetLastError());
|
||||
jit_log.fatal("RtlDeleteFunctionTable() failed! Error %u", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -579,11 +581,11 @@ struct MemoryManager : llvm::RTDyldMemoryManager
|
||||
|
||||
if (addr)
|
||||
{
|
||||
LOG_WARNING(GENERAL, "LLVM: Symbol requested: %s -> 0x%016llx", name, addr);
|
||||
jit_log.warning("LLVM: Symbol requested: %s -> 0x%016llx", name, addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(GENERAL, "LLVM: Linkage failed: %s", name);
|
||||
jit_log.error("LLVM: Linkage failed: %s", name);
|
||||
addr = reinterpret_cast<u64>(null);
|
||||
}
|
||||
}
|
||||
@@ -661,13 +663,13 @@ struct MemoryManager : llvm::RTDyldMemoryManager
|
||||
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
LOG_FATAL(GENERAL, "LLVM: Out of memory (size=0x%llx, aligned 0x%x)", size, align);
|
||||
jit_log.fatal("LLVM: Out of memory (size=0x%llx, aligned 0x%x)", size, align);
|
||||
return nullptr;
|
||||
}
|
||||
utils::memory_commit(ptr, size, utils::protection::wx);
|
||||
m_code_addr = static_cast<u8*>(ptr);
|
||||
|
||||
LOG_NOTICE(GENERAL, "LLVM: Code section %u '%s' allocated -> %p (size=0x%llx, aligned 0x%x)", sec_id, sec_name.data(), ptr, size, align);
|
||||
jit_log.notice("LLVM: Code section %u '%s' allocated -> %p (size=0x%llx, aligned 0x%x)", sec_id, sec_name.data(), ptr, size, align);
|
||||
return static_cast<u8*>(ptr);
|
||||
}
|
||||
|
||||
@@ -685,7 +687,7 @@ struct MemoryManager : llvm::RTDyldMemoryManager
|
||||
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
LOG_FATAL(GENERAL, "LLVM: Out of memory (size=0x%llx, aligned 0x%x)", size, align);
|
||||
jit_log.fatal("LLVM: Out of memory (size=0x%llx, aligned 0x%x)", size, align);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -695,7 +697,7 @@ struct MemoryManager : llvm::RTDyldMemoryManager
|
||||
|
||||
utils::memory_commit(ptr, size);
|
||||
|
||||
LOG_NOTICE(GENERAL, "LLVM: Data section %u '%s' allocated -> %p (size=0x%llx, aligned 0x%x, %s)", sec_id, sec_name.data(), ptr, size, align, is_ro ? "ro" : "rw");
|
||||
jit_log.notice("LLVM: Data section %u '%s' allocated -> %p (size=0x%llx, aligned 0x%x, %s)", sec_id, sec_name.data(), ptr, size, align, is_ro ? "ro" : "rw");
|
||||
return static_cast<u8*>(ptr);
|
||||
}
|
||||
|
||||
@@ -718,9 +720,9 @@ struct MemoryManager : llvm::RTDyldMemoryManager
|
||||
|
||||
void registerEHFrames(u8* addr, u64 load_addr, std::size_t size) override
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// Lock memory manager
|
||||
std::lock_guard lock(s_mutex);
|
||||
#ifdef _WIN32
|
||||
// Fix RUNTIME_FUNCTION records (.pdata section)
|
||||
decltype(s_unwater)::value_type pdata_entry = std::move(s_unwater.front());
|
||||
s_unwater.pop_front();
|
||||
@@ -738,7 +740,7 @@ struct MemoryManager : llvm::RTDyldMemoryManager
|
||||
// Register .xdata UNWIND_INFO structs
|
||||
if (!RtlAddFunctionTable(pdata.data(), (DWORD)pdata.size(), segment_start))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "RtlAddFunctionTable() failed! Error %u", GetLastError());
|
||||
jit_log.error("RtlAddFunctionTable() failed! Error %u", GetLastError());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -784,7 +786,11 @@ struct MemoryManager2 : llvm::RTDyldMemoryManager
|
||||
{
|
||||
#ifndef _WIN32
|
||||
RTDyldMemoryManager::registerEHFramesInProcess(addr, size);
|
||||
s_unfire.push_front(std::make_pair(addr, size));
|
||||
{
|
||||
// Lock memory manager
|
||||
std::lock_guard lock(s_mutex);
|
||||
s_unfire.push_front(std::make_pair(addr, size));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -919,10 +925,14 @@ public:
|
||||
z_stream zs{};
|
||||
uLong zsz = compressBound(obj.getBufferSize()) + 256;
|
||||
auto zbuf = std::make_unique<uchar[]>(zsz);
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
#endif
|
||||
deflateInit2(&zs, 9, Z_DEFLATED, 16 + 15, 9, Z_DEFAULT_STRATEGY);
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
zs.avail_in = static_cast<uInt>(obj.getBufferSize());
|
||||
zs.next_in = reinterpret_cast<uchar*>(const_cast<char*>(obj.getBufferStart()));
|
||||
zs.avail_out = static_cast<uInt>(zsz);
|
||||
@@ -938,14 +948,14 @@ public:
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOG_ERROR(GENERAL, "LLVM: Failed to compress module: %s", module->getName().data());
|
||||
jit_log.error("LLVM: Failed to compress module: %s", module->getName().data());
|
||||
deflateEnd(&zs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fs::file(name, fs::rewrite).write(zbuf.get(), zsz - zs.avail_out);
|
||||
LOG_NOTICE(GENERAL, "LLVM: Created module: %s", module->getName().data());
|
||||
jit_log.notice("LLVM: Created module: %s", module->getName().data());
|
||||
}
|
||||
|
||||
static std::unique_ptr<llvm::MemoryBuffer> load(const std::string& path)
|
||||
@@ -955,10 +965,14 @@ public:
|
||||
std::vector<uchar> gz = cached.to_vector<uchar>();
|
||||
std::vector<uchar> out;
|
||||
z_stream zs{};
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
#endif
|
||||
inflateInit2(&zs, 16 + 15);
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
zs.avail_in = static_cast<uInt>(gz.size());
|
||||
zs.next_in = gz.data();
|
||||
out.resize(gz.size() * 6);
|
||||
@@ -1016,7 +1030,7 @@ public:
|
||||
|
||||
if (auto buf = load(path))
|
||||
{
|
||||
LOG_NOTICE(GENERAL, "LLVM: Loaded module: %s", module->getName().data());
|
||||
jit_log.notice("LLVM: Loaded module: %s", module->getName().data());
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1182,7 +1196,7 @@ void jit_compiler::add(const std::string& path)
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(GENERAL, "ObjectCache: Adding failed: %s", path);
|
||||
jit_log.error("ObjectCache: Adding failed: %s", path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+104
-72
@@ -49,7 +49,6 @@ void fmt_class_string<logs::level>::format(std::string& out, u64 arg)
|
||||
case logs::level::warning: return "Warning";
|
||||
case logs::level::notice: return "Notice";
|
||||
case logs::level::trace: return "Trace";
|
||||
case logs::level::_uninit: return unknown;
|
||||
}
|
||||
|
||||
return unknown;
|
||||
@@ -94,22 +93,6 @@ namespace logs
|
||||
void log(logs::level sev, const char* text, std::size_t size);
|
||||
};
|
||||
|
||||
struct channel_info
|
||||
{
|
||||
channel* pointer = nullptr;
|
||||
level enabled = level::notice;
|
||||
|
||||
void set_level(level value)
|
||||
{
|
||||
enabled = value;
|
||||
|
||||
if (pointer)
|
||||
{
|
||||
pointer->enabled = value;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct stored_message
|
||||
{
|
||||
message m;
|
||||
@@ -128,7 +111,7 @@ namespace logs
|
||||
virtual void log(u64 stamp, const message& msg, const std::string& prefix, const std::string& text) override;
|
||||
|
||||
// Channel registry
|
||||
std::unordered_map<std::string, channel_info> channels;
|
||||
std::unordered_multimap<std::string, channel*> channels;
|
||||
|
||||
// Messages for delayed listener initialization
|
||||
std::vector<stored_message> messages;
|
||||
@@ -174,19 +157,11 @@ namespace logs
|
||||
return timebase.get();
|
||||
}
|
||||
|
||||
channel GENERAL("");
|
||||
channel LOADER("LDR");
|
||||
channel MEMORY("MEM");
|
||||
channel RSX("RSX");
|
||||
channel HLE("HLE");
|
||||
channel PPU("PPU");
|
||||
channel SPU("SPU");
|
||||
|
||||
// Channel registry mutex
|
||||
shared_mutex g_mutex;
|
||||
static shared_mutex g_mutex;
|
||||
|
||||
// Must be set to true in main()
|
||||
atomic_t<bool> g_init{false};
|
||||
static atomic_t<bool> g_init{false};
|
||||
|
||||
void reset()
|
||||
{
|
||||
@@ -194,7 +169,17 @@ namespace logs
|
||||
|
||||
for (auto&& pair : get_logger()->channels)
|
||||
{
|
||||
pair.second.set_level(level::notice);
|
||||
pair.second->enabled.store(level::notice, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
void silence()
|
||||
{
|
||||
std::lock_guard lock(g_mutex);
|
||||
|
||||
for (auto&& pair : get_logger()->channels)
|
||||
{
|
||||
pair.second->enabled.store(level::always, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +187,47 @@ namespace logs
|
||||
{
|
||||
std::lock_guard lock(g_mutex);
|
||||
|
||||
get_logger()->channels[ch_name].set_level(value);
|
||||
auto found = get_logger()->channels.equal_range(ch_name);
|
||||
|
||||
while (found.first != found.second)
|
||||
{
|
||||
found.first->second->enabled.store(value, std::memory_order_relaxed);
|
||||
found.first++;
|
||||
}
|
||||
}
|
||||
|
||||
level get_level(const std::string& ch_name)
|
||||
{
|
||||
std::lock_guard lock(g_mutex);
|
||||
|
||||
auto found = get_logger()->channels.equal_range(ch_name);
|
||||
|
||||
if (found.first != found.second)
|
||||
{
|
||||
return found.first->second->enabled.load(std::memory_order_relaxed);
|
||||
}
|
||||
else
|
||||
{
|
||||
return level::always;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> get_channels()
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
||||
std::lock_guard lock(g_mutex);
|
||||
|
||||
for (auto&& p : get_logger()->channels)
|
||||
{
|
||||
// Copy names removing duplicates
|
||||
if (result.empty() || result.back() != p.first)
|
||||
{
|
||||
result.push_back(p.first);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Must be called in main() to stop accumulating messages in g_messages
|
||||
@@ -211,6 +236,7 @@ namespace logs
|
||||
if (!g_init)
|
||||
{
|
||||
std::lock_guard lock(g_mutex);
|
||||
printf("DEBUG: %zu log messages accumulated. %zu channels registered.\n", get_logger()->messages.size(), get_logger()->channels.size());
|
||||
get_logger()->messages.clear();
|
||||
g_init = true;
|
||||
}
|
||||
@@ -219,6 +245,19 @@ namespace logs
|
||||
|
||||
logs::listener::~listener()
|
||||
{
|
||||
// Shut up all channels on exit
|
||||
if (auto logger = get_logger())
|
||||
{
|
||||
if (logger == this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto&& pair : logger->channels)
|
||||
{
|
||||
pair.second->enabled.store(level::always, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void logs::listener::add(logs::listener* _new)
|
||||
@@ -241,35 +280,18 @@ void logs::listener::add(logs::listener* _new)
|
||||
}
|
||||
}
|
||||
|
||||
logs::registerer::registerer(channel& _ch)
|
||||
{
|
||||
std::lock_guard lock(g_mutex);
|
||||
|
||||
get_logger()->channels.emplace(_ch.name, &_ch);
|
||||
}
|
||||
|
||||
void logs::message::broadcast(const char* fmt, const fmt_type_info* sup, ...) const
|
||||
{
|
||||
// Get timestamp
|
||||
const u64 stamp = get_stamp();
|
||||
|
||||
// Register channel
|
||||
if (ch->enabled == level::_uninit)
|
||||
{
|
||||
std::lock_guard lock(g_mutex);
|
||||
|
||||
auto& info = get_logger()->channels[ch->name];
|
||||
|
||||
if (info.pointer && info.pointer != ch)
|
||||
{
|
||||
fmt::throw_exception("logs::channel repetition: %s", ch->name);
|
||||
}
|
||||
else if (!info.pointer)
|
||||
{
|
||||
info.pointer = ch;
|
||||
ch->enabled = info.enabled;
|
||||
|
||||
// Check level again
|
||||
if (info.enabled < sev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get text, extract va_args
|
||||
thread_local std::string text;
|
||||
thread_local std::vector<u64> args;
|
||||
@@ -400,17 +422,28 @@ logs::file_writer::file_writer(const std::string& name)
|
||||
verify(name.c_str()), m_fptr;
|
||||
|
||||
// Rotate backups (TODO)
|
||||
fs::remove_file(fs::get_cache_dir() + name + "1.log.gz");
|
||||
fs::create_dir(fs::get_cache_dir() + "old_logs");
|
||||
fs::rename(fs::get_cache_dir() + m_name + ".log.gz", fs::get_cache_dir() + "old_logs/" + m_name + ".log.gz", true);
|
||||
if (std::string gz_file_name = fs::get_cache_dir() + m_name + ".log.gz"; fs::is_file(gz_file_name))
|
||||
{
|
||||
fs::remove_file(fs::get_cache_dir() + name + "1.log.gz");
|
||||
fs::create_dir(fs::get_cache_dir() + "old_logs");
|
||||
fs::rename(gz_file_name, fs::get_cache_dir() + "old_logs/" + m_name + ".log.gz", true);
|
||||
}
|
||||
|
||||
// Actual log file (allowed to fail)
|
||||
m_fout.open(log_name, fs::rewrite);
|
||||
|
||||
// Compressed log, make it inaccessible (foolproof)
|
||||
if (!m_fout2.open(log_name + ".gz", fs::rewrite + fs::unread) || deflateInit2(&m_zs, 9, Z_DEFLATED, 16 + 15, 9, Z_DEFAULT_STRATEGY) != Z_OK)
|
||||
if (m_fout2.open(log_name + ".gz", fs::rewrite + fs::unread))
|
||||
{
|
||||
m_fout2.close();
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
#endif
|
||||
if (deflateInit2(&m_zs, 9, Z_DEFLATED, 16 + 15, 9, Z_DEFAULT_STRATEGY) != Z_OK)
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
m_fout2.close();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -448,7 +481,7 @@ logs::file_writer::file_writer(const std::string& name)
|
||||
|
||||
if (!flush(bufv))
|
||||
{
|
||||
if (m_out == -1)
|
||||
if (m_out == umax)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -573,7 +606,7 @@ void logs::file_writer::log(logs::level sev, const char* text, std::size_t size)
|
||||
const u64 v1 = v >> 24;
|
||||
const u64 v2 = v & 0xffffff;
|
||||
|
||||
if (UNLIKELY(v2 + size > 0xffffff || v1 + v2 + size >= m_out + s_log_size))
|
||||
if (v2 + size > 0xffffff || v1 + v2 + size >= m_out + s_log_size) [[unlikely]]
|
||||
{
|
||||
bufv = v;
|
||||
return nullptr;
|
||||
@@ -583,7 +616,7 @@ void logs::file_writer::log(logs::level sev, const char* text, std::size_t size)
|
||||
return m_fptr + (v1 + v2) % s_log_size;
|
||||
});
|
||||
|
||||
if (UNLIKELY(!pos))
|
||||
if (!pos) [[unlikely]]
|
||||
{
|
||||
if ((bufv & 0xffffff) + size > 0xffffff || bufv & 0xffffff)
|
||||
{
|
||||
@@ -629,7 +662,7 @@ logs::file_listener::file_listener(const std::string& name)
|
||||
ver.m.ch = nullptr;
|
||||
ver.m.sev = level::always;
|
||||
ver.stamp = 0;
|
||||
ver.text = fmt::format("RPCS3 v%s | %s%s\n%s", rpcs3::version.to_string(), rpcs3::get_branch(), firmware_string, utils::get_system_info());
|
||||
ver.text = fmt::format("RPCS3 v%s | %s%s\n%s", rpcs3::get_version().to_string(), rpcs3::get_branch(), firmware_string, utils::get_system_info());
|
||||
|
||||
file_writer::log(logs::level::always, ver.text.data(), ver.text.size());
|
||||
file_writer::log(logs::level::always, "\n", 1);
|
||||
@@ -654,15 +687,14 @@ void logs::file_listener::log(u64 stamp, const logs::message& msg, const std::st
|
||||
// Used character: U+00B7 (Middle Dot)
|
||||
switch (msg.sev)
|
||||
{
|
||||
case level::always: text = u8"·A "; break;
|
||||
case level::fatal: text = u8"·F "; break;
|
||||
case level::error: text = u8"·E "; break;
|
||||
case level::todo: text = u8"·U "; break;
|
||||
case level::success: text = u8"·S "; break;
|
||||
case level::warning: text = u8"·W "; break;
|
||||
case level::notice: text = u8"·! "; break;
|
||||
case level::trace: text = u8"·T "; break;
|
||||
case level::_uninit: text = u8"· "; break;
|
||||
case level::always: text = reinterpret_cast<const char*>(u8"·A "); break;
|
||||
case level::fatal: text = reinterpret_cast<const char*>(u8"·F "); break;
|
||||
case level::error: text = reinterpret_cast<const char*>(u8"·E "); break;
|
||||
case level::todo: text = reinterpret_cast<const char*>(u8"·U "); break;
|
||||
case level::success: text = reinterpret_cast<const char*>(u8"·S "); break;
|
||||
case level::warning: text = reinterpret_cast<const char*>(u8"·W "); break;
|
||||
case level::notice: text = reinterpret_cast<const char*>(u8"·! "); break;
|
||||
case level::trace: text = reinterpret_cast<const char*>(u8"·T "); break;
|
||||
}
|
||||
|
||||
// Print µs timestamp
|
||||
|
||||
+58
-28
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "util/atomic.hpp"
|
||||
#include "StrFmt.h"
|
||||
#include <climits>
|
||||
#include "util/atomic.hpp"
|
||||
#include <atomic>
|
||||
|
||||
namespace logs
|
||||
{
|
||||
@@ -17,8 +17,6 @@ namespace logs
|
||||
warning,
|
||||
notice,
|
||||
trace, // Lowest severity (usually disabled)
|
||||
|
||||
_uninit = UINT_MAX, // Special value for delayed initialization
|
||||
};
|
||||
|
||||
struct channel;
|
||||
@@ -61,27 +59,44 @@ namespace logs
|
||||
const char* const name;
|
||||
|
||||
// The lowest logging level enabled for this channel (used for early filtering)
|
||||
atomic_t<level> enabled;
|
||||
std::atomic<level> enabled;
|
||||
|
||||
// Constant initialization: channel name
|
||||
constexpr channel(const char* name)
|
||||
// Initialize channel
|
||||
constexpr channel(const char* name) noexcept
|
||||
: name(name)
|
||||
, enabled(level::_uninit)
|
||||
, enabled(level::notice)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
#if __cpp_char8_t >= 201811
|
||||
using char2 = char8_t;
|
||||
#else
|
||||
using char2 = uchar;
|
||||
#endif
|
||||
|
||||
#define GEN_LOG_METHOD(_sev)\
|
||||
const message msg_##_sev{this, level::_sev};\
|
||||
template <std::size_t N, typename... Args>\
|
||||
void _sev(const char(&fmt)[N], const Args&... args)\
|
||||
{\
|
||||
if (UNLIKELY(level::_sev <= enabled))\
|
||||
if (level::_sev <= enabled.load(std::memory_order_relaxed)) [[unlikely]]\
|
||||
{\
|
||||
static constexpr fmt_type_info type_list[sizeof...(Args) + 1]{fmt_type_info::make<fmt_unveil_t<Args>>()...};\
|
||||
msg_##_sev.broadcast(fmt, type_list, u64{fmt_unveil<Args>::get(args)}...);\
|
||||
}\
|
||||
}
|
||||
}\
|
||||
template <std::size_t N, typename... Args>\
|
||||
void _sev(const char2(&fmt)[N], const Args&... args)\
|
||||
{\
|
||||
if (level::_sev <= enabled.load(std::memory_order_relaxed)) [[unlikely]]\
|
||||
{\
|
||||
static constexpr fmt_type_info type_list[sizeof...(Args) + 1]{fmt_type_info::make<fmt_unveil_t<Args>>()...};\
|
||||
msg_##_sev.broadcast(reinterpret_cast<const char*>(+fmt), type_list, u64{fmt_unveil<Args>::get(args)}...);\
|
||||
}\
|
||||
}\
|
||||
|
||||
public:
|
||||
GEN_LOG_METHOD(fatal)
|
||||
GEN_LOG_METHOD(error)
|
||||
GEN_LOG_METHOD(todo)
|
||||
@@ -93,31 +108,46 @@ namespace logs
|
||||
#undef GEN_LOG_METHOD
|
||||
};
|
||||
|
||||
/* Small set of predefined channels */
|
||||
|
||||
extern channel GENERAL;
|
||||
extern channel LOADER;
|
||||
extern channel MEMORY;
|
||||
extern channel RSX;
|
||||
extern channel HLE;
|
||||
extern channel PPU;
|
||||
extern channel SPU;
|
||||
struct registerer
|
||||
{
|
||||
registerer(channel& _ch);
|
||||
};
|
||||
|
||||
// Log level control: set all channels to level::notice
|
||||
void reset();
|
||||
|
||||
// Log level control: set all channels to level::always
|
||||
void silence();
|
||||
|
||||
// Log level control: register channel if necessary, set channel level
|
||||
void set_level(const std::string&, level);
|
||||
|
||||
// Log level control: get channel level
|
||||
level get_level(const std::string&);
|
||||
|
||||
// Get all registered log channels
|
||||
std::vector<std::string> get_channels();
|
||||
|
||||
// Helper: no additional name specified
|
||||
constexpr const char* make_channel_name(const char* name)
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
// Helper: special channel name specified
|
||||
constexpr const char* make_channel_name(const char*, const char* name, ...)
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
#define LOG_CHANNEL(ch, ...) ::logs::channel ch(#ch, ##__VA_ARGS__)
|
||||
#if __cpp_constinit >= 201907
|
||||
#define LOG_CONSTINIT constinit
|
||||
#else
|
||||
#define LOG_CONSTINIT
|
||||
#endif
|
||||
|
||||
// Legacy:
|
||||
#define LOG_CHANNEL(ch, ...) LOG_CONSTINIT inline ::logs::channel ch(::logs::make_channel_name(#ch, ##__VA_ARGS__)); \
|
||||
namespace logs { inline ::logs::registerer reg_##ch{ch}; }
|
||||
|
||||
#define LOG_SUCCESS(ch, fmt, ...) logs::ch.success("" fmt, ##__VA_ARGS__)
|
||||
#define LOG_NOTICE(ch, fmt, ...) logs::ch.notice ("" fmt, ##__VA_ARGS__)
|
||||
#define LOG_WARNING(ch, fmt, ...) logs::ch.warning("" fmt, ##__VA_ARGS__)
|
||||
#define LOG_ERROR(ch, fmt, ...) logs::ch.error ("" fmt, ##__VA_ARGS__)
|
||||
#define LOG_TODO(ch, fmt, ...) logs::ch.todo ("" fmt, ##__VA_ARGS__)
|
||||
#define LOG_TRACE(ch, fmt, ...) logs::ch.trace ("" fmt, ##__VA_ARGS__)
|
||||
#define LOG_FATAL(ch, fmt, ...) logs::ch.fatal ("" fmt, ##__VA_ARGS__)
|
||||
LOG_CHANNEL(rsx_log, "RSX");
|
||||
|
||||
+8
-8
@@ -8,8 +8,8 @@
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
template <typename... Args>
|
||||
static std::string format(const char*, const Args&...);
|
||||
template <typename CharT, std::size_t N, typename... Args>
|
||||
static std::string format(const CharT(&)[N], const Args&...);
|
||||
}
|
||||
|
||||
template <typename T, typename>
|
||||
@@ -274,19 +274,19 @@ namespace fmt
|
||||
void raw_append(std::string& out, const char*, const fmt_type_info*, const u64*) noexcept;
|
||||
|
||||
// Formatting function
|
||||
template <typename... Args>
|
||||
SAFE_BUFFERS FORCE_INLINE void append(std::string& out, const char* fmt, const Args&... args)
|
||||
template <typename CharT, std::size_t N, typename... Args>
|
||||
SAFE_BUFFERS FORCE_INLINE void append(std::string& out, const CharT(&fmt)[N], const Args&... args)
|
||||
{
|
||||
static constexpr fmt_type_info type_list[sizeof...(Args) + 1]{fmt_type_info::make<fmt_unveil_t<Args>>()...};
|
||||
raw_append(out, fmt, type_list, fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
|
||||
raw_append(out, reinterpret_cast<const char*>(fmt), type_list, fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
|
||||
}
|
||||
|
||||
// Formatting function
|
||||
template <typename... Args>
|
||||
SAFE_BUFFERS FORCE_INLINE std::string format(const char* fmt, const Args&... args)
|
||||
template <typename CharT, std::size_t N, typename... Args>
|
||||
SAFE_BUFFERS FORCE_INLINE std::string format(const CharT(&fmt)[N], const Args&... args)
|
||||
{
|
||||
std::string result;
|
||||
append<Args...>(result, fmt, args...);
|
||||
append(result, fmt, args...);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,12 +25,6 @@ inline void strcpy_trunc(char (&dst)[N], const char (&src)[N2])
|
||||
std::memset(dst + count, 0, N - count);
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
inline bool ends_with(const std::string& src, const char (&end)[N])
|
||||
{
|
||||
return src.size() >= N - 1 && src.compare(src.size() - (N - 1), N - 1, end, N - 1) == 0;
|
||||
}
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
std::string replace_first(const std::string& src, const std::string& from, const std::string& to);
|
||||
|
||||
+217
-99
@@ -1,7 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/Memory/vm.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/Cell/SPUThread.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "Emu/Cell/RawSPUThread.h"
|
||||
@@ -11,6 +8,7 @@
|
||||
#include "sysinfo.h"
|
||||
#include <typeinfo>
|
||||
#include <thread>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
@@ -45,11 +43,23 @@
|
||||
#include "sync.h"
|
||||
#include "Log.h"
|
||||
|
||||
LOG_CHANNEL(sig_log);
|
||||
LOG_CHANNEL(sys_log, "SYS");
|
||||
LOG_CHANNEL(vm_log, "VM");
|
||||
|
||||
thread_local u64 g_tls_fault_all = 0;
|
||||
thread_local u64 g_tls_fault_rsx = 0;
|
||||
thread_local u64 g_tls_fault_spu = 0;
|
||||
extern thread_local std::string(*g_tls_log_prefix)();
|
||||
|
||||
template <>
|
||||
void fmt_class_string<std::thread::id>::format(std::string& out, u64 arg)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << get_object(arg);
|
||||
out += ss.str();
|
||||
}
|
||||
|
||||
[[noreturn]] void catch_all_exceptions()
|
||||
{
|
||||
try
|
||||
@@ -185,7 +195,7 @@ void decode_x64_reg_op(const u8* code, x64_op_t& out_op, x64_reg_t& out_reg, siz
|
||||
{
|
||||
if (lock)
|
||||
{
|
||||
LOG_ERROR(MEMORY, "decode_x64_reg_op(%016llxh): LOCK prefix found twice", code - out_length);
|
||||
sig_log.error("decode_x64_reg_op(%016llxh): LOCK prefix found twice", code - out_length);
|
||||
}
|
||||
|
||||
lock = true;
|
||||
@@ -195,7 +205,7 @@ void decode_x64_reg_op(const u8* code, x64_op_t& out_op, x64_reg_t& out_reg, siz
|
||||
{
|
||||
if (repne)
|
||||
{
|
||||
LOG_ERROR(MEMORY, "decode_x64_reg_op(%016llxh): REPNE/REPNZ prefix found twice", code - out_length);
|
||||
sig_log.error("decode_x64_reg_op(%016llxh): REPNE/REPNZ prefix found twice", code - out_length);
|
||||
}
|
||||
|
||||
repne = true;
|
||||
@@ -205,7 +215,7 @@ void decode_x64_reg_op(const u8* code, x64_op_t& out_op, x64_reg_t& out_reg, siz
|
||||
{
|
||||
if (repe)
|
||||
{
|
||||
LOG_ERROR(MEMORY, "decode_x64_reg_op(%016llxh): REP/REPE/REPZ prefix found twice", code - out_length);
|
||||
sig_log.error("decode_x64_reg_op(%016llxh): REP/REPE/REPZ prefix found twice", code - out_length);
|
||||
}
|
||||
|
||||
repe = true;
|
||||
@@ -221,7 +231,7 @@ void decode_x64_reg_op(const u8* code, x64_op_t& out_op, x64_reg_t& out_reg, siz
|
||||
{
|
||||
if (pg2)
|
||||
{
|
||||
LOG_ERROR(MEMORY, "decode_x64_reg_op(%016llxh): 0x%02x (group 2 prefix) found after 0x%02x", code - out_length, prefix, pg2);
|
||||
sig_log.error("decode_x64_reg_op(%016llxh): 0x%02x (group 2 prefix) found after 0x%02x", code - out_length, prefix, pg2);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -234,7 +244,7 @@ void decode_x64_reg_op(const u8* code, x64_op_t& out_op, x64_reg_t& out_reg, siz
|
||||
{
|
||||
if (oso)
|
||||
{
|
||||
LOG_ERROR(MEMORY, "decode_x64_reg_op(%016llxh): operand-size override prefix found twice", code - out_length);
|
||||
sig_log.error("decode_x64_reg_op(%016llxh): operand-size override prefix found twice", code - out_length);
|
||||
}
|
||||
|
||||
oso = true;
|
||||
@@ -243,7 +253,7 @@ void decode_x64_reg_op(const u8* code, x64_op_t& out_op, x64_reg_t& out_reg, siz
|
||||
|
||||
case 0x67: // group 4
|
||||
{
|
||||
LOG_ERROR(MEMORY, "decode_x64_reg_op(%016llxh): address-size override prefix found", code - out_length, prefix);
|
||||
sig_log.error("decode_x64_reg_op(%016llxh): address-size override prefix found", code - out_length, prefix);
|
||||
out_op = X64OP_NONE;
|
||||
out_reg = X64_NOT_SET;
|
||||
out_size = 0;
|
||||
@@ -257,7 +267,7 @@ void decode_x64_reg_op(const u8* code, x64_op_t& out_op, x64_reg_t& out_reg, siz
|
||||
{
|
||||
if (rex)
|
||||
{
|
||||
LOG_ERROR(MEMORY, "decode_x64_reg_op(%016llxh): 0x%02x (REX prefix) found after 0x%02x", code - out_length, prefix, rex);
|
||||
sig_log.error("decode_x64_reg_op(%016llxh): 0x%02x (REX prefix) found after 0x%02x", code - out_length, prefix, rex);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -757,7 +767,7 @@ uint64_t* darwin_x64reg(x64_context *context, int reg)
|
||||
case 15: return &state->__r15;
|
||||
case 16: return &state->__rip;
|
||||
default:
|
||||
LOG_ERROR(GENERAL, "Invalid register index: %d", reg);
|
||||
sig_log.error("Invalid register index: %d", reg);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -795,7 +805,7 @@ register_t* freebsd_x64reg(x64_context *context, int reg)
|
||||
case 15: return &state->mc_r15;
|
||||
case 16: return &state->mc_rip;
|
||||
default:
|
||||
LOG_ERROR(GENERAL, "Invalid register index: %d", reg);
|
||||
sig_log.error("Invalid register index: %d", reg);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -829,7 +839,7 @@ long* openbsd_x64reg(x64_context *context, int reg)
|
||||
case 15: return &state->sc_r15;
|
||||
case 16: return &state->sc_rip;
|
||||
default:
|
||||
LOG_ERROR(GENERAL, "Invalid register index: %d", reg);
|
||||
sig_log.error("Invalid register index: %d", reg);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -964,7 +974,7 @@ bool get_x64_reg_value(x64_context* context, x64_reg_t reg, size_t d_size, size_
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG_ERROR(MEMORY, "get_x64_reg_value(): invalid arguments (reg=%d, d_size=%lld, i_size=%lld)", +reg, d_size, i_size);
|
||||
sig_log.error("get_x64_reg_value(): invalid arguments (reg=%d, d_size=%lld, i_size=%lld)", +reg, d_size, i_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -983,7 +993,7 @@ bool put_x64_reg_value(x64_context* context, x64_reg_t reg, size_t d_size, u64 v
|
||||
}
|
||||
}
|
||||
|
||||
LOG_ERROR(MEMORY, "put_x64_reg_value(): invalid destination (reg=%d, d_size=%lld, value=0x%llx)", +reg, d_size, value);
|
||||
sig_log.error("put_x64_reg_value(): invalid destination (reg=%d, d_size=%lld, value=0x%llx)", +reg, d_size, value);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -995,7 +1005,7 @@ bool set_x64_cmp_flags(x64_context* context, size_t d_size, u64 x, u64 y, bool c
|
||||
case 2: break;
|
||||
case 4: break;
|
||||
case 8: break;
|
||||
default: LOG_ERROR(MEMORY, "set_x64_cmp_flags(): invalid d_size (%lld)", d_size); return false;
|
||||
default: sig_log.error("set_x64_cmp_flags(): invalid d_size (%lld)", d_size); return false;
|
||||
}
|
||||
|
||||
const u64 sign = 1ull << (d_size * 8 - 1); // sign mask
|
||||
@@ -1093,7 +1103,7 @@ namespace rsx
|
||||
extern std::function<bool(u32 addr, bool is_writing)> g_access_violation_handler;
|
||||
}
|
||||
|
||||
bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) noexcept
|
||||
{
|
||||
g_tls_fault_all++;
|
||||
|
||||
@@ -1114,7 +1124,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_FATAL(RSX, "g_access_violation_handler(0x%x, %d): %s", addr, is_writing, e.what());
|
||||
rsx_log.fatal("g_access_violation_handler(0x%x, %d): %s", addr, is_writing, e.what());
|
||||
|
||||
if (cpu)
|
||||
{
|
||||
@@ -1159,13 +1169,13 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
{
|
||||
if (op == X64OP_NONE)
|
||||
{
|
||||
LOG_ERROR(MEMORY, "decode_x64_reg_op(%p): unsupported opcode: %s", code, *reinterpret_cast<const be_t<v128, 1>*>(code));
|
||||
sig_log.error("decode_x64_reg_op(%p): unsupported opcode: %s", code, *reinterpret_cast<const be_t<v128, 1>*>(code));
|
||||
}
|
||||
};
|
||||
|
||||
if ((d_size | (d_size + addr)) >= 0x100000000ull)
|
||||
{
|
||||
LOG_ERROR(MEMORY, "Invalid d_size (0x%llx)", d_size);
|
||||
sig_log.error("Invalid d_size (0x%llx)", d_size);
|
||||
report_opcode();
|
||||
return false;
|
||||
}
|
||||
@@ -1175,7 +1185,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
|
||||
if ((a_size | (a_size + addr)) >= 0x100000000ull)
|
||||
{
|
||||
LOG_ERROR(MEMORY, "Invalid a_size (0x%llx)", a_size);
|
||||
sig_log.error("Invalid a_size (0x%llx)", a_size);
|
||||
report_opcode();
|
||||
return false;
|
||||
}
|
||||
@@ -1192,7 +1202,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
|
||||
if (a_size != 4 || !d_size || !i_size)
|
||||
{
|
||||
LOG_ERROR(MEMORY, "Invalid or unsupported instruction (op=%d, reg=%d, d_size=%lld, a_size=0x%llx, i_size=%lld)", +op, +reg, d_size, a_size, i_size);
|
||||
sig_log.error("Invalid or unsupported instruction (op=%d, reg=%d, d_size=%lld, a_size=0x%llx, i_size=%lld)", +op, +reg, d_size, a_size, i_size);
|
||||
report_opcode();
|
||||
return false;
|
||||
}
|
||||
@@ -1265,7 +1275,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
case X64OP_STOS:
|
||||
default:
|
||||
{
|
||||
LOG_ERROR(MEMORY, "Invalid or unsupported operation (op=%d, reg=%d, d_size=%lld, i_size=%lld)", +op, +reg, d_size, i_size);
|
||||
sig_log.error("Invalid or unsupported operation (op=%d, reg=%d, d_size=%lld, i_size=%lld)", +op, +reg, d_size, i_size);
|
||||
report_opcode();
|
||||
return false;
|
||||
}
|
||||
@@ -1287,6 +1297,32 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
return true;
|
||||
}
|
||||
|
||||
thread_local bool access_violation_recovered = false;
|
||||
|
||||
// Hack: allocate memory in case the emulator is stopping
|
||||
const auto hack_alloc = [&]()
|
||||
{
|
||||
// If failed the value remains true and std::terminate should be called
|
||||
access_violation_recovered = true;
|
||||
|
||||
const auto area = vm::reserve_map(vm::any, addr & -0x10000, 0x10000);
|
||||
|
||||
if (!area)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (area->flags & 0x100 || (is_writing && vm::check_addr(addr, std::max(1u, ::narrow<u32>(d_size)))))
|
||||
{
|
||||
// For 4kb pages or read only memory
|
||||
utils::memory_protect(vm::base(addr & -0x1000), 0x1000, utils::protection::rw);
|
||||
return true;
|
||||
}
|
||||
|
||||
area->falloc(addr & -0x10000, 0x10000);
|
||||
return vm::check_addr(addr, std::max(1u, ::narrow<u32>(d_size)), is_writing ? vm::page_writable : vm::page_readable);
|
||||
};
|
||||
|
||||
if (cpu)
|
||||
{
|
||||
u32 pf_port_id = 0;
|
||||
@@ -1357,13 +1393,13 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
pf_events->events.emplace(static_cast<u32>(data2), addr);
|
||||
}
|
||||
|
||||
LOG_ERROR(MEMORY, "Page_fault %s location 0x%x because of %s memory", is_writing ? "writing" : "reading",
|
||||
sig_log.error("Page_fault %s location 0x%x because of %s memory", is_writing ? "writing" : "reading",
|
||||
addr, data3 == SYS_MEMORY_PAGE_FAULT_CAUSE_READ_ONLY ? "writing read-only" : "using unmapped");
|
||||
|
||||
error_code sending_error = sys_event_port_send(pf_port_id, data1, data2, data3);
|
||||
|
||||
// If we fail due to being busy, wait a bit and try again.
|
||||
while (sending_error == CELL_EBUSY)
|
||||
while (static_cast<u32>(sending_error) == CELL_EBUSY)
|
||||
{
|
||||
if (cpu->id_type() == 1)
|
||||
{
|
||||
@@ -1374,22 +1410,23 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
sending_error = sys_event_port_send(pf_port_id, data1, data2, data3);
|
||||
}
|
||||
|
||||
if (sending_error)
|
||||
{
|
||||
fmt::throw_exception("Unknown error %x while trying to pass page fault.", sending_error.value);
|
||||
}
|
||||
|
||||
if (cpu->id_type() == 1)
|
||||
{
|
||||
// Deschedule
|
||||
lv2_obj::sleep(*cpu);
|
||||
}
|
||||
|
||||
if (sending_error)
|
||||
{
|
||||
vm_log.fatal("Unknown error %x while trying to pass page fault.", +sending_error);
|
||||
cpu->state += cpu_flag::dbg_pause;
|
||||
}
|
||||
|
||||
// Wait until the thread is recovered
|
||||
for (std::shared_lock pf_lock(pf_events->pf_mutex);
|
||||
pf_events->events.find(static_cast<u32>(data2)) != pf_events->events.end();)
|
||||
pf_events->events.count(static_cast<u32>(data2)) && !sending_error;)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
if (cpu->is_stopped())
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -1398,16 +1435,10 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
pf_events->cond.wait(pf_lock, 10000);
|
||||
}
|
||||
|
||||
// Reschedule
|
||||
if (cpu->test_stopped())
|
||||
// Reschedule, test cpu state and try recovery if stopped
|
||||
if (cpu->test_stopped() && !hack_alloc())
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
// Hack: allocate memory in case the emulator is stopping
|
||||
vm::falloc(addr & -0x10000, 0x10000);
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1415,36 +1446,29 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
|
||||
if (cpu->id_type() != 1)
|
||||
{
|
||||
LOG_NOTICE(GENERAL, "\n%s", cpu->dump());
|
||||
LOG_FATAL(MEMORY, "Access violation %s location 0x%x", is_writing ? "writing" : "reading", addr);
|
||||
if (!access_violation_recovered)
|
||||
{
|
||||
vm_log.notice("\n%s", cpu->dump());
|
||||
vm_log.fatal("Access violation %s location 0x%x (%s)", is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory");
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// RawSPU: Send appropriate interrupt
|
||||
// SPUThread: Send sys_spu exception event
|
||||
cpu->state += cpu_flag::dbg_pause;
|
||||
if (cpu->check_state())
|
||||
|
||||
if (cpu->check_state() && !hack_alloc())
|
||||
{
|
||||
// Hack: allocate memory in case the emulator is stopping
|
||||
auto area = vm::reserve_map(vm::any, addr & -0x10000, 0x10000);
|
||||
|
||||
if (area->flags & 0x100)
|
||||
{
|
||||
// For 4kb pages
|
||||
utils::memory_protect(vm::base(addr & -0x1000), 0x1000, utils::protection::rw);
|
||||
}
|
||||
else
|
||||
{
|
||||
area->falloc(addr & -0x10000, 0x10000);
|
||||
}
|
||||
|
||||
return true;
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto last_func = static_cast<ppu_thread*>(cpu)->current_function)
|
||||
{
|
||||
LOG_FATAL(PPU, "Function aborted: %s", last_func);
|
||||
ppu_log.fatal("Function aborted: %s", last_func);
|
||||
}
|
||||
|
||||
lv2_obj::sleep(*cpu);
|
||||
@@ -1453,19 +1477,24 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
|
||||
Emu.Pause();
|
||||
|
||||
if (cpu)
|
||||
if (cpu && !access_violation_recovered)
|
||||
{
|
||||
LOG_NOTICE(GENERAL, "\n%s", cpu->dump());
|
||||
vm_log.notice("\n%s", cpu->dump());
|
||||
}
|
||||
|
||||
LOG_FATAL(MEMORY, "Access violation %s location 0x%x", is_writing ? "writing" : "reading", addr);
|
||||
// Note: a thread may access violate more than once after hack_alloc recovery
|
||||
// Do not log any further access violations in this case.
|
||||
if (!access_violation_recovered)
|
||||
{
|
||||
vm_log.fatal("Access violation %s location 0x%x (%s)", is_writing ? "writing" : "reading", addr, (is_writing && vm::check_addr(addr)) ? "read-only memory" : "unmapped memory");
|
||||
}
|
||||
|
||||
while (Emu.IsPaused())
|
||||
{
|
||||
thread_ctrl::wait();
|
||||
}
|
||||
|
||||
if (Emu.IsStopped())
|
||||
if (Emu.IsStopped() && !hack_alloc())
|
||||
{
|
||||
std::terminate();
|
||||
}
|
||||
@@ -1475,8 +1504,13 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
static LONG exception_handler(PEXCEPTION_POINTERS pExp)
|
||||
static LONG exception_handler(PEXCEPTION_POINTERS pExp) noexcept
|
||||
{
|
||||
if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT && IsDebuggerPresent())
|
||||
{
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
const u64 addr64 = pExp->ExceptionRecord->ExceptionInformation[1] - reinterpret_cast<u64>(vm::g_base_addr);
|
||||
const u64 exec64 = (pExp->ExceptionRecord->ExceptionInformation[1] - reinterpret_cast<u64>(vm::g_exec_addr)) / 2;
|
||||
const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0;
|
||||
@@ -1496,10 +1530,11 @@ static LONG exception_handler(PEXCEPTION_POINTERS pExp)
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
}
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
static LONG exception_filter(PEXCEPTION_POINTERS pExp)
|
||||
static LONG exception_filter(PEXCEPTION_POINTERS pExp) noexcept
|
||||
{
|
||||
std::string msg = fmt::format("Unhandled Win32 exception 0x%08X.\n", pExp->ExceptionRecord->ExceptionCode);
|
||||
|
||||
@@ -1507,18 +1542,35 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp)
|
||||
{
|
||||
const auto cause = pExp->ExceptionRecord->ExceptionInformation[0] != 0 ? "writing" : "reading";
|
||||
|
||||
msg += fmt::format("Segfault %s location %p at %p.\n", cause, pExp->ExceptionRecord->ExceptionInformation[1], pExp->ExceptionRecord->ExceptionAddress);
|
||||
fmt::append(msg, "Segfault %s location %p at %p.\n", cause, pExp->ExceptionRecord->ExceptionInformation[1], pExp->ExceptionRecord->ExceptionAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg += fmt::format("Exception address: %p.\n", pExp->ExceptionRecord->ExceptionAddress);
|
||||
fmt::append(msg, "Exception address: %p.\n", pExp->ExceptionRecord->ExceptionAddress);
|
||||
|
||||
for (DWORD i = 0; i < pExp->ExceptionRecord->NumberParameters; i++)
|
||||
{
|
||||
msg += fmt::format("ExceptionInformation[0x%x]: %p.\n", i, pExp->ExceptionRecord->ExceptionInformation[i]);
|
||||
fmt::append(msg, "ExceptionInformation[0x%x]: %p.\n", i, pExp->ExceptionRecord->ExceptionInformation[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (thread_ctrl::get_current())
|
||||
{
|
||||
fmt::append(msg, "Emu Thread Name: '%s'.\n", thread_ctrl::get_name());
|
||||
|
||||
if (const auto cpu = get_current_cpu_thread())
|
||||
{
|
||||
sys_log.notice("\n%s", cpu->dump());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Report full thread name if not an emu thread
|
||||
|
||||
fmt::append(msg, "Thread id = %s.\n", std::this_thread::get_id());
|
||||
|
||||
sys_log.notice("Memory bases:\nvm::g_base_addr = %p\nvm::g_sudo_addr = %p\nvm::g_exec_addr = %p\nvm::g_stat_addr = %p\nvm::g_reservations = %p\n",
|
||||
vm::g_base_addr, vm::g_sudo_addr, vm::g_exec_addr, vm::g_stat_addr, vm::g_reservations);
|
||||
|
||||
std::vector<HMODULE> modules;
|
||||
for (DWORD size = 256; modules.size() != size; size /= sizeof(HMODULE))
|
||||
{
|
||||
@@ -1530,14 +1582,14 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp)
|
||||
}
|
||||
}
|
||||
|
||||
msg += fmt::format("Instruction address: %p.\n", pExp->ContextRecord->Rip);
|
||||
fmt::append(msg, "Instruction address: %p.\n", pExp->ContextRecord->Rip);
|
||||
|
||||
DWORD64 unwind_base;
|
||||
if (const auto rtf = RtlLookupFunctionEntry(pExp->ContextRecord->Rip, &unwind_base, nullptr))
|
||||
{
|
||||
// Get function address
|
||||
const DWORD64 func_addr = rtf->BeginAddress + unwind_base;
|
||||
msg += fmt::format("Function address: %p (base+0x%x).\n", func_addr, rtf->BeginAddress);
|
||||
fmt::append(msg, "Function address: %p (base+0x%x).\n", func_addr, rtf->BeginAddress);
|
||||
|
||||
// Access UNWIND_INFO structure
|
||||
//const auto uw = (u8*)(unwind_base + rtf->UnwindData);
|
||||
@@ -1564,18 +1616,23 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp)
|
||||
}
|
||||
}
|
||||
|
||||
msg += fmt::format("Module name: '%s'.\n", module_name);
|
||||
msg += fmt::format("Module base: %p.\n", info.lpBaseOfDll);
|
||||
fmt::append(msg, "Module name: '%s'.\n", module_name);
|
||||
fmt::append(msg, "Module base: %p.\n", info.lpBaseOfDll);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msg += fmt::format("RPCS3 image base: %p.\n", GetModuleHandle(NULL));
|
||||
fmt::append(msg, "RPCS3 image base: %p.\n", GetModuleHandle(NULL));
|
||||
|
||||
// TODO: print registers and the callstack
|
||||
|
||||
// Report fatal error
|
||||
report_fatal_error(msg);
|
||||
sys_log.fatal("\n%s", msg);
|
||||
|
||||
if (!IsDebuggerPresent())
|
||||
{
|
||||
report_fatal_error(msg);
|
||||
}
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
@@ -1596,7 +1653,7 @@ const bool s_exception_handler_set = []() -> bool
|
||||
|
||||
#else
|
||||
|
||||
static void signal_handler(int sig, siginfo_t* info, void* uct)
|
||||
static void signal_handler(int sig, siginfo_t* info, void* uct) noexcept
|
||||
{
|
||||
x64_context* context = static_cast<ucontext_t*>(uct);
|
||||
|
||||
@@ -1633,8 +1690,28 @@ static void signal_handler(int sig, siginfo_t* info, void* uct)
|
||||
}
|
||||
}
|
||||
|
||||
if (const auto cpu = get_current_cpu_thread())
|
||||
{
|
||||
sys_log.notice("\n%s", cpu->dump());
|
||||
}
|
||||
|
||||
sys_log.notice("Memory bases:\nvm::g_base_addr = %p\nvm::g_sudo_addr = %p\nvm::g_exec_addr = %p\nvm::g_stat_addr = %p\nvm::g_reservations = %p\n",
|
||||
vm::g_base_addr, vm::g_sudo_addr, vm::g_exec_addr, vm::g_stat_addr, vm::g_reservations);
|
||||
|
||||
std::string msg = fmt::format("Segfault %s location %p at %p.\n", cause, info->si_addr, RIP(context));
|
||||
|
||||
if (thread_ctrl::get_current())
|
||||
{
|
||||
fmt::append(msg, "Emu Thread Name: '%s'.\n", thread_ctrl::get_name());
|
||||
}
|
||||
|
||||
// TODO: Report full thread name if not an emu thread
|
||||
|
||||
fmt::append(msg, "Thread id = %s.\n", std::this_thread::get_id());
|
||||
|
||||
// TODO (debugger interaction)
|
||||
report_fatal_error(fmt::format("Segfault %s location %p at %p.", cause, info->si_addr, RIP(context)));
|
||||
sys_log.fatal("\n%s", msg);
|
||||
report_fatal_error(msg);
|
||||
}
|
||||
|
||||
const bool s_exception_handler_set = []() -> bool
|
||||
@@ -1679,9 +1756,11 @@ void thread_base::initialize(bool(*wait_cb)(const void*))
|
||||
|
||||
g_tls_log_prefix = []
|
||||
{
|
||||
return thread_ctrl::g_tls_this_thread->m_name.get();
|
||||
return thread_ctrl::get_name_cached();
|
||||
};
|
||||
|
||||
std::string name = thread_ctrl::get_name_cached();
|
||||
|
||||
#ifdef _MSC_VER
|
||||
struct THREADNAME_INFO
|
||||
{
|
||||
@@ -1692,11 +1771,11 @@ void thread_base::initialize(bool(*wait_cb)(const void*))
|
||||
};
|
||||
|
||||
// Set thread name for VS debugger
|
||||
if (IsDebuggerPresent())
|
||||
if (IsDebuggerPresent()) [&]() NEVER_INLINE
|
||||
{
|
||||
THREADNAME_INFO info;
|
||||
info.dwType = 0x1000;
|
||||
info.szName = m_name.get().c_str();
|
||||
info.szName = name.c_str();
|
||||
info.dwThreadID = -1;
|
||||
info.dwFlags = 0;
|
||||
|
||||
@@ -1707,24 +1786,26 @@ void thread_base::initialize(bool(*wait_cb)(const void*))
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
}
|
||||
}
|
||||
}();
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
pthread_setname_np(m_name.get().substr(0, 15).c_str());
|
||||
name.resize(std::min<std::size_t>(15, name.size()));
|
||||
pthread_setname_np(name.c_str());
|
||||
#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
pthread_set_name_np(pthread_self(), m_name.get().c_str());
|
||||
pthread_set_name_np(pthread_self(), name.c_str());
|
||||
#elif defined(__NetBSD__)
|
||||
pthread_setname_np(pthread_self(), "%s", const_cast<char*>(m_name.get().c_str()));
|
||||
pthread_setname_np(pthread_self(), "%s", name.data());
|
||||
#elif !defined(_WIN32)
|
||||
pthread_setname_np(pthread_self(), m_name.get().substr(0, 15).c_str());
|
||||
name.resize(std::min<std::size_t>(15, name.size()));
|
||||
pthread_setname_np(pthread_self(), name.c_str());
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
m_timer = timerfd_create(CLOCK_MONOTONIC, 0);
|
||||
if (m_timer == -1)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "Linux timer allocation failed, use wait_unlock() only");
|
||||
sig_log.error("Linux timer allocation failed, use wait_unlock() only");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1755,34 +1836,49 @@ bool thread_base::finalize(int) noexcept
|
||||
FILETIME ctime, etime, ktime, utime;
|
||||
GetThreadTimes(GetCurrentThread(), &ctime, &etime, &ktime, &utime);
|
||||
const u64 time = ((ktime.dwLowDateTime | (u64)ktime.dwHighDateTime << 32) + (utime.dwLowDateTime | (u64)utime.dwHighDateTime << 32)) * 100ull;
|
||||
const u64 fsoft = 0;
|
||||
const u64 fhard = 0;
|
||||
const u64 ctxvol = 0;
|
||||
const u64 ctxinv = 0;
|
||||
#elif defined(RUSAGE_THREAD)
|
||||
const u64 cycles = 0; // Not supported
|
||||
struct ::rusage stats{};
|
||||
::getrusage(RUSAGE_THREAD, &stats);
|
||||
const u64 time = (stats.ru_utime.tv_sec + stats.ru_stime.tv_sec) * 1000000000ull + (stats.ru_utime.tv_usec + stats.ru_stime.tv_usec) * 1000ull;
|
||||
const u64 fsoft = stats.ru_minflt;
|
||||
const u64 fhard = stats.ru_majflt;
|
||||
const u64 ctxvol = stats.ru_nvcsw;
|
||||
const u64 ctxinv = stats.ru_nivcsw;
|
||||
#else
|
||||
const u64 cycles = 0;
|
||||
const u64 time = 0;
|
||||
const u64 fsoft = 0;
|
||||
const u64 fhard = 0;
|
||||
const u64 ctxvol = 0;
|
||||
const u64 ctxinv = 0;
|
||||
#endif
|
||||
|
||||
g_tls_log_prefix = []
|
||||
{
|
||||
return thread_ctrl::g_tls_this_thread->m_name.get();
|
||||
return thread_ctrl::get_name_cached();
|
||||
};
|
||||
|
||||
LOG_NOTICE(GENERAL, "Thread time: %fs (%fGc); Faults: %u [rsx:%u, spu:%u];",
|
||||
sig_log.notice("Thread time: %fs (%fGc); Faults: %u [rsx:%u, spu:%u]; [soft:%u hard:%u]; Switches:[vol:%u unvol:%u]",
|
||||
time / 1000000000.,
|
||||
cycles / 1000000000.,
|
||||
g_tls_fault_all,
|
||||
g_tls_fault_rsx,
|
||||
g_tls_fault_spu);
|
||||
g_tls_fault_spu,
|
||||
fsoft, fhard, ctxvol, ctxinv);
|
||||
|
||||
// Return true if need to delete thread object
|
||||
const bool result = m_state.exchange(thread_state::finished) == thread_state::detached;
|
||||
const bool ok = m_state.exchange(thread_state::finished) <= thread_state::aborting;
|
||||
|
||||
// Signal waiting threads
|
||||
m_state.notify_all();
|
||||
return result;
|
||||
|
||||
// No detached thread supported atm
|
||||
return !ok;
|
||||
}
|
||||
|
||||
void thread_base::finalize() noexcept
|
||||
@@ -1808,7 +1904,7 @@ void thread_ctrl::_wait_for(u64 usec, bool alert /* true */)
|
||||
timeout.it_interval.tv_nsec = 0;
|
||||
timerfd_settime(_this->m_timer, 0, &timeout, NULL);
|
||||
if (read(_this->m_timer, &missed, sizeof(missed)) != sizeof(missed))
|
||||
LOG_ERROR(GENERAL, "timerfd: read() failed");
|
||||
sig_log.error("timerfd: read() failed");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -1857,8 +1953,27 @@ void thread_ctrl::_wait_for(u64 usec, bool alert /* true */)
|
||||
}
|
||||
}
|
||||
|
||||
std::string thread_ctrl::get_name_cached()
|
||||
{
|
||||
auto _this = thread_ctrl::g_tls_this_thread;
|
||||
|
||||
if (!_this)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
static thread_local stx::shared_cptr<std::string> name_cache;
|
||||
|
||||
if (!_this->m_tname.is_equal(name_cache)) [[unlikely]]
|
||||
{
|
||||
name_cache = _this->m_tname.load();
|
||||
}
|
||||
|
||||
return *name_cache;
|
||||
}
|
||||
|
||||
thread_base::thread_base(std::string_view name)
|
||||
: m_name(name)
|
||||
: m_tname(stx::shared_cptr<std::string>::make(name))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1949,13 +2064,13 @@ void thread_ctrl::detect_cpu_layout()
|
||||
// If buffer size is set to 0 bytes, it will be overwritten with the required size
|
||||
if (GetLogicalProcessorInformationEx(relationship, nullptr, &buffer_size))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "GetLogicalProcessorInformationEx returned 0 bytes");
|
||||
sig_log.error("GetLogicalProcessorInformationEx returned 0 bytes");
|
||||
return;
|
||||
}
|
||||
DWORD error_code = GetLastError();
|
||||
if (error_code != ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "Unexpected windows error code when detecting CPU layout: %u", error_code);
|
||||
sig_log.error("Unexpected windows error code when detecting CPU layout: %u", error_code);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1964,7 +2079,7 @@ void thread_ctrl::detect_cpu_layout()
|
||||
if (!GetLogicalProcessorInformationEx(relationship,
|
||||
reinterpret_cast<SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *>(buffer.data()), &buffer_size))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "GetLogicalProcessorInformationEx failed (size=%u, error=%u)", buffer_size, GetLastError());
|
||||
sig_log.error("GetLogicalProcessorInformationEx failed (size=%u, error=%u)", buffer_size, GetLastError());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1984,7 +2099,7 @@ void thread_ctrl::detect_cpu_layout()
|
||||
}
|
||||
}
|
||||
#else
|
||||
LOG_TODO(GENERAL, "Thread scheduler is not implemented for Intel and this OS");
|
||||
sig_log.todo("Thread scheduler is not implemented for Intel and this OS");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -2160,7 +2275,7 @@ void thread_ctrl::set_native_priority(int priority)
|
||||
|
||||
if (!SetThreadPriority(_this_thread, native_priority))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "SetThreadPriority() failed: 0x%x", GetLastError());
|
||||
sig_log.error("SetThreadPriority() failed: 0x%x", GetLastError());
|
||||
}
|
||||
#else
|
||||
int policy;
|
||||
@@ -2175,7 +2290,7 @@ void thread_ctrl::set_native_priority(int priority)
|
||||
|
||||
if (int err = pthread_setschedparam(pthread_self(), policy, ¶m))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "pthraed_setschedparam() failed: %d", err);
|
||||
sig_log.error("pthraed_setschedparam() failed: %d", err);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -2200,7 +2315,10 @@ void thread_ctrl::set_thread_affinity_mask(u64 mask)
|
||||
|
||||
if (shifted & 1)
|
||||
{
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
CPU_SET(core, &cs);
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
|
||||
if (shifted <= 1)
|
||||
|
||||
+104
-94
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "types.h"
|
||||
#include "util/atomic.hpp"
|
||||
#include "util/shared_cptr.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
@@ -37,8 +38,7 @@ enum class thread_class : u32
|
||||
enum class thread_state : u32
|
||||
{
|
||||
created, // Initial state
|
||||
detached, // The thread has been detached to destroy its own named_thread object (can be dangerously misused)
|
||||
aborting, // The thread has been joined in the destructor or explicitly aborted (mutually exclusive with detached)
|
||||
aborting, // The thread has been joined in the destructor or explicitly aborted
|
||||
finished // Final state, always set at the end of thread execution
|
||||
};
|
||||
|
||||
@@ -81,27 +81,6 @@ struct result_storage<void>
|
||||
template <class Context, typename... Args>
|
||||
using result_storage_t = result_storage<std::invoke_result_t<Context, Args...>>;
|
||||
|
||||
// Detect on_abort() method (should return void)
|
||||
template <typename T, typename = void>
|
||||
struct thread_on_abort : std::bool_constant<false> {};
|
||||
|
||||
template <typename T>
|
||||
struct thread_on_abort<T, decltype(std::declval<named_thread<T>&>().on_abort())> : std::bool_constant<true> {};
|
||||
|
||||
// Detect on_cleanup() static member function (should return void) (in C++20 can use destroying delete instead)
|
||||
template <typename T, typename = void>
|
||||
struct thread_on_cleanup : std::bool_constant<false> {};
|
||||
|
||||
template <typename T>
|
||||
struct thread_on_cleanup<T, decltype(named_thread<T>::on_cleanup(std::declval<named_thread<T>*>()))> : std::bool_constant<true> {};
|
||||
|
||||
// Detect on_wait() method (should return bool)
|
||||
template <typename T, typename = bool>
|
||||
struct thread_on_wait : std::bool_constant<false> {};
|
||||
|
||||
template <typename T>
|
||||
struct thread_on_wait<T, decltype(std::declval<named_thread<T>&>().on_wait())> : std::bool_constant<true> {};
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct thread_thread_name : std::bool_constant<false> {};
|
||||
|
||||
@@ -142,7 +121,7 @@ class thread_base
|
||||
atomic_t<const void*> m_state_notifier{nullptr};
|
||||
|
||||
// Thread name
|
||||
lf_value<std::string> m_name;
|
||||
stx::atomic_cptr<std::string> m_tname;
|
||||
|
||||
//
|
||||
atomic_t<u64> m_cycles = 0;
|
||||
@@ -197,31 +176,34 @@ class thread_ctrl final
|
||||
|
||||
friend class thread_base;
|
||||
|
||||
// Optimized get_name() for logging
|
||||
static std::string get_name_cached();
|
||||
|
||||
public:
|
||||
// Get current thread name
|
||||
static std::string_view get_name()
|
||||
static std::string get_name()
|
||||
{
|
||||
return g_tls_this_thread->m_name.get();
|
||||
return *g_tls_this_thread->m_tname.load();
|
||||
}
|
||||
|
||||
// Get thread name
|
||||
template <typename T>
|
||||
static std::string_view get_name(const named_thread<T>& thread)
|
||||
static std::string get_name(const named_thread<T>& thread)
|
||||
{
|
||||
return static_cast<const thread_base&>(thread).m_name.get();
|
||||
return *static_cast<const thread_base&>(thread).m_tname.load();
|
||||
}
|
||||
|
||||
// Set current thread name (not recommended)
|
||||
static void set_name(std::string_view name)
|
||||
{
|
||||
g_tls_this_thread->m_name.assign(name);
|
||||
g_tls_this_thread->m_tname.store(stx::shared_cptr<std::string>::make(name));
|
||||
}
|
||||
|
||||
// Set thread name (not recommended)
|
||||
template <typename T>
|
||||
static void set_name(named_thread<T>& thread, std::string_view name)
|
||||
{
|
||||
static_cast<thread_base&>(thread).m_name.assign(name);
|
||||
static_cast<thread_base&>(thread).m_tname.store(stx::shared_cptr<std::string>::make(name));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -286,13 +268,6 @@ public:
|
||||
|
||||
// Sets the preferred affinity mask for this thread
|
||||
static void set_thread_affinity_mask(u64 mask);
|
||||
|
||||
// Spawn a detached named thread
|
||||
template <typename F>
|
||||
[[deprecated]] static void spawn(std::string_view name, F&& func)
|
||||
{
|
||||
new named_thread<F>(thread_state::detached, name, std::forward<F>(func));
|
||||
}
|
||||
};
|
||||
|
||||
// Derived from the callable object Context, possibly a lambda
|
||||
@@ -314,15 +289,7 @@ class named_thread final : public Context, result_storage_t<Context>, thread_bas
|
||||
// Perform self-cleanup if necessary
|
||||
if (_this->entry_point())
|
||||
{
|
||||
// Call on_cleanup() static member function if it's available
|
||||
if constexpr (thread_on_cleanup<Context>())
|
||||
{
|
||||
Context::on_cleanup(_this);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete _this;
|
||||
}
|
||||
delete _this;
|
||||
}
|
||||
|
||||
thread::finalize();
|
||||
@@ -344,14 +311,6 @@ class named_thread final : public Context, result_storage_t<Context>, thread_bas
|
||||
return false;
|
||||
}
|
||||
|
||||
if constexpr (thread_on_wait<Context>())
|
||||
{
|
||||
if (!static_cast<named_thread*>(_this)->on_wait())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_this->m_state_notifier.release(data);
|
||||
|
||||
if (!data)
|
||||
@@ -365,15 +324,6 @@ class named_thread final : public Context, result_storage_t<Context>, thread_bas
|
||||
return false;
|
||||
}
|
||||
|
||||
if constexpr (thread_on_wait<Context>())
|
||||
{
|
||||
if (!static_cast<named_thread*>(_this)->on_wait())
|
||||
{
|
||||
_this->m_state_notifier.release(nullptr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -391,35 +341,14 @@ class named_thread final : public Context, result_storage_t<Context>, thread_bas
|
||||
return thread::finalize(0);
|
||||
}
|
||||
|
||||
static decltype(auto) get_default_thread_name()
|
||||
{
|
||||
if constexpr (thread_thread_name<Context>())
|
||||
{
|
||||
return Context::thread_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Unnamed Thread";
|
||||
}
|
||||
}
|
||||
|
||||
// Detached thread constructor
|
||||
named_thread(thread_state s, std::string_view name, Context&& f)
|
||||
: Context(std::forward<Context>(f))
|
||||
, thread(name)
|
||||
{
|
||||
thread::m_state.raw() = s;
|
||||
thread::start(&named_thread::entry_point);
|
||||
}
|
||||
|
||||
friend class thread_ctrl;
|
||||
|
||||
public:
|
||||
// Default constructor
|
||||
template <bool Valid = std::is_default_constructible_v<Context>, typename = std::enable_if_t<Valid>>
|
||||
template <bool Valid = std::is_default_constructible_v<Context> && thread_thread_name<Context>(), typename = std::enable_if_t<Valid>>
|
||||
named_thread()
|
||||
: Context()
|
||||
, thread(get_default_thread_name())
|
||||
, thread(Context::thread_name)
|
||||
{
|
||||
thread::start(&named_thread::entry_point);
|
||||
}
|
||||
@@ -473,19 +402,15 @@ public:
|
||||
return thread::m_state.load();
|
||||
}
|
||||
|
||||
// Try to abort/detach
|
||||
// Try to abort by assigning thread_state::aborting (UB if assigning different state)
|
||||
named_thread& operator=(thread_state s)
|
||||
{
|
||||
if (s < thread_state::finished && thread::m_state.compare_and_swap_test(thread_state::created, s))
|
||||
ASSUME(s == thread_state::aborting);
|
||||
|
||||
if (s == thread_state::aborting && thread::m_state.compare_and_swap_test(thread_state::created, s))
|
||||
{
|
||||
if (s == thread_state::aborting)
|
||||
{
|
||||
// Call on_abort() method if it's available
|
||||
if constexpr (thread_on_abort<Context>())
|
||||
{
|
||||
Context::on_abort();
|
||||
}
|
||||
|
||||
thread::notify_abort();
|
||||
}
|
||||
}
|
||||
@@ -496,6 +421,7 @@ public:
|
||||
// Context type doesn't need virtual destructor
|
||||
~named_thread()
|
||||
{
|
||||
// Assign aborting state forcefully
|
||||
operator=(thread_state::aborting);
|
||||
thread::join();
|
||||
|
||||
@@ -505,3 +431,87 @@ public:
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Group of named threads, similar to named_thread
|
||||
template <class Context>
|
||||
class named_thread_group final
|
||||
{
|
||||
using Thread = named_thread<Context>;
|
||||
|
||||
const u32 m_count;
|
||||
|
||||
Thread* m_threads;
|
||||
|
||||
public:
|
||||
// Lambda constructor, also the implicit deduction guide candidate
|
||||
named_thread_group(std::string_view name, u32 count, const Context& f)
|
||||
: m_count(count)
|
||||
, m_threads(nullptr)
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_threads = static_cast<Thread*>(::operator new(sizeof(Thread) * m_count, std::align_val_t{alignof(Thread)}));
|
||||
|
||||
// Create all threads
|
||||
for (u32 i = 0; i < m_count; i++)
|
||||
{
|
||||
new (static_cast<void*>(m_threads + i)) Thread(std::string(name) + std::to_string(i + 1), f);
|
||||
}
|
||||
}
|
||||
|
||||
named_thread_group(const named_thread_group&) = delete;
|
||||
|
||||
named_thread_group& operator=(const named_thread_group&) = delete;
|
||||
|
||||
// Wait for completion
|
||||
void join() const
|
||||
{
|
||||
for (u32 i = 0; i < m_count; i++)
|
||||
{
|
||||
std::as_const(*std::launder(m_threads + i))();
|
||||
}
|
||||
}
|
||||
|
||||
// Join and access specific thread
|
||||
auto operator[](u32 index) const
|
||||
{
|
||||
return std::as_const(*std::launder(m_threads + index))();
|
||||
}
|
||||
|
||||
// Join and access specific thread
|
||||
auto operator[](u32 index)
|
||||
{
|
||||
return (*std::launder(m_threads + index))();
|
||||
}
|
||||
|
||||
// Dumb iterator
|
||||
auto begin()
|
||||
{
|
||||
return std::launder(m_threads);
|
||||
}
|
||||
|
||||
// Dumb iterator
|
||||
auto end()
|
||||
{
|
||||
return m_threads + m_count;
|
||||
}
|
||||
|
||||
u32 size() const
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
~named_thread_group()
|
||||
{
|
||||
// Destroy all threads (it should join them)
|
||||
for (u32 i = 0; i < m_count; i++)
|
||||
{
|
||||
std::launder(m_threads + i)->~Thread();
|
||||
}
|
||||
|
||||
::operator delete(static_cast<void*>(m_threads), std::align_val_t{alignof(Thread)});
|
||||
}
|
||||
};
|
||||
|
||||
+78
-1
@@ -3,6 +3,8 @@
|
||||
#include "File.h"
|
||||
#include "Config.h"
|
||||
|
||||
LOG_CHANNEL(patch_log);
|
||||
|
||||
template <>
|
||||
void fmt_class_string<patch_type>::format(std::string& out, u64 arg)
|
||||
{
|
||||
@@ -40,7 +42,7 @@ void patch_engine::append(const std::string& patch)
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_FATAL(GENERAL, "Failed to load patch file %s\n%s thrown: %s", patch, typeid(e).name(), e.what());
|
||||
patch_log.fatal("Failed to load patch file %s\n%s thrown: %s", patch, typeid(e).name(), e.what());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -173,3 +175,78 @@ std::size_t patch_engine::apply(const std::string& name, u8* dst) const
|
||||
|
||||
return found->second.size();
|
||||
}
|
||||
|
||||
std::size_t patch_engine::apply_with_ls_check(const std::string& name, u8* dst, u32 filesz, u32 ls_addr) const
|
||||
{
|
||||
u32 rejected = 0;
|
||||
|
||||
const auto found = m_map.find(name);
|
||||
|
||||
if (found == m_map.cend())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Apply modifications sequentially
|
||||
for (const auto& p : found->second)
|
||||
{
|
||||
auto ptr = dst + (p.offset - ls_addr);
|
||||
|
||||
if(p.offset < ls_addr || p.offset >= (ls_addr + filesz))
|
||||
{
|
||||
// This patch is out of range for this segment
|
||||
rejected++;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (p.type)
|
||||
{
|
||||
case patch_type::load:
|
||||
{
|
||||
// Invalid in this context
|
||||
break;
|
||||
}
|
||||
case patch_type::byte:
|
||||
{
|
||||
*ptr = static_cast<u8>(p.value);
|
||||
break;
|
||||
}
|
||||
case patch_type::le16:
|
||||
{
|
||||
*reinterpret_cast<le_t<u16, 1>*>(ptr) = static_cast<u16>(p.value);
|
||||
break;
|
||||
}
|
||||
case patch_type::le32:
|
||||
case patch_type::lef32:
|
||||
{
|
||||
*reinterpret_cast<le_t<u32, 1>*>(ptr) = static_cast<u32>(p.value);
|
||||
break;
|
||||
}
|
||||
case patch_type::le64:
|
||||
case patch_type::lef64:
|
||||
{
|
||||
*reinterpret_cast<le_t<u64, 1>*>(ptr) = static_cast<u64>(p.value);
|
||||
break;
|
||||
}
|
||||
case patch_type::be16:
|
||||
{
|
||||
*reinterpret_cast<be_t<u16, 1>*>(ptr) = static_cast<u16>(p.value);
|
||||
break;
|
||||
}
|
||||
case patch_type::be32:
|
||||
case patch_type::bef32:
|
||||
{
|
||||
*reinterpret_cast<be_t<u32, 1>*>(ptr) = static_cast<u32>(p.value);
|
||||
break;
|
||||
}
|
||||
case patch_type::be64:
|
||||
case patch_type::bef64:
|
||||
{
|
||||
*reinterpret_cast<be_t<u64, 1>*>(ptr) = static_cast<u64>(p.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (found->second.size() - rejected);
|
||||
}
|
||||
|
||||
@@ -39,4 +39,6 @@ public:
|
||||
|
||||
// Apply patch (returns the number of entries applied)
|
||||
std::size_t apply(const std::string& name, u8* dst) const;
|
||||
// Apply patch with a check that the address exists in SPU local storage
|
||||
std::size_t apply_with_ls_check(const std::string&name, u8*dst, u32 filesz, u32 ls_addr) const;
|
||||
};
|
||||
|
||||
+17
-17
@@ -136,7 +136,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
case '8':
|
||||
case '9':
|
||||
{
|
||||
if (UNLIKELY(ctx.width))
|
||||
if (ctx.width) [[unlikely]]
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
@@ -150,7 +150,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
|
||||
case '*':
|
||||
{
|
||||
if (UNLIKELY(ctx.width || !src.test(ctx.args)))
|
||||
if (ctx.width || !src.test(ctx.args)) [[unlikely]]
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
@@ -166,7 +166,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
|
||||
case '.':
|
||||
{
|
||||
if (UNLIKELY(ctx.dot || ctx.prec))
|
||||
if (ctx.dot || ctx.prec) [[unlikely]]
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
@@ -177,7 +177,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
}
|
||||
else if (*fmt == '*')
|
||||
{
|
||||
if (UNLIKELY(!src.test(ctx.args)))
|
||||
if (!src.test(ctx.args)) [[unlikely]]
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
@@ -200,7 +200,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
|
||||
case 'h':
|
||||
{
|
||||
if (UNLIKELY(ctx.type))
|
||||
if (ctx.type) [[unlikely]]
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
@@ -219,7 +219,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
|
||||
case 'l':
|
||||
{
|
||||
if (UNLIKELY(ctx.type))
|
||||
if (ctx.type) [[unlikely]]
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
@@ -238,7 +238,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
|
||||
case 'z':
|
||||
{
|
||||
if (UNLIKELY(ctx.type))
|
||||
if (ctx.type) [[unlikely]]
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
@@ -252,7 +252,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
|
||||
case 'j':
|
||||
{
|
||||
if (UNLIKELY(ctx.type))
|
||||
if (ctx.type) [[unlikely]]
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
@@ -266,7 +266,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
|
||||
case 't':
|
||||
{
|
||||
if (UNLIKELY(ctx.type))
|
||||
if (ctx.type) [[unlikely]]
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
@@ -280,7 +280,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
|
||||
case 'c':
|
||||
{
|
||||
if (UNLIKELY(ctx.type || !src.test(ctx.args)))
|
||||
if (ctx.type || !src.test(ctx.args)) [[unlikely]]
|
||||
{
|
||||
drop_sequence();
|
||||
break;
|
||||
@@ -302,7 +302,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
|
||||
case 's':
|
||||
{
|
||||
if (UNLIKELY(ctx.type || !src.test(ctx.args)))
|
||||
if (ctx.type || !src.test(ctx.args)) [[unlikely]]
|
||||
{
|
||||
drop_sequence();
|
||||
break;
|
||||
@@ -333,7 +333,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
case 'd':
|
||||
case 'i':
|
||||
{
|
||||
if (UNLIKELY(!src.test(ctx.args)))
|
||||
if (!src.test(ctx.args)) [[unlikely]]
|
||||
{
|
||||
drop_sequence();
|
||||
break;
|
||||
@@ -395,7 +395,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
|
||||
case 'o':
|
||||
{
|
||||
if (UNLIKELY(!src.test(ctx.args)))
|
||||
if (!src.test(ctx.args)) [[unlikely]]
|
||||
{
|
||||
drop_sequence();
|
||||
break;
|
||||
@@ -452,7 +452,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
case 'x':
|
||||
case 'X':
|
||||
{
|
||||
if (UNLIKELY(!src.test(ctx.args)))
|
||||
if (!src.test(ctx.args)) [[unlikely]]
|
||||
{
|
||||
drop_sequence();
|
||||
break;
|
||||
@@ -516,7 +516,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
|
||||
case 'u':
|
||||
{
|
||||
if (UNLIKELY(!src.test(ctx.args)))
|
||||
if (!src.test(ctx.args)) [[unlikely]]
|
||||
{
|
||||
drop_sequence();
|
||||
break;
|
||||
@@ -563,7 +563,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
|
||||
case 'p':
|
||||
{
|
||||
if (UNLIKELY(!src.test(ctx.args) || ctx.type))
|
||||
if (!src.test(ctx.args) || ctx.type) [[unlikely]]
|
||||
{
|
||||
drop_sequence();
|
||||
break;
|
||||
@@ -597,7 +597,7 @@ std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
case 'g':
|
||||
case 'G':
|
||||
{
|
||||
if (UNLIKELY(!src.test(ctx.args) || ctx.type))
|
||||
if (!src.test(ctx.args) || ctx.type) [[unlikely]]
|
||||
{
|
||||
drop_sequence();
|
||||
break;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace utils
|
||||
|
||||
+87
-46
@@ -15,10 +15,6 @@ struct size2_base
|
||||
{
|
||||
}
|
||||
|
||||
constexpr size2_base(const size2_base& rhs) : width{ rhs.width }, height{ rhs.height }
|
||||
{
|
||||
}
|
||||
|
||||
constexpr size2_base operator -(const size2_base& rhs) const
|
||||
{
|
||||
return{ width - rhs.width, height - rhs.height };
|
||||
@@ -101,18 +97,21 @@ struct size2_base
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr bool operator == (const size2_base& rhs) const
|
||||
constexpr bool operator ==(const size2_base& rhs) const
|
||||
{
|
||||
return width == rhs.width && height == rhs.height;
|
||||
}
|
||||
|
||||
constexpr bool operator != (const size2_base& rhs) const
|
||||
#if __cpp_impl_three_way_comparison >= 201711
|
||||
#else
|
||||
constexpr bool operator !=(const size2_base& rhs) const
|
||||
{
|
||||
return width != rhs.width || height != rhs.height;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename NT>
|
||||
constexpr operator size2_base<NT>() const
|
||||
explicit constexpr operator size2_base<NT>() const
|
||||
{
|
||||
return{ static_cast<NT>(width), static_cast<NT>(height) };
|
||||
}
|
||||
@@ -212,6 +211,8 @@ struct position1_base
|
||||
return x == rhs;
|
||||
}
|
||||
|
||||
#if __cpp_impl_three_way_comparison >= 201711
|
||||
#else
|
||||
bool operator !=(const position1_base& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
@@ -221,9 +222,10 @@ struct position1_base
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename NT>
|
||||
operator position1_base<NT>() const
|
||||
explicit operator position1_base<NT>() const
|
||||
{
|
||||
return{ static_cast<NT>(x) };
|
||||
}
|
||||
@@ -247,10 +249,6 @@ struct position2_base
|
||||
{
|
||||
}
|
||||
|
||||
constexpr position2_base(const position2_base& rhs) : x{ rhs.x }, y{ rhs.y }
|
||||
{
|
||||
}
|
||||
|
||||
constexpr bool operator >(const position2_base& rhs) const
|
||||
{
|
||||
return x > rhs.x && y > rhs.y;
|
||||
@@ -385,6 +383,8 @@ struct position2_base
|
||||
return x == rhs && y == rhs;
|
||||
}
|
||||
|
||||
#if __cpp_impl_three_way_comparison >= 201711
|
||||
#else
|
||||
constexpr bool operator !=(const position2_base& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
@@ -394,9 +394,10 @@ struct position2_base
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename NT>
|
||||
constexpr operator position2_base<NT>() const
|
||||
explicit constexpr operator position2_base<NT>() const
|
||||
{
|
||||
return{ static_cast<NT>(x), static_cast<NT>(y) };
|
||||
}
|
||||
@@ -477,6 +478,8 @@ struct position3_base
|
||||
return x == rhs && y == rhs && z == rhs;
|
||||
}
|
||||
|
||||
#if __cpp_impl_three_way_comparison >= 201711
|
||||
#else
|
||||
bool operator !=(const position3_base& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
@@ -486,9 +489,10 @@ struct position3_base
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename NT>
|
||||
operator position3_base<NT>() const
|
||||
explicit operator position3_base<NT>() const
|
||||
{
|
||||
return{ static_cast<NT>(x), static_cast<NT>(y), static_cast<NT>(z) };
|
||||
}
|
||||
@@ -567,6 +571,8 @@ struct position4_base
|
||||
return x == rhs && y == rhs && z == rhs && w == rhs;
|
||||
}
|
||||
|
||||
#if __cpp_impl_three_way_comparison >= 201711
|
||||
#else
|
||||
constexpr bool operator !=(const position4_base& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
@@ -576,9 +582,10 @@ struct position4_base
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename NT>
|
||||
constexpr operator position4_base<NT>() const
|
||||
explicit constexpr operator position4_base<NT>() const
|
||||
{
|
||||
return{ static_cast<NT>(x), static_cast<NT>(y), static_cast<NT>(z), static_cast<NT>(w) };
|
||||
}
|
||||
@@ -603,23 +610,11 @@ struct coord_base
|
||||
};
|
||||
|
||||
constexpr coord_base() : position{}, size{}
|
||||
#ifdef _MSC_VER
|
||||
//compiler error
|
||||
, x{}, y{}, width{}, height{}
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
constexpr coord_base(const position_base<T>& position, const size2_base<T>& size)
|
||||
: position{ position }, size{ size }
|
||||
#ifdef _MSC_VER
|
||||
, x{ position.x }, y{ position.y }, width{ size.width }, height{ size.height }
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
constexpr coord_base(const coord_base<T>& other)
|
||||
: position{ other.position }, size{ other.size }
|
||||
{
|
||||
}
|
||||
|
||||
@@ -644,13 +639,16 @@ struct coord_base
|
||||
return position == rhs.position && size == rhs.size;
|
||||
}
|
||||
|
||||
#if __cpp_impl_three_way_comparison >= 201711
|
||||
#else
|
||||
constexpr bool operator != (const coord_base& rhs) const
|
||||
{
|
||||
return position != rhs.position || size != rhs.size;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename NT>
|
||||
constexpr operator coord_base<NT>() const
|
||||
explicit constexpr operator coord_base<NT>() const
|
||||
{
|
||||
return{ static_cast<NT>(x), static_cast<NT>(y), static_cast<NT>(width), static_cast<NT>(height) };
|
||||
}
|
||||
@@ -720,10 +718,13 @@ struct area_base
|
||||
return x1 == rhs.x1 && x2 == rhs.x2 && y1 == rhs.y1 && y2 == rhs.y2;
|
||||
}
|
||||
|
||||
#if __cpp_impl_three_way_comparison >= 201711
|
||||
#else
|
||||
constexpr bool operator != (const area_base& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
constexpr area_base operator - (const size2_base<T>& size) const
|
||||
{
|
||||
@@ -759,7 +760,7 @@ struct area_base
|
||||
}
|
||||
|
||||
template<typename NT>
|
||||
constexpr operator area_base<NT>() const
|
||||
explicit constexpr operator area_base<NT>() const
|
||||
{
|
||||
return{ static_cast<NT>(x1), static_cast<NT>(y1), static_cast<NT>(x2), static_cast<NT>(y2) };
|
||||
}
|
||||
@@ -769,15 +770,6 @@ template<typename T>
|
||||
struct size3_base
|
||||
{
|
||||
T width, height, depth;
|
||||
/*
|
||||
size3_base() : width{}, height{}, depth{}
|
||||
{
|
||||
}
|
||||
|
||||
size3_base(T width, T height, T depth) : width{ width }, height{ height }, depth{ depth }
|
||||
{
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@@ -822,7 +814,7 @@ struct coord3_base
|
||||
}
|
||||
|
||||
template<typename NT>
|
||||
constexpr operator coord3_base<NT>() const
|
||||
explicit constexpr operator coord3_base<NT>() const
|
||||
{
|
||||
return{ static_cast<NT>(x), static_cast<NT>(y), static_cast<NT>(z), static_cast<NT>(width), static_cast<NT>(height), static_cast<NT>(depth) };
|
||||
}
|
||||
@@ -856,7 +848,7 @@ struct color4_base
|
||||
{
|
||||
}
|
||||
|
||||
constexpr color4_base(T x, T y = {}, T z = {}, T w = {})
|
||||
constexpr color4_base(T x, T y, T z, T w)
|
||||
: x(x)
|
||||
, y(y)
|
||||
, z(z)
|
||||
@@ -864,18 +856,59 @@ struct color4_base
|
||||
{
|
||||
}
|
||||
|
||||
constexpr color4_base(T value)
|
||||
: x(value)
|
||||
, y(value)
|
||||
, z(value)
|
||||
, w(value)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr bool operator == (const color4_base& rhs) const
|
||||
{
|
||||
return r == rhs.r && g == rhs.g && b == rhs.b && a == rhs.a;
|
||||
}
|
||||
|
||||
#if __cpp_impl_three_way_comparison >= 201711
|
||||
#else
|
||||
constexpr bool operator != (const color4_base& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
void operator *= (const color4_base<T>& rhs)
|
||||
{
|
||||
r *= rhs.r;
|
||||
g *= rhs.g;
|
||||
b *= rhs.b;
|
||||
a *= rhs.a;
|
||||
}
|
||||
|
||||
void operator *= (const T& rhs)
|
||||
{
|
||||
r *= rhs;
|
||||
g *= rhs;
|
||||
b *= rhs;
|
||||
a *= rhs;
|
||||
}
|
||||
|
||||
constexpr color4_base<T> operator * (const color4_base<T>& rhs) const
|
||||
{
|
||||
return { r * rhs.r, g * rhs.g, b * rhs.b, a * rhs.a };
|
||||
}
|
||||
|
||||
constexpr color4_base<T> operator * (const T& rhs) const
|
||||
{
|
||||
return { r * rhs, g * rhs, b * rhs, a * rhs };
|
||||
}
|
||||
|
||||
constexpr color4_base<T> operator + (const color4_base<T>& rhs) const
|
||||
{
|
||||
return { r + rhs.r, g + rhs.g, b + rhs.b, a + rhs.a };
|
||||
}
|
||||
|
||||
template<typename NT>
|
||||
constexpr operator color4_base<NT>() const
|
||||
explicit constexpr operator color4_base<NT>() const
|
||||
{
|
||||
return{ static_cast<NT>(x), static_cast<NT>(y), static_cast<NT>(z), static_cast<NT>(w) };
|
||||
}
|
||||
@@ -911,14 +944,16 @@ struct color3_base
|
||||
{
|
||||
return r == rhs.r && g == rhs.g && b == rhs.b;
|
||||
}
|
||||
|
||||
#if __cpp_impl_three_way_comparison >= 201711
|
||||
#else
|
||||
constexpr bool operator != (const color3_base& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename NT>
|
||||
constexpr operator color3_base<NT>() const
|
||||
explicit constexpr operator color3_base<NT>() const
|
||||
{
|
||||
return{ static_cast<NT>(x), static_cast<NT>(y), static_cast<NT>(z) };
|
||||
}
|
||||
@@ -954,13 +989,16 @@ struct color2_base
|
||||
return r == rhs.r && g == rhs.g;
|
||||
}
|
||||
|
||||
#if __cpp_impl_three_way_comparison >= 201711
|
||||
#else
|
||||
constexpr bool operator != (const color2_base& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename NT>
|
||||
constexpr operator color2_base<NT>() const
|
||||
explicit constexpr operator color2_base<NT>() const
|
||||
{
|
||||
return{ static_cast<NT>(x), static_cast<NT>(y) };
|
||||
}
|
||||
@@ -985,13 +1023,16 @@ struct color1_base
|
||||
return r == rhs.r;
|
||||
}
|
||||
|
||||
#if __cpp_impl_three_way_comparison >= 201711
|
||||
#else
|
||||
constexpr bool operator != (const color1_base& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename NT>
|
||||
constexpr operator color1_base<NT>() const
|
||||
explicit constexpr operator color1_base<NT>() const
|
||||
{
|
||||
return{ static_cast<NT>(x) };
|
||||
}
|
||||
|
||||
+16
-140
@@ -22,7 +22,7 @@ public:
|
||||
|
||||
~lf_array()
|
||||
{
|
||||
for (auto ptr = m_next.raw(); UNLIKELY(ptr);)
|
||||
for (auto ptr = m_next.raw(); ptr;)
|
||||
{
|
||||
delete std::exchange(ptr, std::exchange(ptr->m_next.raw(), nullptr));
|
||||
}
|
||||
@@ -30,14 +30,14 @@ public:
|
||||
|
||||
T& operator [](std::size_t index)
|
||||
{
|
||||
if (LIKELY(index < N))
|
||||
if (index < N) [[likely]]
|
||||
{
|
||||
return m_data[index];
|
||||
}
|
||||
else if (UNLIKELY(!m_next))
|
||||
else if (!m_next) [[unlikely]]
|
||||
{
|
||||
// Create new array block. It's not a full-fledged once-synchronization, unlikely needed.
|
||||
for (auto _new = new lf_array, ptr = this; UNLIKELY(ptr);)
|
||||
for (auto _new = new lf_array, ptr = this; ptr;)
|
||||
{
|
||||
// Install the pointer. If failed, go deeper.
|
||||
ptr = ptr->m_next.compare_and_swap(nullptr, _new);
|
||||
@@ -54,98 +54,50 @@ public:
|
||||
template<typename T, std::size_t N>
|
||||
class lf_fifo : public lf_array<T, N>
|
||||
{
|
||||
struct alignas(8) ctrl_t
|
||||
{
|
||||
u32 push;
|
||||
u32 pop;
|
||||
};
|
||||
|
||||
atomic_t<ctrl_t> m_ctrl{};
|
||||
// LSB 32-bit: push, MSB 32-bit: pop
|
||||
atomic_t<u64> m_ctrl{};
|
||||
|
||||
public:
|
||||
constexpr lf_fifo() = default;
|
||||
|
||||
// Get current "push" position
|
||||
// Get number of elements in the queue
|
||||
u32 size() const
|
||||
{
|
||||
return m_ctrl.load().push;
|
||||
const u64 ctrl = m_ctrl.load();
|
||||
return static_cast<u32>(ctrl - (ctrl >> 32));
|
||||
}
|
||||
|
||||
// Acquire the place for one or more elements.
|
||||
u32 push_begin(u32 count = 1)
|
||||
{
|
||||
return std::bit_cast<atomic_t<u64>*>(&m_ctrl)->fetch_add(count); // Hack
|
||||
return static_cast<u32>(m_ctrl.fetch_add(count));
|
||||
}
|
||||
|
||||
// Get current "pop" position
|
||||
u32 peek() const
|
||||
{
|
||||
return m_ctrl.load().pop;
|
||||
return static_cast<u32>(m_ctrl >> 32);
|
||||
}
|
||||
|
||||
// Acknowledge processed element, return number of the next one.
|
||||
// Perform clear if possible, zero is returned in this case.
|
||||
u32 pop_end(u32 count = 1)
|
||||
{
|
||||
return m_ctrl.atomic_op([&](ctrl_t& ctrl)
|
||||
return m_ctrl.atomic_op([&](u64& ctrl)
|
||||
{
|
||||
ctrl.pop += count;
|
||||
ctrl += u64{count} << 32;
|
||||
|
||||
if (ctrl.pop == ctrl.push)
|
||||
if (ctrl >> 32 == static_cast<u32>(ctrl))
|
||||
{
|
||||
// Clean if possible
|
||||
ctrl.push = 0;
|
||||
ctrl.pop = 0;
|
||||
ctrl = 0;
|
||||
}
|
||||
|
||||
return ctrl.pop;
|
||||
return static_cast<u32>(ctrl >> 32);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
//! Simple lock-free map. Based on lf_array<>. All elements are accessible, implicitly initialized.
|
||||
template<typename K, typename T, typename Hash = value_hash<K>, std::size_t Size = 256>
|
||||
class lf_hashmap
|
||||
{
|
||||
struct pair_t
|
||||
{
|
||||
// Default-constructed key means "no key"
|
||||
atomic_t<K> key{};
|
||||
T value{};
|
||||
};
|
||||
|
||||
//
|
||||
lf_array<pair_t, Size> m_data{};
|
||||
|
||||
// Value for default-constructed key
|
||||
T m_default_key_data{};
|
||||
|
||||
public:
|
||||
constexpr lf_hashmap() = default;
|
||||
|
||||
// Access element (added implicitly)
|
||||
T& operator [](const K& key)
|
||||
{
|
||||
if (UNLIKELY(key == K{}))
|
||||
{
|
||||
return m_default_key_data;
|
||||
}
|
||||
|
||||
// Calculate hash and array position
|
||||
for (std::size_t pos = Hash{}(key) % Size;; pos += Size)
|
||||
{
|
||||
// Access the array
|
||||
auto& pair = m_data[pos];
|
||||
|
||||
// Check the key value (optimistic)
|
||||
if (LIKELY(pair.key == key) || pair.key.compare_and_swap_test(K{}, key))
|
||||
{
|
||||
return pair.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Helper type, linked list element
|
||||
template <typename T>
|
||||
class lf_queue_item final
|
||||
@@ -536,79 +488,3 @@ public:
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
// Assignable lock-free thread-safe value of any type (memory-inefficient)
|
||||
template <typename T>
|
||||
class lf_value final
|
||||
{
|
||||
atomic_t<lf_value*> m_head;
|
||||
|
||||
T m_data;
|
||||
|
||||
public:
|
||||
template <typename... Args>
|
||||
explicit constexpr lf_value(Args&&... args)
|
||||
: m_head(this)
|
||||
, m_data(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
~lf_value()
|
||||
{
|
||||
// All values are kept in the queue until the end
|
||||
for (lf_value* ptr = m_head.load(); ptr != this;)
|
||||
{
|
||||
delete std::exchange(ptr, std::exchange(ptr->m_head.raw(), ptr));
|
||||
}
|
||||
}
|
||||
|
||||
// Get current head, allows to inspect old values
|
||||
[[nodiscard]] const lf_value* head() const
|
||||
{
|
||||
return m_head.load();
|
||||
}
|
||||
|
||||
// Inspect the initial (oldest) value
|
||||
[[nodiscard]] const T& first() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
[[nodiscard]] const T& get() const
|
||||
{
|
||||
return m_head.load()->m_data;
|
||||
}
|
||||
|
||||
[[nodiscard]] operator const T&() const
|
||||
{
|
||||
return m_head.load()->m_data;
|
||||
}
|
||||
|
||||
// Construct new value in-place
|
||||
template <typename... Args>
|
||||
const T& assign(Args&&... args)
|
||||
{
|
||||
lf_value* val = new lf_value(std::forward<Args>(args)...);
|
||||
lf_value* old = m_head.load();
|
||||
|
||||
do
|
||||
{
|
||||
val->m_head = old;
|
||||
}
|
||||
while (!m_head.compare_exchange(old, val));
|
||||
|
||||
return val->m_data;
|
||||
}
|
||||
|
||||
// Copy-assign new value
|
||||
const T& operator =(const T& value)
|
||||
{
|
||||
return assign(value);
|
||||
}
|
||||
|
||||
// Move-assign new value
|
||||
const T& operator =(T&& value)
|
||||
{
|
||||
return assign(std::move(value));
|
||||
}
|
||||
};
|
||||
|
||||
+15
-15
@@ -45,7 +45,7 @@ public:
|
||||
{
|
||||
const u32 value = m_value.load();
|
||||
|
||||
if (UNLIKELY(value >= c_one - 1 || !m_value.compare_and_swap_test(value, value + 1)))
|
||||
if (value >= c_one - 1 || !m_value.compare_and_swap_test(value, value + 1)) [[unlikely]]
|
||||
{
|
||||
imp_lock_shared(value);
|
||||
}
|
||||
@@ -55,10 +55,10 @@ public:
|
||||
{
|
||||
const u32 value = m_value.load();
|
||||
|
||||
if (LIKELY(value < c_one - 1))
|
||||
if (value < c_one - 1) [[likely]]
|
||||
{
|
||||
u32 old = value;
|
||||
if (LIKELY(atomic_storage<u32>::compare_exchange_hle_acq(m_value.raw(), old, value + 1)))
|
||||
if (atomic_storage<u32>::compare_exchange_hle_acq(m_value.raw(), old, value + 1)) [[likely]]
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
// Unconditional decrement (can result in broken state)
|
||||
const u32 value = m_value.fetch_sub(1);
|
||||
|
||||
if (UNLIKELY(value >= c_one))
|
||||
if (value >= c_one) [[unlikely]]
|
||||
{
|
||||
imp_unlock_shared(value);
|
||||
}
|
||||
@@ -82,7 +82,7 @@ public:
|
||||
{
|
||||
const u32 value = atomic_storage<u32>::fetch_add_hle_rel(m_value.raw(), -1);
|
||||
|
||||
if (UNLIKELY(value >= c_one))
|
||||
if (value >= c_one) [[unlikely]]
|
||||
{
|
||||
imp_unlock_shared(value);
|
||||
}
|
||||
@@ -100,7 +100,7 @@ public:
|
||||
{
|
||||
const u32 value = m_value.load();
|
||||
|
||||
if (UNLIKELY(value >= c_vip - 1 || !m_value.compare_and_swap_test(value, value + 1)))
|
||||
if (value >= c_vip - 1 || !m_value.compare_and_swap_test(value, value + 1)) [[unlikely]]
|
||||
{
|
||||
imp_lock_low(value);
|
||||
}
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
// Unconditional decrement (can result in broken state)
|
||||
const u32 value = m_value.fetch_sub(1);
|
||||
|
||||
if (UNLIKELY(value >= c_one))
|
||||
if (value >= c_one) [[unlikely]]
|
||||
{
|
||||
imp_unlock_low(value);
|
||||
}
|
||||
@@ -129,7 +129,7 @@ public:
|
||||
{
|
||||
const u32 value = m_value.load();
|
||||
|
||||
if (UNLIKELY((value >= c_one - 1 && !(value & (c_one - c_vip))) || (value % c_vip) || !m_value.compare_and_swap_test(value, value + c_vip)))
|
||||
if ((value >= c_one - 1 && !(value & (c_one - c_vip))) || (value % c_vip) || !m_value.compare_and_swap_test(value, value + c_vip)) [[unlikely]]
|
||||
{
|
||||
imp_lock_vip(value);
|
||||
}
|
||||
@@ -140,7 +140,7 @@ public:
|
||||
// Unconditional decrement (can result in broken state)
|
||||
const u32 value = m_value.fetch_sub(c_vip);
|
||||
|
||||
if (UNLIKELY(value >= c_one))
|
||||
if (value >= c_one) [[unlikely]]
|
||||
{
|
||||
imp_unlock_vip(value);
|
||||
}
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
{
|
||||
const u32 value = m_value.compare_and_swap(0, c_one);
|
||||
|
||||
if (UNLIKELY(value))
|
||||
if (value) [[unlikely]]
|
||||
{
|
||||
imp_lock(value);
|
||||
}
|
||||
@@ -165,7 +165,7 @@ public:
|
||||
{
|
||||
u32 value = 0;
|
||||
|
||||
if (UNLIKELY(!atomic_storage<u32>::compare_exchange_hle_acq(m_value.raw(), value, c_one)))
|
||||
if (!atomic_storage<u32>::compare_exchange_hle_acq(m_value.raw(), value, c_one)) [[unlikely]]
|
||||
{
|
||||
imp_lock(value);
|
||||
}
|
||||
@@ -176,7 +176,7 @@ public:
|
||||
// Unconditional decrement (can result in broken state)
|
||||
const u32 value = m_value.fetch_sub(c_one);
|
||||
|
||||
if (UNLIKELY(value != c_one))
|
||||
if (value != c_one) [[unlikely]]
|
||||
{
|
||||
imp_unlock(value);
|
||||
}
|
||||
@@ -186,7 +186,7 @@ public:
|
||||
{
|
||||
const u32 value = atomic_storage<u32>::fetch_add_hle_rel(m_value.raw(), 0u - c_one);
|
||||
|
||||
if (UNLIKELY(value != c_one))
|
||||
if (value != c_one) [[unlikely]]
|
||||
{
|
||||
imp_unlock(value);
|
||||
}
|
||||
@@ -202,7 +202,7 @@ public:
|
||||
|
||||
void lock_upgrade()
|
||||
{
|
||||
if (UNLIKELY(!try_lock_upgrade()))
|
||||
if (!try_lock_upgrade()) [[unlikely]]
|
||||
{
|
||||
imp_lock_upgrade();
|
||||
}
|
||||
@@ -223,7 +223,7 @@ public:
|
||||
// Optimized wait for lockability without locking, relaxed
|
||||
void lock_unlock()
|
||||
{
|
||||
if (UNLIKELY(m_value != 0))
|
||||
if (m_value != 0) [[unlikely]]
|
||||
{
|
||||
imp_lock_unlock();
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include <pugixml.hpp>
|
||||
#include <memory>
|
||||
|
||||
struct rXmlNode
|
||||
{
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ protected:
|
||||
const s32 value = m_value.load();
|
||||
|
||||
// Conditional decrement
|
||||
if (UNLIKELY(value <= 0 || !m_value.compare_and_swap_test(value, value - 1)))
|
||||
if (value <= 0 || !m_value.compare_and_swap_test(value, value - 1)) [[unlikely]]
|
||||
{
|
||||
imp_wait();
|
||||
}
|
||||
@@ -42,7 +42,7 @@ protected:
|
||||
// Unconditional increment
|
||||
const s32 value = m_value.fetch_add(1);
|
||||
|
||||
if (UNLIKELY(value < 0 || value >= _max))
|
||||
if (value < 0 || value >= _max) [[unlikely]]
|
||||
{
|
||||
imp_post(value);
|
||||
}
|
||||
|
||||
+36
-16
@@ -1,7 +1,7 @@
|
||||
#include "sysinfo.h"
|
||||
#include "StrFmt.h"
|
||||
#include "File.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/system_config.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
@@ -75,9 +75,8 @@ bool utils::has_clwb()
|
||||
return g_value;
|
||||
}
|
||||
|
||||
std::string utils::get_system_info()
|
||||
std::string utils::get_cpu_brand()
|
||||
{
|
||||
std::string result;
|
||||
std::string brand;
|
||||
|
||||
if (get_cpuid(0x80000000, 0)[0] >= 0x80000004)
|
||||
@@ -101,18 +100,16 @@ std::string utils::get_system_info()
|
||||
brand.erase(brand.begin() + found);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
::SYSTEM_INFO sysInfo;
|
||||
::GetNativeSystemInfo(&sysInfo);
|
||||
::MEMORYSTATUSEX memInfo;
|
||||
memInfo.dwLength = sizeof(memInfo);
|
||||
::GlobalMemoryStatusEx(&memInfo);
|
||||
const u32 num_proc = sysInfo.dwNumberOfProcessors;
|
||||
const u64 mem_total = memInfo.ullTotalPhys;
|
||||
#else
|
||||
const u32 num_proc = ::sysconf(_SC_NPROCESSORS_ONLN);
|
||||
const u64 mem_total = ::sysconf(_SC_PHYS_PAGES) * ::sysconf(_SC_PAGE_SIZE);
|
||||
#endif
|
||||
return brand;
|
||||
}
|
||||
|
||||
std::string utils::get_system_info()
|
||||
{
|
||||
std::string result;
|
||||
|
||||
const std::string brand = get_cpu_brand();
|
||||
const u64 mem_total = get_total_memory();
|
||||
const u32 num_proc = get_thread_count();
|
||||
|
||||
fmt::append(result, "%s | %d Threads | %.2f GiB RAM", brand, num_proc, mem_total / (1024.0f * 1024 * 1024));
|
||||
|
||||
@@ -189,7 +186,7 @@ std::string utils::get_firmware_version()
|
||||
|
||||
std::string utils::get_OS_version()
|
||||
{
|
||||
std::string output = "";
|
||||
std::string output;
|
||||
#ifdef _WIN32
|
||||
// GetVersionEx is deprecated, RtlGetVersion is kernel-mode only and AnalyticsInfo is UWP only.
|
||||
// So we're forced to read PEB instead to get Windows version info. It's ugly but works.
|
||||
@@ -242,3 +239,26 @@ ullong utils::get_tsc_freq()
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
u64 utils::get_total_memory()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
::MEMORYSTATUSEX memInfo;
|
||||
memInfo.dwLength = sizeof(memInfo);
|
||||
::GlobalMemoryStatusEx(&memInfo);
|
||||
return memInfo.ullTotalPhys;
|
||||
#else
|
||||
return ::sysconf(_SC_PHYS_PAGES) * ::sysconf(_SC_PAGE_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
u32 utils::get_thread_count()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
::SYSTEM_INFO sysInfo;
|
||||
::GetNativeSystemInfo(&sysInfo);
|
||||
return sysInfo.dwNumberOfProcessors;
|
||||
#else
|
||||
return ::sysconf(_SC_NPROCESSORS_ONLN);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ namespace utils
|
||||
|
||||
bool has_clwb();
|
||||
|
||||
std::string get_cpu_brand();
|
||||
|
||||
std::string get_system_info();
|
||||
|
||||
std::string get_firmware_version();
|
||||
@@ -54,4 +56,8 @@ namespace utils
|
||||
std::string get_OS_version();
|
||||
|
||||
ullong get_tsc_freq();
|
||||
|
||||
u64 get_total_memory();
|
||||
|
||||
u32 get_thread_count();
|
||||
}
|
||||
|
||||
+12
-12
@@ -658,7 +658,7 @@ namespace utils
|
||||
static_assert(!std::is_volatile_v<std::remove_reference_t<Type>>);
|
||||
|
||||
// Try to acquire the semaphore
|
||||
if (UNLIKELY(!head->m_sema.try_inc(last + 1)))
|
||||
if (!head->m_sema.try_inc(last + 1)) [[unlikely]]
|
||||
{
|
||||
block = nullptr;
|
||||
}
|
||||
@@ -671,7 +671,7 @@ namespace utils
|
||||
|
||||
if (block->m_type == 0 && block->m_mutex.try_lock())
|
||||
{
|
||||
if (LIKELY(block->m_type == 0))
|
||||
if (block->m_type == 0) [[likely]]
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -695,7 +695,7 @@ namespace utils
|
||||
{
|
||||
block = nullptr;
|
||||
}
|
||||
else if (UNLIKELY(block->m_type != 0))
|
||||
else if (block->m_type != 0) [[unlikely]]
|
||||
{
|
||||
block->m_mutex.unlock();
|
||||
block = nullptr;
|
||||
@@ -737,13 +737,13 @@ namespace utils
|
||||
block = reinterpret_cast<typemap_block*>(head->m_ptr + std::size_t{head->m_ssize} * unscaled);
|
||||
|
||||
// Check id range and type
|
||||
if (UNLIKELY(unscaled >= typeinfo_count<Type>::max_count || unbiased % step))
|
||||
if (unscaled >= typeinfo_count<Type>::max_count || unbiased % step) [[unlikely]]
|
||||
{
|
||||
block = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (UNLIKELY(block->m_type == 0))
|
||||
if (block->m_type == 0) [[unlikely]]
|
||||
{
|
||||
block = nullptr;
|
||||
}
|
||||
@@ -785,12 +785,12 @@ namespace utils
|
||||
}
|
||||
else if constexpr (std::is_invocable_r_v<bool, const Arg&, const Type&>)
|
||||
{
|
||||
if (UNLIKELY(!block))
|
||||
if (!block) [[unlikely]]
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (LIKELY(block->m_type))
|
||||
if (block->m_type) [[likely]]
|
||||
{
|
||||
if (std::invoke(std::forward<Arg>(id), std::as_const(*block->get_ptr<Type>())))
|
||||
{
|
||||
@@ -800,7 +800,7 @@ namespace utils
|
||||
}
|
||||
else if (block)
|
||||
{
|
||||
if (LIKELY(block->m_type))
|
||||
if (block->m_type) [[likely]]
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -848,7 +848,7 @@ namespace utils
|
||||
}
|
||||
else if constexpr (is_const || is_volatile)
|
||||
{
|
||||
if (LIKELY(block->m_mutex.is_lockable()))
|
||||
if (block->m_mutex.is_lockable()) [[likely]]
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -858,7 +858,7 @@ namespace utils
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LIKELY(block->m_mutex.is_free()))
|
||||
if (block->m_mutex.is_free()) [[likely]]
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -878,7 +878,7 @@ namespace utils
|
||||
if constexpr (I + 1 < N)
|
||||
{
|
||||
// Proceed recursively
|
||||
if (LIKELY(try_lock<I + 1, Types...>(array, locked, std::integer_sequence<bool, Locks...>{})))
|
||||
if (try_lock<I + 1, Types...>(array, locked, std::integer_sequence<bool, Locks...>{})) [[likely]]
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -973,7 +973,7 @@ namespace utils
|
||||
while (true)
|
||||
{
|
||||
const uint locked = lock_array<decode_t<Types>...>(result, seq_t{}, locks_t{});
|
||||
if (LIKELY(try_lock<0, decode_t<Types>...>(result, locked, locks_t{})))
|
||||
if (try_lock<0, decode_t<Types>...>(result, locked, locks_t{})) [[likely]]
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+86
-23
@@ -17,9 +17,9 @@
|
||||
#include <limits>
|
||||
#include <array>
|
||||
|
||||
// Assume little-endian
|
||||
#define IS_LE_MACHINE 1
|
||||
#define IS_BE_MACHINE 0
|
||||
#if __has_include(<bit>)
|
||||
#include <bit>
|
||||
#endif
|
||||
|
||||
#ifndef __has_builtin
|
||||
#define __has_builtin(x) 0
|
||||
@@ -28,8 +28,6 @@
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#define ASSUME(...) __assume(__VA_ARGS__) // MSVC __assume ignores side-effects
|
||||
#define LIKELY
|
||||
#define UNLIKELY
|
||||
#define SAFE_BUFFERS __declspec(safebuffers)
|
||||
#define NEVER_INLINE __declspec(noinline)
|
||||
#define FORCE_INLINE __forceinline
|
||||
@@ -48,8 +46,6 @@
|
||||
#define ASSUME(...) do { if (!(__VA_ARGS__)) __builtin_unreachable(); } while (0) // note: the compiler will generate code to evaluate "cond" if the expression is opaque
|
||||
#endif
|
||||
|
||||
#define LIKELY(...) __builtin_expect(!!(__VA_ARGS__), 1)
|
||||
#define UNLIKELY(...) __builtin_expect(!!(__VA_ARGS__), 0)
|
||||
#define SAFE_BUFFERS
|
||||
#define NEVER_INLINE __attribute__((noinline))
|
||||
#define FORCE_INLINE __attribute__((always_inline)) inline
|
||||
@@ -86,7 +82,7 @@
|
||||
#define AUDIT(...) ((void)0)
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_lib_bit_cast) && (__cpp_lib_bit_cast >= 201806L)
|
||||
#if __cpp_lib_bit_cast >= 201806L
|
||||
#include <bit>
|
||||
#else
|
||||
namespace std
|
||||
@@ -413,6 +409,48 @@ struct alignas(16) s128
|
||||
CHECK_SIZE_ALIGN(u128, 16, 16);
|
||||
CHECK_SIZE_ALIGN(s128, 16, 16);
|
||||
|
||||
// Return magic value for any unsigned type
|
||||
constexpr inline struct umax_helper
|
||||
{
|
||||
constexpr umax_helper() noexcept = default;
|
||||
|
||||
template <typename T, typename S = simple_t<T>, typename = std::enable_if_t<std::is_unsigned_v<S>>>
|
||||
explicit constexpr operator T() const
|
||||
{
|
||||
return std::numeric_limits<S>::max();
|
||||
}
|
||||
|
||||
template <typename T, typename S = simple_t<T>, typename = std::enable_if_t<std::is_unsigned_v<S>>>
|
||||
constexpr bool operator==(const T& rhs) const
|
||||
{
|
||||
return rhs == std::numeric_limits<S>::max();
|
||||
}
|
||||
|
||||
#if __cpp_impl_three_way_comparison >= 201711 && !__INTELLISENSE__
|
||||
#else
|
||||
template <typename T>
|
||||
friend constexpr std::enable_if_t<std::is_unsigned_v<simple_t<T>>, bool> operator==(const T& lhs, const umax_helper& rhs)
|
||||
{
|
||||
return lhs == std::numeric_limits<simple_t<T>>::max();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if __cpp_impl_three_way_comparison >= 201711
|
||||
#else
|
||||
template <typename T, typename S = simple_t<T>, typename = std::enable_if_t<std::is_unsigned_v<S>>>
|
||||
constexpr bool operator!=(const T& rhs) const
|
||||
{
|
||||
return rhs != std::numeric_limits<S>::max();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
friend constexpr std::enable_if_t<std::is_unsigned_v<simple_t<T>>, bool> operator!=(const T& lhs, const umax_helper& rhs)
|
||||
{
|
||||
return lhs != std::numeric_limits<simple_t<T>>::max();
|
||||
}
|
||||
#endif
|
||||
} umax;
|
||||
|
||||
using f32 = float;
|
||||
using f64 = double;
|
||||
|
||||
@@ -534,31 +572,56 @@ constexpr u32 to_u8(char c)
|
||||
return static_cast<u8>(c);
|
||||
}
|
||||
|
||||
// Convert 2-byte string to u16 value like reinterpret_cast does
|
||||
// Convert 1-2-byte string to u16 value like reinterpret_cast does
|
||||
constexpr u16 operator""_u16(const char* s, std::size_t /*length*/)
|
||||
{
|
||||
return
|
||||
#if IS_LE_MACHINE == 1
|
||||
static_cast<u16>(to_u8(s[1]) << 8 | to_u8(s[0]));
|
||||
#endif
|
||||
if constexpr (std::endian::little == std::endian::native)
|
||||
{
|
||||
return static_cast<u16>(to_u8(s[1]) << 8 | to_u8(s[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
return static_cast<u16>(to_u8(s[0]) << 8 | to_u8(s[1]));
|
||||
}
|
||||
}
|
||||
|
||||
// Convert 4-byte string to u32 value like reinterpret_cast does
|
||||
// Convert 3-4-byte string to u32 value like reinterpret_cast does
|
||||
constexpr u32 operator""_u32(const char* s, std::size_t /*length*/)
|
||||
{
|
||||
return
|
||||
#if IS_LE_MACHINE == 1
|
||||
to_u8(s[3]) << 24 | to_u8(s[2]) << 16 | to_u8(s[1]) << 8 | to_u8(s[0]);
|
||||
#endif
|
||||
if constexpr (std::endian::little == std::endian::native)
|
||||
{
|
||||
return to_u8(s[3]) << 24 | to_u8(s[2]) << 16 | to_u8(s[1]) << 8 | to_u8(s[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return to_u8(s[0]) << 24 | to_u8(s[1]) << 16 | to_u8(s[2]) << 8 | to_u8(s[3]);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert 8-byte string to u64 value like reinterpret_cast does
|
||||
// Convert 5-6-byte string to u64 value like reinterpret_cast does
|
||||
constexpr u64 operator""_u48(const char* s, std::size_t /*length*/)
|
||||
{
|
||||
if constexpr (std::endian::little == std::endian::native)
|
||||
{
|
||||
return static_cast<u64>(to_u8(s[5]) << 8 | to_u8(s[4])) << 32 | to_u8(s[3]) << 24 | to_u8(s[2]) << 16 | to_u8(s[1]) << 8 | to_u8(s[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return static_cast<u64>(to_u8(s[0]) << 8 | to_u8(s[1])) << 32 | to_u8(s[2]) << 24 | to_u8(s[3]) << 16 | to_u8(s[4]) << 8 | to_u8(s[5]);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert 7-8-byte string to u64 value like reinterpret_cast does
|
||||
constexpr u64 operator""_u64(const char* s, std::size_t /*length*/)
|
||||
{
|
||||
return
|
||||
#if IS_LE_MACHINE == 1
|
||||
static_cast<u64>(to_u8(s[7]) << 24 | to_u8(s[6]) << 16 | to_u8(s[5]) << 8 | to_u8(s[4])) << 32 | to_u8(s[3]) << 24 | to_u8(s[2]) << 16 | to_u8(s[1]) << 8 | to_u8(s[0]);
|
||||
#endif
|
||||
if constexpr (std::endian::little == std::endian::native)
|
||||
{
|
||||
return static_cast<u64>(to_u8(s[7]) << 24 | to_u8(s[6]) << 16 | to_u8(s[5]) << 8 | to_u8(s[4])) << 32 | to_u8(s[3]) << 24 | to_u8(s[2]) << 16 | to_u8(s[1]) << 8 | to_u8(s[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return static_cast<u64>(to_u8(s[0]) << 24 | to_u8(s[1]) << 16 | to_u8(s[2]) << 8 | to_u8(s[3])) << 32 | to_u8(s[4]) << 24 | to_u8(s[5]) << 16 | to_u8(s[6]) << 8 | to_u8(s[7]);
|
||||
}
|
||||
}
|
||||
|
||||
namespace fmt
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
set(BUILD_EXTERNAL OFF CACHE BOOL "Build external dependencies in /External" FORCE)
|
||||
set(SKIP_GLSLANG_INSTALL ON CACHE BOOL "Skip installation" FORCE)
|
||||
set(ENABLE_SPVREMAPPER OFF CACHE BOOL "Enables building of SPVRemapper" FORCE)
|
||||
set(ENABLE_GLSLANG_BINARIES OFF CACHE BOOL "Builds glslangValidator and spirv-remap" FORCE)
|
||||
set(ENABLE_OPT OFF CACHE BOOL "Enables spirv-opt capability if present" FORCE)
|
||||
set(ENABLE_HLSL OFF CACHE BOOL "Enables HLSL input support" FORCE)
|
||||
set(ENABLE_AMD_EXTENSIONS ON CACHE BOOL "Enables support of AMD-specific extensions" FORCE)
|
||||
set(ENABLE_NV_EXTENSIONS ON CACHE BOOL "Enables support of Nvidia-specific extensions" FORCE)
|
||||
set(ENABLE_OPT OFF CACHE BOOL "Enables spirv-opt capability if present" FORCE)
|
||||
set(ENABLE_CTEST OFF CACHE BOOL "Enables testing" FORCE)
|
||||
add_subdirectory(glslang)
|
||||
|
||||
+1
-1
Submodule Vulkan/glslang updated: 7f77b2e866...ae59435606
@@ -41,24 +41,24 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<NMakeBuildCommandLine>cmake -G $(CmakeGenerator) -A x64 -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Release /m</NMakeBuildCommandLine>
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Release /p:ForceImportBeforeCppTargets=$(SolutionDir)rpcs3_glslang.props /m</NMakeBuildCommandLine>
|
||||
<NMakeReBuildCommandLine>cmake -G $(CmakeGenerator) -A x64 -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release /m</NMakeReBuildCommandLine>
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release /p:ForceImportBeforeCppTargets=$(SolutionDir)rpcs3_glslang.props /m</NMakeReBuildCommandLine>
|
||||
<NMakeCleanCommandLine>cmake -G $(CmakeGenerator) -A x64 -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Release /m</NMakeCleanCommandLine>
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Release /p:ForceImportBeforeCppTargets=$(SolutionDir)rpcs3_glslang.props /m</NMakeCleanCommandLine>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<NMakeBuildCommandLine>
|
||||
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Debug /m
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Debug /p:ForceImportBeforeCppTargets=$(SolutionDir)rpcs3_glslang.props /m
|
||||
</NMakeBuildCommandLine>
|
||||
<NMakeReBuildCommandLine>
|
||||
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug /m
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug /p:ForceImportBeforeCppTargets=$(SolutionDir)rpcs3_glslang.props /m
|
||||
</NMakeReBuildCommandLine>
|
||||
<NMakeCleanCommandLine>
|
||||
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug /m
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug /p:ForceImportBeforeCppTargets=$(SolutionDir)rpcs3_glslang.props /m
|
||||
</NMakeCleanCommandLine>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
|
||||
+2
-6
@@ -4,10 +4,9 @@ version: '{build}'
|
||||
image: Visual Studio 2019
|
||||
|
||||
environment:
|
||||
QTDIR: C:\Qt\5.13\msvc2017_64
|
||||
QT_URL: https://cdn.discordapp.com/attachments/442667232489897997/614126952953020416/msvc2017_64.7z
|
||||
QTDIR: C:\Qt\5.14\msvc2017_64
|
||||
LLVMLIBS: https://github.com/RPCS3/llvm/releases/download/continuous-master/llvmlibs.7z
|
||||
GLSLANG: https://www.dropbox.com/s/ku2qgwmtfptzbvx/glslang.7z?dl=1
|
||||
GLSLANG: https://www.dropbox.com/s/6e8w6t5dxh3ad4l/glslang.7z?dl=1
|
||||
COMPATDB: https://rpcs3.net/compatibility?api=v1&export
|
||||
VULKAN_SDK: "C:\\VulkanSDK\\1.1.126.0"
|
||||
VULKAN_SDK_URL: https://sdk.lunarg.com/sdk/download/1.1.126.0/windows/VulkanSDK-1.1.126.0-Installer.exe
|
||||
@@ -17,7 +16,6 @@ cache:
|
||||
- glslang.7z -> appveyor.yml
|
||||
- compat_database.dat
|
||||
- vulkan-sdk.exe -> appveyor.yml
|
||||
- msvc2017_64.7z -> appveyor.yml
|
||||
|
||||
install:
|
||||
- ps: | # set env vars for versioning
|
||||
@@ -76,10 +74,8 @@ before_build:
|
||||
)
|
||||
if (!(test-path llvmlibs.7z)) { irm $env:LLVMLIBS -outfile llvmlibs.7z }
|
||||
if (!(test-path glslang.7z)) { irm $env:GLSLANG -outfile glslang.7z }
|
||||
if (!(test-path msvc2017_64.7z)) { irm $env:QT_URL -outfile msvc2017_64.7z }
|
||||
7z x llvmlibs.7z -aos -o"." | out-null
|
||||
7z x glslang.7z -aos -o".\lib\$env:CONFIGURATION-$env:PLATFORM" | out-null
|
||||
7z x msvc2017_64.7z -aos -o"C:\Qt\5.13" | out-null
|
||||
if (!(test-path vulkan-sdk.exe))
|
||||
{
|
||||
foreach ($url in $VULKAN_SDK_URLS) {
|
||||
|
||||
@@ -80,14 +80,14 @@ QToolTip {
|
||||
}
|
||||
|
||||
|
||||
/* CG Disasm: background-image doesn't work, use static color */
|
||||
QWidget#cg_disasm {
|
||||
/* CG Disasm and Trophy Manager: background-image doesn't work, use static color */
|
||||
QWidget#cg_disasm, QWidget#trophy_manager {
|
||||
background: #b3ac98;
|
||||
}
|
||||
|
||||
|
||||
/* Main Window, Dialogs and Trophy Manager which isn't a dialog */
|
||||
QDialog, QWidget#trophy_manager, QMainWindow#main_window {
|
||||
/* Main Window and Dialogs */
|
||||
QDialog, QMainWindow#main_window {
|
||||
border-image: url("GuiConfigs/YoRHa-background.jpg");
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -8,8 +8,12 @@
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<AdditionalOptions>-d2FH4- %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalOptions>-d2:-FH4- %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup />
|
||||
</Project>
|
||||
+1
-1
Submodule llvm updated: 2e038bff10...1394b1ccc8
@@ -110,11 +110,13 @@ else()
|
||||
target_link_libraries(rpcs3 ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
|
||||
set_target_properties(rpcs3 PROPERTIES
|
||||
COTIRE_CXX_PREFIX_HEADER_INIT "${RPCS3_SRC_DIR}/stdafx.h"
|
||||
COTIRE_ADD_UNITY_BUILD OFF)
|
||||
if(USE_COTIRE)
|
||||
set_target_properties(rpcs3 PROPERTIES
|
||||
COTIRE_CXX_PREFIX_HEADER_INIT "${RPCS3_SRC_DIR}/stdafx.h"
|
||||
COTIRE_ADD_UNITY_BUILD OFF)
|
||||
|
||||
cotire(rpcs3)
|
||||
cotire(rpcs3)
|
||||
endif()
|
||||
|
||||
# Copy icons to executable directory
|
||||
if(APPLE)
|
||||
|
||||
+110
-107
@@ -1,12 +1,15 @@
|
||||
#include "utils.h"
|
||||
#include "utils.h"
|
||||
#include "aes.h"
|
||||
#include "key_vault.h"
|
||||
|
||||
SELF_KEY::SELF_KEY(u64 ver, u16 rev, u32 type, const std::string& e, const std::string& r, const std::string& pb, const std::string& pr, u32 ct)
|
||||
LOG_CHANNEL(key_vault_log, "KEY_VAULT");
|
||||
|
||||
SELF_KEY::SELF_KEY(u64 ver_start, u64 ver_end, u16 rev, u32 type, const std::string& e, const std::string& r, const std::string& pb, const std::string& pr, u32 ct)
|
||||
{
|
||||
version = ver;
|
||||
revision = rev;
|
||||
self_type = type;
|
||||
version_start = ver_start;
|
||||
version_end = ver_end;
|
||||
revision = rev;
|
||||
self_type = type;
|
||||
hex_to_bytes(erk, e.c_str(), 0);
|
||||
hex_to_bytes(riv, r.c_str(), 0);
|
||||
hex_to_bytes(pub, pb.c_str(), 0);
|
||||
@@ -21,7 +24,7 @@ KeyVault::KeyVault()
|
||||
void KeyVault::LoadSelfLV0Keys()
|
||||
{
|
||||
sk_LV0_arr.clear();
|
||||
sk_LV0_arr.emplace_back(0x0000000000000000, 0x0000, KEY_LV0,
|
||||
sk_LV0_arr.emplace_back(0x0000000000000000, 0x0000000000000000, 0x0000, KEY_LV0,
|
||||
"CA7A24EC38BDB45B98CCD7D363EA2AF0C326E65081E0630CB9AB2D215865878A",
|
||||
"F9205F46F6021697E670F13DFA726212",
|
||||
"A8FD6DB24532D094EFA08CB41C9A72287D905C6B27B42BE4AB925AAF4AFFF34D41EEB54DD128700D",
|
||||
@@ -32,7 +35,7 @@ void KeyVault::LoadSelfLV0Keys()
|
||||
void KeyVault::LoadSelfLDRKeys()
|
||||
{
|
||||
sk_LDR_arr.clear();
|
||||
sk_LDR_arr.emplace_back(0x0000000000000000, 0x0000, KEY_LDR,
|
||||
sk_LDR_arr.emplace_back(0x0000000000000000, 0x0000000000000000, 0x0000, KEY_LDR,
|
||||
"C0CEFE84C227F75BD07A7EB846509F93B238E770DACB9FF4A388F812482BE21B",
|
||||
"47EE7454E4774CC9B8960C7B59F4C14D",
|
||||
"C2D4AAF319355019AF99D44E2B58CA29252C89123D11D6218F40B138CAB29B7101F3AEB72A975019",
|
||||
@@ -43,61 +46,61 @@ void KeyVault::LoadSelfLDRKeys()
|
||||
void KeyVault::LoadSelfLV1Keys()
|
||||
{
|
||||
sk_LV1_arr.clear();
|
||||
sk_LV1_arr.emplace_back(0x0003003000000000, 0x0000, KEY_LV1,
|
||||
sk_LV1_arr.emplace_back(0x0003000000000000, 0x0003003100000000, 0x0000, KEY_LV1,
|
||||
"B9F3F9E6107CFF2680A91E118C2403CF4A6F18F3C7EFD7D13D1AC4DB760BD222",
|
||||
"B43661B9A79BAD9D8E2B046469CDA1E7",
|
||||
"4C870BE86DDD996A92A3F7F404F33604244A1D02AB5B78BC9DAF030B78BE8867CF586171B7D45D20",
|
||||
"002CC736C7AD06D264E9AB663EB1F35F5DC159248C",
|
||||
0x33);
|
||||
sk_LV1_arr.emplace_back(0x0003004200000000, 0x0000, KEY_LV1,
|
||||
sk_LV1_arr.emplace_back(0x0003004000000000, 0x0003004200000000, 0x0000, KEY_LV1,
|
||||
"B880593856C8C6D2037585626A12977F50DCFCF3F132D2C89AA6E670EAFC1646",
|
||||
"A79B05D4E37B8117A95E6E7C14FB640E",
|
||||
"7454C7CCBFC2F66C142D78A730A3A6F973CC0FB75A46FCBB390790138910A0CAC78E5E21F4DA3375",
|
||||
"00033A699FDD2DA6CDD6CCC03B2C6145F998706F74",
|
||||
0x34);
|
||||
sk_LV1_arr.emplace_back(0x0003005000000000, 0x0000, KEY_LV1,
|
||||
sk_LV1_arr.emplace_back(0x0003005000000000, 0x0003005000000000, 0x0000, KEY_LV1,
|
||||
"1E8EEEA9E80A729F3FA52CF523B25941EA44B4155D94E5DADC5C5A77847620C7",
|
||||
"E034D31A80316960024D1B3D3164FDC3",
|
||||
"7E3A196f4A5879F3A7B091A2263F7C24E1716129B580566D308D9C2254B36AEE53DEF30EC85F8398",
|
||||
"005815D17125D04C33790321DE29EB6241365100B5",
|
||||
0x35);
|
||||
sk_LV1_arr.emplace_back(0x0003005500000000, 0x0000, KEY_LV1,
|
||||
sk_LV1_arr.emplace_back(0x0003005500000000, 0x0003005500000000, 0x0000, KEY_LV1,
|
||||
"53ABDF84BE08B0351B734F2B97D2BE1621BC6C889E4362E5C70F39D6C3ED9F23",
|
||||
"44E652661AC7584DBE08ECB810FB5FC0",
|
||||
"733198A7759BC07326755BC9773A8A17C8A7043C7BDAB83D88E230512E2EA3852D7DA4263A7E97F9",
|
||||
"004312C65347ACBE95CC306442FEFD0AF4C2935EB3",
|
||||
0x05);
|
||||
sk_LV1_arr.emplace_back(0x0003005600000000, 0x0000, KEY_LV1,
|
||||
sk_LV1_arr.emplace_back(0x0003005600000000, 0x0003005600000000, 0x0000, KEY_LV1,
|
||||
"48793EBDDA1AF65D737DA2FDA2DD104447A698F8A82CAAEE992831711BA94E83",
|
||||
"15DCF3C67147A45D09DE7521EECA07A1",
|
||||
"85A8868C320127F10B6598964C69221C086702021D31803520E21FDE4DBE827766BE41825CB7328C",
|
||||
"",
|
||||
0x07);
|
||||
sk_LV1_arr.emplace_back(0x0003006100000000, 0x0000, KEY_LV1,
|
||||
sk_LV1_arr.emplace_back(0x0003006000000000, 0x0003006100000000, 0x0000, KEY_LV1,
|
||||
"5FF17D836E2C4AD69476E2614F64BDD05B9115389A9A6D055B5B544B1C34E3D5",
|
||||
"DF0F50EC3C4743C5B17839D7B49F24A4",
|
||||
"1CDABE30833823F461CA534104115FFF60010B710631E435A7D915E82AE88EDE667264656CB7062E",
|
||||
"",
|
||||
0x05);
|
||||
sk_LV1_arr.emplace_back(0x0003006600000000, 0x0000, KEY_LV1,
|
||||
sk_LV1_arr.emplace_back(0x0003006500000000, 0x0003006600000000, 0x0000, KEY_LV1,
|
||||
"BD0621FA19383C3C72ECBC3B008F1CD55FFD7C3BB7510BF11AD0CF0FC2B70951",
|
||||
"569AF3745E1E02E3E288273CDE244CD8",
|
||||
"21E26F11C2D69478609DD1BD278CDFC940D90386455BA52FCD1FA7E27AC2AFA826C79A10193B625C",
|
||||
"",
|
||||
0x07);
|
||||
sk_LV1_arr.emplace_back(0x0003007400000000, 0x0000, KEY_LV1,
|
||||
sk_LV1_arr.emplace_back(0x0003007000000000, 0x0003007400000000, 0x0000, KEY_LV1,
|
||||
"41A6E0039041E9D8AAF4EF2F2A2971248EDBD96A3985611ED7B4CE73EE4804FE",
|
||||
"C8C98D5A5CE23AF5607A352AECACB0DC",
|
||||
"4389664390265F96C1A882374C0F856364E33DB09BE124A4666F9A12F0DD9C811EDD55BA21ED0667",
|
||||
"",
|
||||
0x12);
|
||||
sk_LV1_arr.emplace_back(0x0004001100000000, 0x0000, KEY_LV1,
|
||||
sk_LV1_arr.emplace_back(0x0004000000000000, 0x0004001100000000, 0x0000, KEY_LV1,
|
||||
"557EDF6C063F3272B0D44EEC12F418DA774815B5415597CC5F75C21E048BAD74",
|
||||
"7144D7574937818517826227EF4AC0B4",
|
||||
"085D38DBF9B757329EB862107929909D32FA1DAE60641BF4AC25319D7650597EE977F8E810FEEA96",
|
||||
"",
|
||||
0x13);
|
||||
sk_LV1_arr.emplace_back(0x0004005000000000, 0x0000, KEY_LV1,
|
||||
sk_LV1_arr.emplace_back(0x0004002000000000, 0xFFFFFFFFFFFFFFFF, 0x0000, KEY_LV1,
|
||||
"10CEA04973FCCC12EC19924510822D8D4C41F657FD3D7E73F415A8D687421BCD",
|
||||
"ED8699562C6AC65204FA166257E7FCF4",
|
||||
"9AF86FC869C159FBB62F7D9674EE257ABF12E5A96D5875B4AA73C13C2BC13E2A4079F98B9B935EE2",
|
||||
@@ -108,61 +111,61 @@ void KeyVault::LoadSelfLV1Keys()
|
||||
void KeyVault::LoadSelfLV2Keys()
|
||||
{
|
||||
sk_LV2_arr.clear();
|
||||
sk_LV2_arr.emplace_back(0x0003003000000000, 0x0000, KEY_LV2,
|
||||
sk_LV2_arr.emplace_back(0x0000000300000000, 0x0003003100000000, 0x0000, KEY_LV2,
|
||||
"94303F69513572AB5AE17C8C2A1839D2C24C28F65389D3BBB11894CE23E0798F",
|
||||
"9769BFD187B90990AE5FEA4E110B9CF5",
|
||||
"AFAF5E96AF396CBB69071082C46A8F34A030E8EDB799E0A7BE00AA264DFF3AEBF7923920D559404D",
|
||||
"0070ABF9361B02291829D479F56AB248203CD3EB46",
|
||||
0x20);
|
||||
sk_LV2_arr.emplace_back(0x0003004200000000, 0x0000, KEY_LV2,
|
||||
sk_LV2_arr.emplace_back(0x0003004000000000, 0x0003004200000000, 0x0000, KEY_LV2,
|
||||
"575B0A6C4B4F2760A03FE4189EBAF4D947279FD982B14070349098B08FF92C10",
|
||||
"411CB18F460CE50CAF2C426D8F0D93C8",
|
||||
"3FEE313954CB3039C321A7E33B97FFDEC8988A8B55759161B04DBF4731284E4A8191E3F17D32B0EA",
|
||||
"0073076441A08CD179E5FACE349B86DA58B5B7BA78",
|
||||
0x21);
|
||||
sk_LV2_arr.emplace_back(0x0003005000000000, 0x0000, KEY_LV2,
|
||||
sk_LV2_arr.emplace_back(0x0003005000000000, 0x0003005000000000, 0x0000, KEY_LV2,
|
||||
"6DBD48D787C58803A8D724DA5ACF04FF8FCE91D7545D2322F2B7ABF57014AF68",
|
||||
"603A36213708520ED5D745DEC1325BA5",
|
||||
"5888CB83AC3CCA9610BC173C53141C0CA58B93719E744660CA8823D5EAEE8F9BF736997054E4B7E3",
|
||||
"0009EBC3DE442FA5FBF6C4F3D4F9EAB07778A142BD",
|
||||
0x22);
|
||||
sk_LV2_arr.emplace_back(0x0003005500000000, 0x0000, KEY_LV2,
|
||||
sk_LV2_arr.emplace_back(0x0003005500000000, 0x0003005500000000, 0x0000, KEY_LV2,
|
||||
"84015E90FA23139628A3C75CC09714E6427B527A82D18ABC3E91CD8D7DDAFF17",
|
||||
"5B240444D645F2038118F97FD5A145D5",
|
||||
"B266318245266B2D33641CD8A864066D077FAC60B7E27399099A70A683454B70F9888E7CC0C2BF72",
|
||||
"009D4CBA2BFB1A8330D3E20E59D281D476D231C73A",
|
||||
0x32);
|
||||
sk_LV2_arr.emplace_back(0x0003005600000000, 0x0000, KEY_LV2,
|
||||
sk_LV2_arr.emplace_back(0x0003005600000000, 0x0003005600000000, 0x0000, KEY_LV2,
|
||||
"EAE15444048EFDE7A831BFA9F5D96F047C9FCFF50723E292CF50F5417D81E359",
|
||||
"9CA9282DC7FA9F315EF3156D970B7CD4",
|
||||
"0D58938CB47598A6A672874F1768068F8B80D8D17014D2ABEBAC85E5B0993D9FB6F307DDC3DDA699",
|
||||
"",
|
||||
0x33);
|
||||
sk_LV2_arr.emplace_back(0x0003006100000000, 0x0000, KEY_LV2,
|
||||
sk_LV2_arr.emplace_back(0x0003006000000000, 0x0003006100000000, 0x0000, KEY_LV2,
|
||||
"88AD367EDEC2FEED3E2F99B1C685075C41BDEC90C84F526CAF588F89BBD1CBCC",
|
||||
"8D18E8E525230E63DE10291C9DD615BF",
|
||||
"86EED1D65E58890ABDA9ACA486A2BDDB9C0A529C2053FAE301F0F698EAF443DA0F60595A597A7027",
|
||||
"",
|
||||
0x32);
|
||||
sk_LV2_arr.emplace_back(0x0003006600000000, 0x0000, KEY_LV2,
|
||||
sk_LV2_arr.emplace_back(0x0003006500000000, 0x0003006600000000, 0x0000, KEY_LV2,
|
||||
"688D5FCAC6F4EA35AC6AC79B10506007286131EE038116DB8AA2C0B0340D9FB0",
|
||||
"75E0239D18B0B669EAE650972F99726B",
|
||||
"008E1C820AC567D1BFB8FE3CC6AD2E1845A1D1B19ED2E18B18CA34A8D28A83EC60C63859CDB3DACA",
|
||||
"",
|
||||
0x33);
|
||||
sk_LV2_arr.emplace_back(0x0003007400000000, 0x0000, KEY_LV2,
|
||||
sk_LV2_arr.emplace_back(0x0003007000000000, 0x0003007400000000, 0x0000, KEY_LV2,
|
||||
"E81C5B04C29FB079A4A2687A39D4EA97BFB49D80EF546CEB292979A5F77A6254",
|
||||
"15058FA7F2CAD7C528B5F605F6444EB0",
|
||||
"438D0E5C1E7AFB18234DB6867472FF5F52B750F30C379C7DD1EE0FD23E417B3EA819CC01BAC480ED",
|
||||
"",
|
||||
0x11);
|
||||
sk_LV2_arr.emplace_back(0x0004001100000000, 0x0000, KEY_LV2,
|
||||
sk_LV2_arr.emplace_back(0x0004001000000000, 0x0004001100000000, 0x0000, KEY_LV2,
|
||||
"A1E4B86ED02BF7F1372A2C73FE02BC738907EB37CE3BA605FE783C999FAFDB97",
|
||||
"BBE7799B9A37CB272E386618FDFD4AEC",
|
||||
"5B31A8E2A663EBD673196E2E1022E0D64988C4E1BBFE5E474415883A3BA0D9C562A2BE9C30E9B4A8",
|
||||
"",
|
||||
0x07);
|
||||
sk_LV2_arr.emplace_back(0x0004005000000000, 0x0000, KEY_LV2,
|
||||
sk_LV2_arr.emplace_back(0x0004002000000000, 0xFFFFFFFFFFFFFFFF, 0x0000, KEY_LV2,
|
||||
"0CAF212B6FA53C0DA7E2C575ADF61DBE68F34A33433B1B891ABF5C4251406A03",
|
||||
"9B79374722AD888EB6A35A2DF25A8B3E",
|
||||
"1034A6F98AF6625CC3E3604B59B971CA617DF337538D2179EBB22F3BDC9D0C6DA56BA7DDFD205A50",
|
||||
@@ -173,79 +176,79 @@ void KeyVault::LoadSelfLV2Keys()
|
||||
void KeyVault::LoadSelfISOKeys()
|
||||
{
|
||||
sk_ISO_arr.clear();
|
||||
sk_ISO_arr.emplace_back(0x0003003000000000, 0x0001, KEY_ISO,
|
||||
sk_ISO_arr.emplace_back(0x0000006000000000, 0x0003003000000000, 0x0001, KEY_ISO,
|
||||
"8860D0CFF4D0DC688D3223321B96B59A777E6914961488E07048DAECB020ECA4",
|
||||
"C82D015D46CF152F1DD0C16F18B5B1E5",
|
||||
"733918D7C888130509346E6B4A8B6CAA357AB557E814E8122BF102C14A314BF9475B9D70EAF9EC29",
|
||||
"009BE892E122A5C943C1BB7403A67318AA9E1B286F",
|
||||
0x36);
|
||||
sk_ISO_arr.emplace_back(0x0003004200000000, 0x0001, KEY_ISO,
|
||||
sk_ISO_arr.emplace_back(0x0003004000000000, 0x0003004200000000, 0x0001, KEY_ISO,
|
||||
"101E27F3FA2FB53ACA924F783AD553162D56B975D05B81351A1111799F20254D",
|
||||
"8D2E9C6297B8AD252998458296AC773C",
|
||||
"138446EE0BDDA5638F97328C8956E6489CBBFE57C5961D40DD5C43BB4138F1C400A8B27204A5D625",
|
||||
"00849DBC57D3B92F01864E6E82EB4EF0EF6311E122",
|
||||
0x32);
|
||||
sk_ISO_arr.emplace_back(0x0003005000000000, 0x0001, KEY_ISO,
|
||||
sk_ISO_arr.emplace_back(0x0003005000000000, 0x0003005000000000, 0x0001, KEY_ISO,
|
||||
"3F2604FA27AEADFBE1AC69EB00BB16EF196C2193CBD62900FFD8C25041680843",
|
||||
"A414AC1DB7987E43777651B330B899E1",
|
||||
"1F4633AFDE18614D6CEF38A2FD6C4CCAC7B6EB8109D72CD066ECEBA0193EA3F43C37AE83179A4E5F",
|
||||
"0085B4B05DEBA7E6AD831653C974D95149803BB272",
|
||||
0x33);
|
||||
sk_ISO_arr.emplace_back(0x0003005500000000, 0x0001, KEY_ISO,
|
||||
sk_ISO_arr.emplace_back(0x0003005500000000, 0x0003005500000000, 0x0001, KEY_ISO,
|
||||
"BDB74AA6E3BA2DC10B1BD7F17198399A158DBE1FA0BEA68C90FCACBE4D04BE37",
|
||||
"0207A479B1574F8E7F697528F05D5435",
|
||||
"917E1F1DC48A54EB5F10B38E7569BB5383628A7C906F0DCA62FDA33805C15FAB270016940A09DB58",
|
||||
"00294411363290975BA551336D3965D88AF029A17B",
|
||||
0x03);
|
||||
sk_ISO_arr.emplace_back(0x0003005600000000, 0x0001, KEY_ISO,
|
||||
sk_ISO_arr.emplace_back(0x0003005600000000, 0x0003005600000000, 0x0001, KEY_ISO,
|
||||
"311C015F169F2A1E0757F7064B14C7C9F3A3FFEE015BD4E3A22401A2667857CE",
|
||||
"7BB8B3F5AC8E0890E3148AE5688C7350",
|
||||
"3F040EFA2335FED5670BA4D5C3AB2D9D0B4BA69D154A0062EA995A7D21DBAF0DC5A0DAD333D1C1DD",
|
||||
"",
|
||||
0x08);
|
||||
sk_ISO_arr.emplace_back(0x0003006100000000, 0x0001, KEY_ISO,
|
||||
sk_ISO_arr.emplace_back(0x0003006000000000, 0x0003006100000000, 0x0001, KEY_ISO,
|
||||
"8474ADCA3B3244931EECEB9357841442442A1C4A4BCF4E498E6738950F4E4093",
|
||||
"FFF9CACCC4129125CAFB240F419E5F39",
|
||||
"098E1A53E59A95316B00D5A29C05FFEBAE41D1A8A386F9DA96F98858FD25E07BB7A3BC96A5D5B556",
|
||||
"",
|
||||
0x03);
|
||||
sk_ISO_arr.emplace_back(0x0003006600000000, 0x0001, KEY_ISO,
|
||||
sk_ISO_arr.emplace_back(0x0003006500000000, 0x0003006600000000, 0x0001, KEY_ISO,
|
||||
"E6A21C599B75696C169EC02582BDA74A776134A6E05108EA701EC0CA2AC03592",
|
||||
"D292A7BD57C0BB2EABBCA1252FA9EDEF",
|
||||
"2ED078A13DC4617EB550AD06E228C83C142A2D588EB5E729402D18038A14842FD65B277DCAD225A5",
|
||||
"",
|
||||
0x08);
|
||||
sk_ISO_arr.emplace_back(0x0003007400000000, 0x0001, KEY_ISO,
|
||||
sk_ISO_arr.emplace_back(0x0003007000000000, 0x0003007400000000, 0x0001, KEY_ISO,
|
||||
"072D3A5C3BDB0D674DE209381432B20414BC9BDA0F583ECB94BD9A134176DD51",
|
||||
"8516A81F02CF938740498A406C880871",
|
||||
"5A778DEB5C4F12E8D48E06A2BBBBE3C90FA8C6C47DF9BDB5697FD4A8EB7941CE3F59A557E81C787D",
|
||||
"",
|
||||
0x21);
|
||||
sk_ISO_arr.emplace_back(0x0003007400000000, 0x0100, KEY_ISO,
|
||||
sk_ISO_arr.emplace_back(0x0003007000000000, 0x0003007400000000, 0x0100, KEY_ISO,
|
||||
"786FAB8A0B89474A2CB80B3EA104CCCB9E13F66B45EC499BB31865D07C661EA8",
|
||||
"94662F13D99A9F5D211C979FFDF65FE3",
|
||||
"912C94C252B7799CEB45DFBB73EF7CAD9BCC0793A3331BBB79E3C47C0F5C782F698065A8D4DB0D8B",
|
||||
"",
|
||||
0x0E);
|
||||
sk_ISO_arr.emplace_back(0x0004001100000000, 0x0001, KEY_ISO,
|
||||
sk_ISO_arr.emplace_back(0x0004001000000000, 0x0004001100000000, 0x0001, KEY_ISO,
|
||||
"4262657A3185D9480F82C8BD2F81766FCC2C8FD7DD5EBE8657B00B939E0C75BD",
|
||||
"4F1E3EF07D893A4714B1B3D5A4E50479",
|
||||
"4DBFCFA68B52F1D66E09AFA6C18EC65479EDBD027B6B8C6A5D85FE5C84D43EA40CEF1672078A0702",
|
||||
"",
|
||||
0x11);
|
||||
sk_ISO_arr.emplace_back(0x0004001100000000, 0x0100, KEY_ISO,
|
||||
sk_ISO_arr.emplace_back(0x0004001000000000, 0x0004001100000000, 0x0100, KEY_ISO,
|
||||
"16AA7D7C35399E2B1BFAF68CD19D7512A7855029C08BECC4CC3F035DF7F9C70B",
|
||||
"0E50DB6D937D262CB0499136852FCB80",
|
||||
"AEE2795BF295662A50DFAFE70D1B0B6F0A2EBB211E1323A275FC6E2D13BE4F2F10CA34784F4CF1EC",
|
||||
"",
|
||||
0x0F);
|
||||
sk_ISO_arr.emplace_back(0x0004005000000000, 0x0001, KEY_ISO,
|
||||
sk_ISO_arr.emplace_back(0x0004002000000000, 0xFFFFFFFFFFFFFFFF, 0x0001, KEY_ISO,
|
||||
"63565DBE98C3B1A52AADC907C47130FE57A10734E84F22592670F86ED2B0A086",
|
||||
"953F6A99891B4739358F5363A00C08B9",
|
||||
"26BE7B02E7D65C6C21BF4063CDB8C0092FE1679D62FA1A8CCC284A1D21885473A959992537A06612",
|
||||
"",
|
||||
0x15);
|
||||
sk_ISO_arr.emplace_back(0x0004005000000000, 0x0100, KEY_ISO,
|
||||
sk_ISO_arr.emplace_back(0x0004002000000000, 0xFFFFFFFFFFFFFFFF, 0x0100, KEY_ISO,
|
||||
"B96EA32CB96EA32DB96EA32CB96EA32CB96EA32CB96EA32DB96EA32CB96EA32C",
|
||||
"B96EA32CB96EA32DB96EA32DB96EA32C",
|
||||
"2D7066E68C6AC3373B1346FD76FE7D18A207C811500E65D85DB57BC4A27AD78F59FD53F38F50E151",
|
||||
@@ -256,169 +259,169 @@ void KeyVault::LoadSelfISOKeys()
|
||||
void KeyVault::LoadSelfAPPKeys()
|
||||
{
|
||||
sk_APP_arr.clear();
|
||||
sk_APP_arr.emplace_back(0x0000009200000000, 0x0000, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0000009200000000, 0x0000009200000000, 0x0000, KEY_APP,
|
||||
"95F50019E7A68E341FA72EFDF4D60ED376E25CF46BB48DFDD1F080259DC93F04",
|
||||
"4A0955D946DB70D691A640BB7FAECC4C",
|
||||
"6F8DF8EBD0A1D1DB08B30DD3A951E3F1F27E34030B42C729C55555232D61B834B8BDFFB07E54B343",
|
||||
"006C3E4CCB2C69A5AD7C6F60448E50C7F9184EEAF4",
|
||||
0x21);
|
||||
sk_APP_arr.emplace_back(0x0003003000000000, 0x0001, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003003000000000, 0x0003003000000000, 0x0001, KEY_APP,
|
||||
"79481839C406A632BDB4AC093D73D99AE1587F24CE7E69192C1CD0010274A8AB",
|
||||
"6F0F25E1C8C4B7AE70DF968B04521DDA",
|
||||
"94D1B7378BAFF5DFED269240A7A364ED68446741622E50BC6079B6E606A2F8E0A4C56E5CFF836526",
|
||||
"003DE80167D2F0E9D30F2145144A558D1174F5410C",
|
||||
0x11);
|
||||
sk_APP_arr.emplace_back(0x0003003000000000, 0x0002, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003003000000000, 0x0003003000000000, 0x0002, KEY_APP,
|
||||
"4F89BE98DDD43CAD343F5BA6B1A133B0A971566F770484AAC20B5DD1DC9FA06A",
|
||||
"90C127A9B43BA9D8E89FE6529E25206F",
|
||||
"8CA6905F46148D7D8D84D2AFCEAE61B41E6750FC22EA435DFA61FCE6F4F860EE4F54D9196CA5290E",
|
||||
"",
|
||||
0x13);
|
||||
sk_APP_arr.emplace_back(0x0003003000000000, 0x0003, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003003000000000, 0x0003003000000000, 0x0003, KEY_APP,
|
||||
"C1E6A351FCED6A0636BFCB6801A0942DB7C28BDFC5E0A053A3F52F52FCE9754E",
|
||||
"E0908163F457576440466ACAA443AE7C",
|
||||
"50022D5D37C97905F898E78E7AA14A0B5CAAD5CE8190AE5629A10D6F0CF4173597B37A95A7545C92",
|
||||
"",
|
||||
0x0B);
|
||||
sk_APP_arr.emplace_back(0x0003004200000000, 0x0004, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003004200000000, 0x0003004200000000, 0x0004, KEY_APP,
|
||||
"838F5860CF97CDAD75B399CA44F4C214CDF951AC795298D71DF3C3B7E93AAEDA",
|
||||
"7FDBB2E924D182BB0D69844ADC4ECA5B",
|
||||
"1F140E8EF887DAB52F079A06E6915A6460B75CD256834A43FA7AF90C23067AF412EDAFE2C1778D69",
|
||||
"0074E922FDEE5DC4CDF22FC8D7986477F813400860",
|
||||
0x14);
|
||||
sk_APP_arr.emplace_back(0x0003004200000000, 0x0005, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003004200000000, 0x0003004200000000, 0x0005, KEY_APP,
|
||||
"C109AB56593DE5BE8BA190578E7D8109346E86A11088B42C727E2B793FD64BDC",
|
||||
"15D3F191295C94B09B71EBDE088A187A",
|
||||
"B6BB0A84C649A90D97EBA55B555366F52381BB38A84C8BB71DA5A5A0949043C6DB249029A43156F7",
|
||||
"",
|
||||
0x15);
|
||||
sk_APP_arr.emplace_back(0x0003004200000000, 0x0006, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003004200000000, 0x0003004200000000, 0x0006, KEY_APP,
|
||||
"6DFD7AFB470D2B2C955AB22264B1FF3C67F180983B26C01615DE9F2ECCBE7F41",
|
||||
"24BD1C19D2A8286B8ACE39E4A37801C2",
|
||||
"71F46AC33FF89DF589A100A7FB64CEAC244C9A0CBBC1FDCE80FB4BF8A0D2E66293309CB8EE8CFA95",
|
||||
"",
|
||||
0x2C);
|
||||
sk_APP_arr.emplace_back(0x0003005000000000, 0x0007, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003005000000000, 0x0003005000000000, 0x0007, KEY_APP,
|
||||
"945B99C0E69CAF0558C588B95FF41B232660ECB017741F3218C12F9DFDEEDE55",
|
||||
"1D5EFBE7C5D34AD60F9FBC46A5977FCE",
|
||||
"AB284CA549B2DE9AA5C903B75652F78D192F8F4A8F3CD99209415C0A84C5C9FD6BF3095C1C18FFCD",
|
||||
"002CF896D35DB871D0E6A252E799876A70D043C23E",
|
||||
0x15);
|
||||
sk_APP_arr.emplace_back(0x0003005000000000, 0x0008, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003005000000000, 0x0003005000000000, 0x0008, KEY_APP,
|
||||
"2C9E8969EC44DFB6A8771DC7F7FDFBCCAF329EC3EC070900CABB23742A9A6E13",
|
||||
"5A4CEFD5A9C3C093D0B9352376D19405",
|
||||
"6E82F6B54A0E9DEBE4A8B3043EE3B24CD9BBB62B4416B0482582E419A2552E29AB4BEA0A4D7FA2D5",
|
||||
"",
|
||||
0x16);
|
||||
sk_APP_arr.emplace_back(0x0003005000000000, 0x0009, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003005000000000, 0x0003005000000000, 0x0009, KEY_APP,
|
||||
"F69E4A2934F114D89F386CE766388366CDD210F1D8913E3B973257F1201D632B",
|
||||
"F4D535069301EE888CC2A852DB654461",
|
||||
"1D7B974D10E61C2ED087A0981535904677EC07E96260F89565FF7EBDA4EE035C2AA9BCBDD5893F99",
|
||||
"",
|
||||
0x2D);
|
||||
sk_APP_arr.emplace_back(0x0003005500000000, 0x000A, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003005500000000, 0x0003005500000000, 0x000A, KEY_APP,
|
||||
"29805302E7C92F204009161CA93F776A072141A8C46A108E571C46D473A176A3",
|
||||
"5D1FAB844107676ABCDFC25EAEBCB633",
|
||||
"09301B6436C85B53CB1585300A3F1AF9FB14DB7C30088C4642AD66D5C148B8995BB1A698A8C71827",
|
||||
"0010818ED8A666051C6198662C3D6DDE2CA4901DDC",
|
||||
0x25);
|
||||
sk_APP_arr.emplace_back(0x0003005500000000, 0x000B, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003005500000000, 0x0003005500000000, 0x000B, KEY_APP,
|
||||
"A4C97402CC8A71BC7748661FE9CE7DF44DCE95D0D58938A59F47B9E9DBA7BFC3",
|
||||
"E4792F2B9DB30CB8D1596077A13FB3B5",
|
||||
"2733C889D289550FE00EAA5A47A34CEF0C1AF187610EB07BA35D2C09BB73C80B244EB4147700D1BF",
|
||||
"",
|
||||
0x26);
|
||||
sk_APP_arr.emplace_back(0x0003005500000000, 0x000C, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003005500000000, 0x0003005500000000, 0x000C, KEY_APP,
|
||||
"9814EFFF67B7074D1B263BF85BDC8576CE9DEC914123971B169472A1BC2387FA",
|
||||
"D43B1FA8BE15714B3078C23908BB2BCA",
|
||||
"7D1986C6BEE6CE1E0C5893BD2DF203881F40D5056761CC3F1F2E9D9A378617A2DE40BA5F09844CEB",
|
||||
"",
|
||||
0x3D);
|
||||
sk_APP_arr.emplace_back(0x0003005600000000, 0x000D, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003005600000000, 0x0003005600000000, 0x000D, KEY_APP,
|
||||
"03B4C421E0C0DE708C0F0B71C24E3EE04306AE7383D8C5621394CCB99FF7A194",
|
||||
"5ADB9EAFE897B54CB1060D6885BE22CF",
|
||||
"71502ADB5783583AB88B2D5F23F419AF01C8B1E72FCA1E694AD49FE3266F1F9C61EFC6F29B351142",
|
||||
"",
|
||||
0x12);
|
||||
sk_APP_arr.emplace_back(0x0003005600000000, 0x000E, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003005600000000, 0x0003005600000000, 0x000E, KEY_APP,
|
||||
"39A870173C226EB8A3EEE9CA6FB675E82039B2D0CCB22653BFCE4DB013BAEA03",
|
||||
"90266C98CBAA06C1BF145FF760EA1B45",
|
||||
"84DE5692809848E5ACBE25BE548F6981E3DB14735A5DDE1A0FD1F475866532B862B1AB6A004B7255",
|
||||
"",
|
||||
0x27);
|
||||
sk_APP_arr.emplace_back(0x0003005600000000, 0x000F, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003005600000000, 0x0003005600000000, 0x000F, KEY_APP,
|
||||
"FD52DFA7C6EEF5679628D12E267AA863B9365E6DB95470949CFD235B3FCA0F3B",
|
||||
"64F50296CF8CF49CD7C643572887DA0B",
|
||||
"0696D6CCBD7CF585EF5E00D547503C185D7421581BAD196E081723CD0A97FA40B2C0CD2492B0B5A1",
|
||||
"",
|
||||
0x3A);
|
||||
sk_APP_arr.emplace_back(0x0003006100000000, 0x0010, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003006100000000, 0x0003006100000000, 0x0010, KEY_APP,
|
||||
"A5E51AD8F32FFBDE808972ACEE46397F2D3FE6BC823C8218EF875EE3A9B0584F",
|
||||
"7A203D5112F799979DF0E1B8B5B52AA4",
|
||||
"50597B7F680DD89F6594D9BDC0CBEE03666AB53647D0487F7F452FE2DD02694631EA755548C9E934",
|
||||
"",
|
||||
0x25);
|
||||
sk_APP_arr.emplace_back(0x0003006100000000, 0x0011, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003006100000000, 0x0003006100000000, 0x0011, KEY_APP,
|
||||
"0F8EAB8884A51D092D7250597388E3B8B75444AC138B9D36E5C7C5B8C3DF18FD",
|
||||
"97AF39C383E7EF1C98FA447C597EA8FE",
|
||||
"2FDA7A56AAEA65921C0284FF1942C6DE137370093D106034B59191951A5201B422D462F8726F852D",
|
||||
"",
|
||||
0x26);
|
||||
sk_APP_arr.emplace_back(0x0003006600000000, 0x0013, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003006600000000, 0x0003006600000000, 0x0013, KEY_APP,
|
||||
"DBF62D76FC81C8AC92372A9D631DDC9219F152C59C4B20BFF8F96B64AB065E94",
|
||||
"CB5DD4BE8CF115FFB25801BC6086E729",
|
||||
"B26FE6D3E3A1E766FAE79A8E6A7F48998E7FC1E4B0AD8745FF54C018C2A6CC7A0DD7525FAFEA4917",
|
||||
"",
|
||||
0x12);
|
||||
sk_APP_arr.emplace_back(0x0003006600000000, 0x0014, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003006600000000, 0x0003006600000000, 0x0014, KEY_APP,
|
||||
"491B0D72BB21ED115950379F4564CE784A4BFAABB00E8CB71294B192B7B9F88E",
|
||||
"F98843588FED8B0E62D7DDCB6F0CECF4",
|
||||
"04275E8838EF95BD013B223C3DF674540932F21B534C7ED2944B9104D938FEB03B824DDB866AB26E",
|
||||
"",
|
||||
0x27);
|
||||
sk_APP_arr.emplace_back(0x0003007400000000, 0x0016, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003007400000000, 0x0003007400000000, 0x0016, KEY_APP,
|
||||
"A106692224F1E91E1C4EBAD4A25FBFF66B4B13E88D878E8CD072F23CD1C5BF7C",
|
||||
"62773C70BD749269C0AFD1F12E73909E",
|
||||
"566635D3E1DCEC47243AAD1628AE6B2CEB33463FC155E4635846CE33899C5E353DDFA47FEF5694AF",
|
||||
"",
|
||||
0x30);
|
||||
sk_APP_arr.emplace_back(0x0003007400000000, 0x0017, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003007400000000, 0x0003007400000000, 0x0017, KEY_APP,
|
||||
"4E104DCE09BA878C75DA98D0B1636F0E5F058328D81419E2A3D22AB0256FDF46",
|
||||
"954A86C4629E116532304A740862EF85",
|
||||
"3B7B04C71CAE2B1199D57453C038BB1B541A05AD1B94167B0AB47A9B24CAECB9000CB21407009666",
|
||||
"",
|
||||
0x08);
|
||||
sk_APP_arr.emplace_back(0x0003007400000000, 0x0018, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0003007400000000, 0x0003007400000000, 0x0018, KEY_APP,
|
||||
"1F876AB252DDBCB70E74DC4A20CD8ED51E330E62490E652F862877E8D8D0F997",
|
||||
"BF8D6B1887FA88E6D85C2EDB2FBEC147",
|
||||
"64A04126D77BF6B4D686F6E8F87DD150A5B014BA922D2B694FFF4453E11239A6E0B58F1703C51494",
|
||||
"",
|
||||
0x11);
|
||||
sk_APP_arr.emplace_back(0x0004001100000000, 0x0019, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0004001100000000, 0x0004001100000000, 0x0019, KEY_APP,
|
||||
"3236B9937174DF1DC12EC2DD8A318A0EA4D3ECDEA5DFB4AC1B8278447000C297",
|
||||
"6153DEE781B8ADDC6A439498B816DC46",
|
||||
"148DCA961E2738BAF84B2D1B6E2DA2ABD6A95F2C9571E54C6922F9ED9674F062B7F1BE5BD6FA5268",
|
||||
"",
|
||||
0x31);
|
||||
sk_APP_arr.emplace_back(0x0004001100000000, 0x001A, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0004001100000000, 0x0004001100000000, 0x001A, KEY_APP,
|
||||
"5EFD1E9961462794E3B9EF2A4D0C1F46F642AAE053B5025504130590E66F19C9",
|
||||
"1AC8FA3B3C90F8FDE639515F91B58327",
|
||||
"BE4B1B513536960618BFEF12A713F6673881B02F9DC616191E823FC8337CCF99ADAA6172019C0C23",
|
||||
"",
|
||||
0x17);
|
||||
sk_APP_arr.emplace_back(0x0004001100000000, 0x001B, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0004001100000000, 0x0004001100000000, 0x001B, KEY_APP,
|
||||
"66637570D1DEC098467DB207BAEA786861964D0964D4DBAF89E76F46955D181B",
|
||||
"9F7B5713A5ED59F6B35CD8F8A165D4B8",
|
||||
"4AB6FB1F6F0C3D9219923C1AC683137AB05DF667833CC6A5E8F590E4E28FE2EB180C7D5861117CFB",
|
||||
"",
|
||||
0x12);
|
||||
sk_APP_arr.emplace_back(0x0004004600000000, 0x001C, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0004004600000000, 0x0004004600000000, 0x001C, KEY_APP,
|
||||
"CFF025375BA0079226BE01F4A31F346D79F62CFB643CA910E16CF60BD9092752",
|
||||
"FD40664E2EBBA01BF359B0DCDF543DA4",
|
||||
"36C1ACE6DD5CCC0006FDF3424750FAC515FC5CFA2C93EC53C6EC2BC421708D154E91F2E7EA54A893",
|
||||
"",
|
||||
0x09);
|
||||
sk_APP_arr.emplace_back(0x0004004600000000, 0x001D, KEY_APP,
|
||||
sk_APP_arr.emplace_back(0x0004004600000000, 0x0004004600000000, 0x001D, KEY_APP,
|
||||
"D202174EB65A62048F3674B59EF6FE72E1872962F3E1CD658DE8D7AF71DA1F3E",
|
||||
"ACB9945914EBB7B9A31ECE320AE09F2D",
|
||||
"430322887503CF52928FAAA410FD623C7321281C8825D95F5B47EF078EFCFC44454C3AB4F00BB879",
|
||||
@@ -429,97 +432,97 @@ void KeyVault::LoadSelfAPPKeys()
|
||||
void KeyVault::LoadSelfNPDRMKeys()
|
||||
{
|
||||
sk_NPDRM_arr.clear();
|
||||
sk_NPDRM_arr.emplace_back(0x0001000000000000, 0x0001, KEY_NPDRM,
|
||||
sk_NPDRM_arr.emplace_back(0x0001000000000000, 0x0001000000000000, 0x0001, KEY_NPDRM,
|
||||
"F9EDD0301F770FABBA8863D9897F0FEA6551B09431F61312654E28F43533EA6B",
|
||||
"A551CCB4A42C37A734A2B4F9657D5540",
|
||||
"B05F9DA5F9121EE4031467E74C505C29A8E29D1022379EDFF0500B9AE480B5DAB4578A4C61C5D6BF",
|
||||
"00040AB47509BED04BD96521AD1B365B86BF620A98",
|
||||
0x11);
|
||||
sk_NPDRM_arr.emplace_back(0x0001000000000000, 0x0002, KEY_NPDRM,
|
||||
sk_NPDRM_arr.emplace_back(0x0001000000000000, 0x0001000000000000, 0x0002, KEY_NPDRM,
|
||||
"8E737230C80E66AD0162EDDD32F1F774EE5E4E187449F19079437A508FCF9C86",
|
||||
"7AAECC60AD12AED90C348D8C11D2BED5",
|
||||
"05BF09CB6FD78050C78DE69CC316FF27C9F1ED66A45BFCE0A1E5A6749B19BD546BBB4602CF373440",
|
||||
"",
|
||||
0x0A);
|
||||
sk_NPDRM_arr.emplace_back(0x0003003000000000, 0x0003, KEY_NPDRM,
|
||||
sk_NPDRM_arr.emplace_back(0x0003003000000000, 0x0003003000000000, 0x0003, KEY_NPDRM,
|
||||
"1B715B0C3E8DC4C1A5772EBA9C5D34F7CCFE5B82025D453F3167566497239664",
|
||||
"E31E206FBB8AEA27FAB0D9A2FFB6B62F",
|
||||
"3F51E59FC74D6618D34431FA67987FA11ABBFACC7111811473CD9988FE91C43FC74605E7B8CB732D",
|
||||
"",
|
||||
0x08);
|
||||
sk_NPDRM_arr.emplace_back(0x0003004200000000, 0x0004, KEY_NPDRM,
|
||||
sk_NPDRM_arr.emplace_back(0x0003004200000000, 0x0003004200000000, 0x0004, KEY_NPDRM,
|
||||
"BB4DBF66B744A33934172D9F8379A7A5EA74CB0F559BB95D0E7AECE91702B706",
|
||||
"ADF7B207A15AC601110E61DDFC210AF6",
|
||||
"9C327471BAFF1F877AE4FE29F4501AF5AD6A2C459F8622697F583EFCA2CA30ABB5CD45D1131CAB30",
|
||||
"00B61A91DF4AB6A9F142C326BA9592B5265DA88856",
|
||||
0x16);
|
||||
sk_NPDRM_arr.emplace_back(0x0003004200000000, 0x0006, KEY_NPDRM,
|
||||
sk_NPDRM_arr.emplace_back(0x0003004200000000, 0x0003004200000000, 0x0006, KEY_NPDRM,
|
||||
"8B4C52849765D2B5FA3D5628AFB17644D52B9FFEE235B4C0DB72A62867EAA020",
|
||||
"05719DF1B1D0306C03910ADDCE4AF887",
|
||||
"2A5D6C6908CA98FC4740D834C6400E6D6AD74CF0A712CF1E7DAE806E98605CC308F6A03658F2970E",
|
||||
"",
|
||||
0x29);
|
||||
sk_NPDRM_arr.emplace_back(0x0003005000000000, 0x0007, KEY_NPDRM,
|
||||
sk_NPDRM_arr.emplace_back(0x0003005000000000, 0x0003005000000000, 0x0007, KEY_NPDRM,
|
||||
"3946DFAA141718C7BE339A0D6C26301C76B568AEBC5CD52652F2E2E0297437C3",
|
||||
"E4897BE553AE025CDCBF2B15D1C9234E",
|
||||
"A13AFE8B63F897DA2D3DC3987B39389DC10BAD99DFB703838C4A0BC4E8BB44659C726CFD0CE60D0E",
|
||||
"009EF86907782A318D4CC3617EBACE2480E73A46F6",
|
||||
0x17);
|
||||
sk_NPDRM_arr.emplace_back(0x0003005000000000, 0x0009, KEY_NPDRM,
|
||||
sk_NPDRM_arr.emplace_back(0x0003005000000000, 0x0003005000000000, 0x0009, KEY_NPDRM,
|
||||
"0786F4B0CA5937F515BDCE188F569B2EF3109A4DA0780A7AA07BD89C3350810A",
|
||||
"04AD3C2F122A3B35E804850CAD142C6D",
|
||||
"A1FE61035DBBEA5A94D120D03C000D3B2F084B9F4AFA99A2D4A588DF92B8F36327CE9E47889A45D0",
|
||||
"",
|
||||
0x2A);
|
||||
sk_NPDRM_arr.emplace_back(0x0003005500000000, 0x000A, KEY_NPDRM,
|
||||
sk_NPDRM_arr.emplace_back(0x0003005500000000, 0x0003005500000000, 0x000A, KEY_NPDRM,
|
||||
"03C21AD78FBB6A3D425E9AAB1298F9FD70E29FD4E6E3A3C151205DA50C413DE4",
|
||||
"0A99D4D4F8301A88052D714AD2FB565E",
|
||||
"3995C390C9F7FBBAB124A1C14E70F9741A5E6BDF17A605D88239652C8EA7D5FC9F24B30546C1E44B",
|
||||
"009AC6B22A056BA9E0B6D1520F28A57A3135483F9F",
|
||||
0x27);
|
||||
sk_NPDRM_arr.emplace_back(0x0003005500000000, 0x000C, KEY_NPDRM,
|
||||
sk_NPDRM_arr.emplace_back(0x0003005500000000, 0x0003005500000000, 0x000C, KEY_NPDRM,
|
||||
"357EBBEA265FAEC271182D571C6CD2F62CFA04D325588F213DB6B2E0ED166D92",
|
||||
"D26E6DD2B74CD78E866E742E5571B84F",
|
||||
"00DCF5391618604AB42C8CFF3DC304DF45341EBA4551293E9E2B68FFE2DF527FFA3BE8329E015E57",
|
||||
"",
|
||||
0x3A);
|
||||
sk_NPDRM_arr.emplace_back(0x0003005600000000, 0x000D, KEY_NPDRM,
|
||||
sk_NPDRM_arr.emplace_back(0x0003005600000000, 0x0003005600000000, 0x000D, KEY_NPDRM,
|
||||
"337A51416105B56E40D7CAF1B954CDAF4E7645F28379904F35F27E81CA7B6957",
|
||||
"8405C88E042280DBD794EC7E22B74002",
|
||||
"9BFF1CC7118D2393DE50D5CF44909860683411A532767BFDAC78622DB9E5456753FE422CBAFA1DA1",
|
||||
"",
|
||||
0x18);
|
||||
sk_NPDRM_arr.emplace_back(0x0003005600000000, 0x000F, KEY_NPDRM,
|
||||
sk_NPDRM_arr.emplace_back(0x0003005600000000, 0x0003005600000000, 0x000F, KEY_NPDRM,
|
||||
"135C098CBE6A3E037EBE9F2BB9B30218DDE8D68217346F9AD33203352FBB3291",
|
||||
"4070C898C2EAAD1634A288AA547A35A8",
|
||||
"BBD7CCCB556C2EF0F908DC7810FAFC37F2E56B3DAA5F7FAF53A4944AA9B841F76AB091E16B231433",
|
||||
"",
|
||||
0x3B);
|
||||
sk_NPDRM_arr.emplace_back(0x0003006100000000, 0x0010, KEY_NPDRM,
|
||||
sk_NPDRM_arr.emplace_back(0x0003006100000000, 0x0003006100000000, 0x0010, KEY_NPDRM,
|
||||
"4B3CD10F6A6AA7D99F9B3A660C35ADE08EF01C2C336B9E46D1BB5678B4261A61",
|
||||
"C0F2AB86E6E0457552DB50D7219371C5",
|
||||
"64A5C60BC2AD18B8A237E4AA690647E12BF7A081523FAD4F29BE89ACAC72F7AB43C74EC9AFFDA213",
|
||||
"",
|
||||
0x27);
|
||||
sk_NPDRM_arr.emplace_back(0x0003006600000000, 0x0013, KEY_NPDRM,
|
||||
sk_NPDRM_arr.emplace_back(0x0003006600000000, 0x0003006600000000, 0x0013, KEY_NPDRM,
|
||||
"265C93CF48562EC5D18773BEB7689B8AD10C5EB6D21421455DEBC4FB128CBF46",
|
||||
"8DEA5FF959682A9B98B688CEA1EF4A1D",
|
||||
"9D8DB5A880608DC69717991AFC3AD5C0215A5EE413328C2ABC8F35589E04432373DB2E2339EEF7C8",
|
||||
"",
|
||||
0x18);
|
||||
sk_NPDRM_arr.emplace_back(0x0003007400000000, 0x0016, KEY_NPDRM,
|
||||
sk_NPDRM_arr.emplace_back(0x0003007400000000, 0x0003007400000000, 0x0016, KEY_NPDRM,
|
||||
"7910340483E419E55F0D33E4EA5410EEEC3AF47814667ECA2AA9D75602B14D4B",
|
||||
"4AD981431B98DFD39B6388EDAD742A8E",
|
||||
"62DFE488E410B1B6B2F559E4CB932BCB78845AB623CC59FDF65168400FD76FA82ED1DC60E091D1D1",
|
||||
"",
|
||||
0x25);
|
||||
sk_NPDRM_arr.emplace_back(0x0004001100000000, 0x0019, KEY_NPDRM,
|
||||
sk_NPDRM_arr.emplace_back(0x0004001100000000, 0x0004001100000000, 0x0019, KEY_NPDRM,
|
||||
"FBDA75963FE690CFF35B7AA7B408CF631744EDEF5F7931A04D58FD6A921FFDB3",
|
||||
"F72C1D80FFDA2E3BF085F4133E6D2805",
|
||||
"637EAD34E7B85C723C627E68ABDD0419914EBED4008311731DD87FDDA2DAF71F856A70E14DA17B42",
|
||||
"",
|
||||
0x24);
|
||||
sk_NPDRM_arr.emplace_back(0x0004004600000000, 0x001C, KEY_NPDRM,
|
||||
sk_NPDRM_arr.emplace_back(0x0004004600000000, 0x0004004600000000, 0x001C, KEY_NPDRM,
|
||||
"8103EA9DB790578219C4CEDF0592B43064A7D98B601B6C7BC45108C4047AA80F",
|
||||
"246F4B8328BE6A2D394EDE20479247C5",
|
||||
"503172C9551308A87621ECEE90362D14889BFED2CF32B0B3E32A4F9FE527A41464B735E1ADBC6762",
|
||||
@@ -530,61 +533,61 @@ void KeyVault::LoadSelfNPDRMKeys()
|
||||
void KeyVault::LoadSelfUNK7Keys()
|
||||
{
|
||||
sk_UNK7_arr.clear();
|
||||
sk_UNK7_arr.emplace_back(0x0003003000000000, 0x0000, KEY_UNK7,
|
||||
sk_UNK7_arr.emplace_back(0x0000008400000000, 0x0003003100000000, 0x0000, KEY_UNK7,
|
||||
"D91166973979EA8694476B011AC62C7E9F37DA26DE1E5C2EE3D66E42B8517085",
|
||||
"DC01280A6E46BC674B81A7E8801EBE6E",
|
||||
"A0FC44108236141BF3517A662B027AFC1AC513A05690496C754DEB7D43BDC41B80FD75C212624EE4",
|
||||
"",
|
||||
0x11);
|
||||
sk_UNK7_arr.emplace_back(0x0003004200000000, 0x0000, KEY_UNK7,
|
||||
sk_UNK7_arr.emplace_back(0x0003004000000000, 0x0003004200000000, 0x0000, KEY_UNK7,
|
||||
"B73111B0B00117E48DE5E2EE5E534C0F0EFFA4890BBB8CAD01EE0F848F91583E",
|
||||
"86F56F9E5DE513894874B8BA253334B1",
|
||||
"B0BA1A1AB9723BB4E87CED9637BE056066BC56E16572D43D0210A06411DBF8FEB8885CD912384AE5",
|
||||
"",
|
||||
0x12);
|
||||
sk_UNK7_arr.emplace_back(0x0003005000000000, 0x0000, KEY_UNK7,
|
||||
sk_UNK7_arr.emplace_back(0x0003005000000000, 0x0003005000000000, 0x0000, KEY_UNK7,
|
||||
"8E944267C02E69A4FE474B7F5FCD7974A4F936FF4355AEC4F80EFA123858D8F6",
|
||||
"908A75754E521EAC2F5A4889C6D7B72D",
|
||||
"91201DA7D79E8EE2563142ECBD646DA026C963AC09E760E5390FFE24DAE6864310ABE147F8204D0B",
|
||||
"",
|
||||
0x13);
|
||||
sk_UNK7_arr.emplace_back(0x0003005500000000, 0x0000, KEY_UNK7,
|
||||
sk_UNK7_arr.emplace_back(0x0003005500000000, 0x0003005500000000, 0x0000, KEY_UNK7,
|
||||
"BB31DF9A6F62C0DF853075FAA65134D9CE2240306C1731D1F7DA9B5329BD699F",
|
||||
"263057225873F83940A65C8C926AC3E4",
|
||||
"BC3A82A4F44C43A197070CD236FDC94FCC542D69A3E803E0AFF78D1F3DA19A79D2F61FAB5B94B437",
|
||||
"",
|
||||
0x23);
|
||||
sk_UNK7_arr.emplace_back(0x0003005600000000, 0x0000, KEY_UNK7,
|
||||
sk_UNK7_arr.emplace_back(0x0003005600000000, 0x0003005600000000, 0x0000, KEY_UNK7,
|
||||
"71AA75C70A255580E4AE9BDAA0B08828C53EAA713CD0713797F143B284C1589B",
|
||||
"9DED878CB6BA07121C0F50E7B172A8BF",
|
||||
"387FCDAEAFF1B59CFAF79CE6215A065ACEAFFAF4048A4F217E1FF5CE67C66EC3F089DB235E52F9D3",
|
||||
"",
|
||||
0x29);
|
||||
sk_UNK7_arr.emplace_back(0x0003006100000000, 0x0000, KEY_UNK7,
|
||||
sk_UNK7_arr.emplace_back(0x0003006000000000, 0x0003006100000000, 0x0000, KEY_UNK7,
|
||||
"F5D1DBC182F5083CD4EA37C431C7DAC73882C07F232D2699B1DD9FDDF1BF4195",
|
||||
"D3A7C3C91CBA014FCBCA6D5570DE13FF",
|
||||
"97CA8A9781F45E557E98F176EF794FCDA6B151EB3DFD1ABA12151E00AE59957C3B15628FC8875D28",
|
||||
"",
|
||||
0x23);
|
||||
sk_UNK7_arr.emplace_back(0x0003006600000000, 0x0000, KEY_UNK7,
|
||||
sk_UNK7_arr.emplace_back(0x0003006500000000, 0x0003006600000000, 0x0000, KEY_UNK7,
|
||||
"BF10F09590C0152F7EF749FF4B990122A4E8E5491DA49A2D931E72EEB990F860",
|
||||
"22C19C5522F7A782AFC547C2640F5BDE",
|
||||
"3233BA2B284189FB1687DF653002257A0925D8EB0C64EBBE8CC7DE87F548D107DE1FD3D1D285DB4F",
|
||||
"",
|
||||
0x29);
|
||||
sk_UNK7_arr.emplace_back(0x0003007400000000, 0x0000, KEY_UNK7,
|
||||
sk_UNK7_arr.emplace_back(0x0003007000000000, 0x0003007400000000, 0x0000, KEY_UNK7,
|
||||
"F11DBD2C97B32AD37E55F8E743BC821D3E67630A6784D9A058DDD26313482F0F",
|
||||
"FC5FA12CA3D2D336C4B8B425D679DA55",
|
||||
"19E27EE90E33EDAB16B22E688B5F704E5C6EC1062070EBF43554CD03DFDAE16D684BB8B5574DBECA",
|
||||
"",
|
||||
0x15);
|
||||
sk_UNK7_arr.emplace_back(0x0004001100000000, 0x0000, KEY_UNK7,
|
||||
sk_UNK7_arr.emplace_back(0x0004000000000000, 0x0004001100000000, 0x0000, KEY_UNK7,
|
||||
"751EE949CD3ADF50A469197494A1EC358409CCBE6E85217EBDE7A87D3FF1ABD8",
|
||||
"23AE4ADA4D3F798DC5ED98000337FF77",
|
||||
"1BABA87CD1AD705C462D4E7427B6DAF59A50383A348A15088F0EDFCF1ADF2B5C2B2D507B2A357D36",
|
||||
"",
|
||||
0x1A);
|
||||
sk_UNK7_arr.emplace_back(0x0004004600000000, 0x0000, KEY_UNK7,
|
||||
sk_UNK7_arr.emplace_back(0x0004002000000000, 0xFFFFFFFFFFFFFFFF, 0x0000, KEY_UNK7,
|
||||
"46BD0891224E0CE13E2162921D4BB76193AEEE4416A729FCDD111C5536BF87C9",
|
||||
"BF036387CDB613C0AC88A6D9D2CC5316",
|
||||
"A14F6D5F9AD7EBB3B7A39A7C32F13E5DC3B0BA16BDC33D39FDDF88F4AEEA6CFEEB0C0796C917A952",
|
||||
@@ -604,11 +607,11 @@ SELF_KEY KeyVault::GetSelfLDRKey() const
|
||||
|
||||
SELF_KEY KeyVault::GetSelfLV1Key(u64 version) const
|
||||
{
|
||||
SELF_KEY key(0, 0, 0, "", "", "", "", 0);
|
||||
SELF_KEY key(0, 0, 0, 0, "", "", "", "", 0);
|
||||
|
||||
for(unsigned int i = 0; i < sk_LV1_arr.size(); i++)
|
||||
{
|
||||
if (sk_LV1_arr[i].version == version)
|
||||
if (version >= sk_LV1_arr[i].version_start && version <= sk_LV1_arr[i].version_end)
|
||||
{
|
||||
key = sk_LV1_arr[i];
|
||||
break;
|
||||
@@ -620,11 +623,11 @@ SELF_KEY KeyVault::GetSelfLV1Key(u64 version) const
|
||||
|
||||
SELF_KEY KeyVault::GetSelfLV2Key(u64 version) const
|
||||
{
|
||||
SELF_KEY key(0, 0, 0, "", "", "", "", 0);
|
||||
SELF_KEY key(0, 0, 0, 0, "", "", "", "", 0);
|
||||
|
||||
for(unsigned int i = 0; i < sk_LV2_arr.size(); i++)
|
||||
{
|
||||
if (sk_LV2_arr[i].version == version)
|
||||
if (version >= sk_LV2_arr[i].version_start && version <= sk_LV2_arr[i].version_end)
|
||||
{
|
||||
key = sk_LV2_arr[i];
|
||||
break;
|
||||
@@ -636,12 +639,11 @@ SELF_KEY KeyVault::GetSelfLV2Key(u64 version) const
|
||||
|
||||
SELF_KEY KeyVault::GetSelfISOKey(u16 revision, u64 version) const
|
||||
{
|
||||
SELF_KEY key(0, 0, 0, "", "", "", "", 0);
|
||||
SELF_KEY key(0, 0, 0, 0, "", "", "", "", 0);
|
||||
|
||||
for(unsigned int i = 0; i < sk_ISO_arr.size(); i++)
|
||||
{
|
||||
if ((sk_ISO_arr[i].version == version) &&
|
||||
(sk_ISO_arr[i].revision == revision))
|
||||
if ((version >= sk_ISO_arr[i].version_start && version <= sk_ISO_arr[i].version_end) && (sk_ISO_arr[i].revision == revision))
|
||||
{
|
||||
key = sk_ISO_arr[i];
|
||||
break;
|
||||
@@ -653,7 +655,7 @@ SELF_KEY KeyVault::GetSelfISOKey(u16 revision, u64 version) const
|
||||
|
||||
SELF_KEY KeyVault::GetSelfAPPKey(u16 revision) const
|
||||
{
|
||||
SELF_KEY key(0, 0, 0, "", "", "", "", 0);
|
||||
SELF_KEY key(0, 0, 0, 0, "", "", "", "", 0);
|
||||
|
||||
for(unsigned int i = 0; i < sk_APP_arr.size(); i++)
|
||||
{
|
||||
@@ -669,11 +671,11 @@ SELF_KEY KeyVault::GetSelfAPPKey(u16 revision) const
|
||||
|
||||
SELF_KEY KeyVault::GetSelfUNK7Key(u64 version) const
|
||||
{
|
||||
SELF_KEY key(0, 0, 0, "", "", "", "", 0);
|
||||
SELF_KEY key(0, 0, 0, 0, "", "", "", "", 0);
|
||||
|
||||
for(unsigned int i = 0; i < sk_UNK7_arr.size(); i++)
|
||||
{
|
||||
if (sk_UNK7_arr[i].version == version)
|
||||
if (version >= sk_UNK7_arr[i].version_start && version <= sk_UNK7_arr[i].version_end)
|
||||
{
|
||||
key = sk_UNK7_arr[i];
|
||||
break;
|
||||
@@ -685,7 +687,7 @@ SELF_KEY KeyVault::GetSelfUNK7Key(u64 version) const
|
||||
|
||||
SELF_KEY KeyVault::GetSelfNPDRMKey(u16 revision) const
|
||||
{
|
||||
SELF_KEY key(0, 0, 0, "", "", "", "", 0);
|
||||
SELF_KEY key(0, 0, 0, 0, "", "", "", "", 0);
|
||||
|
||||
for(unsigned int i = 0; i < sk_NPDRM_arr.size(); i++)
|
||||
{
|
||||
@@ -702,7 +704,9 @@ SELF_KEY KeyVault::GetSelfNPDRMKey(u16 revision) const
|
||||
SELF_KEY KeyVault::FindSelfKey(u32 type, u16 revision, u64 version)
|
||||
{
|
||||
// Empty key.
|
||||
SELF_KEY key(0, 0, 0, "", "", "", "", 0);
|
||||
SELF_KEY key(0, 0, 0, 0, "", "", "", "", 0);
|
||||
|
||||
key_vault_log.notice("FindSelfKey: Type:0x%x, Revision:0x%x, Version:0x%x", type, revision, version);
|
||||
|
||||
// Check SELF type.
|
||||
switch (type)
|
||||
@@ -808,4 +812,3 @@ void rap_to_rif(unsigned char* rap, unsigned char* rif)
|
||||
|
||||
memcpy(rif, key, 0x10);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/types.h"
|
||||
#include "Utilities/Log.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -18,7 +19,8 @@ enum SELF_KEY_TYPE {
|
||||
};
|
||||
|
||||
struct SELF_KEY {
|
||||
u64 version;
|
||||
u64 version_start;
|
||||
u64 version_end;
|
||||
u16 revision;
|
||||
u32 self_type;
|
||||
u8 erk[0x20];
|
||||
@@ -27,7 +29,11 @@ struct SELF_KEY {
|
||||
u8 priv[0x15];
|
||||
u32 curve_type;
|
||||
|
||||
SELF_KEY(u64 ver, u16 rev, u32 type, const std::string& e, const std::string& r, const std::string& pb, const std::string& pr, u32 ct);
|
||||
SELF_KEY(u64 ver_start, u64 ver_end, u16 rev, u32 type, const std::string& e, const std::string& r, const std::string& pb, const std::string& pr, u32 ct);
|
||||
};
|
||||
|
||||
static u8 PKG_AES_KEY_IDU[0x10] = {
|
||||
0x5d, 0xb9, 0x11, 0xe6, 0xb7, 0xe5, 0x0a, 0x7d, 0x32, 0x15, 0x38, 0xfd, 0x7c, 0x66, 0xf1, 0x7b
|
||||
};
|
||||
|
||||
static u8 PKG_AES_KEY[0x10] = {
|
||||
@@ -143,13 +149,13 @@ static u8 VSH_PUB[0x28] = {
|
||||
0x6E, 0x73, 0x6A, 0xBF, 0x81, 0xF7, 0x0E, 0xE9, 0x16, 0x1B, 0x0D, 0xDE, 0xB0, 0x26, 0x76, 0x1A, 0xFF, 0x7B, 0xC8, 0x5B
|
||||
};
|
||||
|
||||
static u8 SCEPKG_RIV[0x10] = {
|
||||
0x4A, 0xCE, 0xF0, 0x12, 0x24, 0xFB, 0xEE, 0xDF, 0x82, 0x45, 0xF8, 0xFF, 0x10, 0x21, 0x1E, 0x6E
|
||||
static u8 SCEPKG_RIV[0x10] = {
|
||||
0x4A, 0xCE, 0xF0, 0x12, 0x24, 0xFB, 0xEE, 0xDF, 0x82, 0x45, 0xF8, 0xFF, 0x10, 0x21, 0x1E, 0x6E
|
||||
};
|
||||
|
||||
static u8 SCEPKG_ERK[0x20] = {
|
||||
static u8 SCEPKG_ERK[0x20] = {
|
||||
0xA9, 0x78, 0x18, 0xBD, 0x19, 0x3A, 0x67, 0xA1, 0x6F, 0xE8, 0x3A, 0x85, 0x5E, 0x1B, 0xE9, 0xFB, 0x56, 0x40, 0x93, 0x8D,
|
||||
0x4D, 0xBC, 0xB2, 0xCB, 0x52, 0xC5, 0xA2, 0xF8, 0xB0, 0x2B, 0x10, 0x31
|
||||
0x4D, 0xBC, 0xB2, 0xCB, 0x52, 0xC5, 0xA2, 0xF8, 0xB0, 0x2B, 0x10, 0x31
|
||||
};
|
||||
|
||||
static u8 PUP_KEY[0x40] = {
|
||||
@@ -177,7 +183,7 @@ public:
|
||||
void SetKlicenseeKey(u8 *key);
|
||||
u8 *GetKlicenseeKey();
|
||||
|
||||
private:
|
||||
private:
|
||||
void LoadSelfLV0Keys();
|
||||
void LoadSelfLDRKeys();
|
||||
void LoadSelfLV1Keys();
|
||||
|
||||
+59
-57
@@ -4,6 +4,8 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
LOG_CHANNEL(edat_log, "EDAT");
|
||||
|
||||
void generate_key(int crypto_mode, int version, unsigned char *key_final, unsigned char *iv_final, unsigned char *key, unsigned char *iv)
|
||||
{
|
||||
int mode = crypto_mode & 0xF0000000;
|
||||
@@ -78,7 +80,7 @@ bool decrypt(int hash_mode, int crypto_mode, int version, unsigned char *in, uns
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: Unknown crypto algorithm!");
|
||||
edat_log.error("EDAT: Unknown crypto algorithm!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -96,7 +98,7 @@ bool decrypt(int hash_mode, int crypto_mode, int version, unsigned char *in, uns
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: Unknown hashing algorithm!");
|
||||
edat_log.error("EDAT: Unknown hashing algorithm!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -280,7 +282,7 @@ s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *np
|
||||
// Call main crypto routine on this data block.
|
||||
if (!decrypt(hash_mode, crypto_mode, (npd->version == 4), enc_data.get(), dec_data.get(), length, key_result, iv, hash, hash_result))
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: Block at offset 0x%llx has invalid hash!", offset);
|
||||
edat_log.error("EDAT: Block at offset 0x%llx has invalid hash!", offset);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -296,7 +298,7 @@ s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *np
|
||||
{
|
||||
if (res < 0)
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: Decompression failed!");
|
||||
edat_log.error("EDAT: Decompression failed!");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -322,9 +324,9 @@ int decrypt_data(const fs::file* in, const fs::file* out, EDAT_HEADER *edat, NPD
|
||||
in->seek(0);
|
||||
memset(data.get(), 0, edat->block_size);
|
||||
u64 res = decrypt_block(in, data.get(), edat, npd, crypt_key, i, total_blocks, size_left);
|
||||
if (res == -1)
|
||||
if (res == umax)
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: Decrypt Block failed!");
|
||||
edat_log.error("EDAT: Decrypt Block failed!");
|
||||
return 1;
|
||||
}
|
||||
size_left -= res;
|
||||
@@ -349,7 +351,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
{
|
||||
if (edat->flags & 0x7EFFFFFE)
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: Bad header flags!");
|
||||
edat_log.error("EDAT: Bad header flags!");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -357,7 +359,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
{
|
||||
if (edat->flags & 0x7EFFFFE0)
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: Bad header flags!");
|
||||
edat_log.error("EDAT: Bad header flags!");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -365,13 +367,13 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
{
|
||||
if (edat->flags & 0x7EFFFFC0)
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: Bad header flags!");
|
||||
edat_log.error("EDAT: Bad header flags!");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: Unknown version!");
|
||||
edat_log.error("EDAT: Unknown version!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -391,7 +393,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
hash_mode |= 0x01000000;
|
||||
|
||||
if (verbose)
|
||||
LOG_WARNING(LOADER, "EDAT: DEBUG data detected!");
|
||||
edat_log.warning("EDAT: DEBUG data detected!");
|
||||
}
|
||||
|
||||
// Setup header key and iv buffers.
|
||||
@@ -402,12 +404,12 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
if (!decrypt(hash_mode, crypto_mode, (npd->version == 4), header, empty_header, 0xA0, header_key, header_iv, key, header_hash))
|
||||
{
|
||||
if (verbose)
|
||||
LOG_WARNING(LOADER, "EDAT: Header hash is invalid!");
|
||||
edat_log.warning("EDAT: Header hash is invalid!");
|
||||
|
||||
// If the header hash test fails and the data is not DEBUG, then RAP/RIF/KLIC key is invalid.
|
||||
if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != EDAT_DEBUG_DATA_FLAG)
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: RAP/RIF/KLIC key is invalid!");
|
||||
edat_log.error("EDAT: RAP/RIF/KLIC key is invalid!");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -417,7 +419,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
if (((edat->flags & EDAT_COMPRESSED_FLAG) != 0))
|
||||
{
|
||||
if (verbose)
|
||||
LOG_WARNING(LOADER, "EDAT: COMPRESSED data detected!");
|
||||
edat_log.warning("EDAT: COMPRESSED data detected!");
|
||||
}
|
||||
|
||||
const int block_num = static_cast<int>((edat->file_size + edat->block_size - 1) / edat->block_size);
|
||||
@@ -452,7 +454,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
if (!decrypt(hash_mode, crypto_mode, (npd->version == 4), metadata.get(), empty_metadata.get(), metadata_size, header_key, header_iv, key, metadata_hash))
|
||||
{
|
||||
if (verbose)
|
||||
LOG_WARNING(LOADER, "EDAT: Metadata section hash is invalid!");
|
||||
edat_log.warning("EDAT: Metadata section hash is invalid!");
|
||||
}
|
||||
|
||||
// Checking ECDSA signatures.
|
||||
@@ -480,7 +482,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
memcpy(signature_r + 01, metadata_signature, 0x14);
|
||||
memcpy(signature_s + 01, metadata_signature + 0x14, 0x14);
|
||||
if ((!memcmp(signature_r, zero_buf, 0x15)) || (!memcmp(signature_s, zero_buf, 0x15)))
|
||||
LOG_WARNING(LOADER, "EDAT: Metadata signature is invalid!");
|
||||
edat_log.warning("EDAT: Metadata signature is invalid!");
|
||||
else
|
||||
{
|
||||
// Setup signature hash.
|
||||
@@ -497,9 +499,9 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
|
||||
if (!ecdsa_verify(signature_hash, signature_r, signature_s))
|
||||
{
|
||||
LOG_WARNING(LOADER, "EDAT: Metadata signature is invalid!");
|
||||
edat_log.warning("EDAT: Metadata signature is invalid!");
|
||||
if (((edat->block_size + 0ull) * block_num) > 0x100000000)
|
||||
LOG_WARNING(LOADER, "EDAT: *Due to large file size, metadata signature status may be incorrect!");
|
||||
edat_log.warning("EDAT: *Due to large file size, metadata signature status may be incorrect!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -511,7 +513,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
memcpy(signature_s + 01, header_signature + 0x14, 0x14);
|
||||
|
||||
if ((!memcmp(signature_r, zero_buf, 0x15)) || (!memcmp(signature_s, zero_buf, 0x15)))
|
||||
LOG_WARNING(LOADER, "EDAT: Header signature is invalid!");
|
||||
edat_log.warning("EDAT: Header signature is invalid!");
|
||||
else
|
||||
{
|
||||
// Setup header signature hash.
|
||||
@@ -522,7 +524,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
sha1(header_buf.get(), 0xD8, signature_hash );
|
||||
|
||||
if (!ecdsa_verify(signature_hash, signature_r, signature_s))
|
||||
LOG_WARNING(LOADER, "EDAT: Header signature is invalid!");
|
||||
edat_log.warning("EDAT: Header signature is invalid!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -589,9 +591,9 @@ int validate_npd_hashes(const char* file_name, const u8* klicensee, NPD_HEADER *
|
||||
if (verbose)
|
||||
{
|
||||
if (title_hash_result)
|
||||
LOG_NOTICE(LOADER, "EDAT: NPD title hash is valid!");
|
||||
edat_log.notice("EDAT: NPD title hash is valid!");
|
||||
else
|
||||
LOG_WARNING(LOADER, "EDAT: NPD title hash is invalid!");
|
||||
edat_log.warning("EDAT: NPD title hash is invalid!");
|
||||
}
|
||||
|
||||
|
||||
@@ -635,16 +637,16 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
|
||||
unsigned char npd_magic[4] = {0x4E, 0x50, 0x44, 0x00}; //NPD0
|
||||
if (memcmp(&NPD.magic, npd_magic, 4))
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: %s has invalid NPD header or already decrypted.", input_file_name);
|
||||
edat_log.error("EDAT: %s has invalid NPD header or already decrypted.", input_file_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
LOG_NOTICE(LOADER, "NPD HEADER");
|
||||
LOG_NOTICE(LOADER, "NPD version: %d", NPD.version);
|
||||
LOG_NOTICE(LOADER, "NPD license: %d", NPD.license);
|
||||
LOG_NOTICE(LOADER, "NPD type: %d", NPD.type);
|
||||
edat_log.notice("NPD HEADER");
|
||||
edat_log.notice("NPD version: %d", NPD.version);
|
||||
edat_log.notice("NPD license: %d", NPD.license);
|
||||
edat_log.notice("NPD type: %d", NPD.type);
|
||||
}
|
||||
|
||||
// Set decryption key.
|
||||
@@ -655,10 +657,10 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
LOG_NOTICE(LOADER, "SDAT HEADER");
|
||||
LOG_NOTICE(LOADER, "SDAT flags: 0x%08X", EDAT.flags);
|
||||
LOG_NOTICE(LOADER, "SDAT block size: 0x%08X", EDAT.block_size);
|
||||
LOG_NOTICE(LOADER, "SDAT file size: 0x%08X", EDAT.file_size);
|
||||
edat_log.notice("SDAT HEADER");
|
||||
edat_log.notice("SDAT flags: 0x%08X", EDAT.flags);
|
||||
edat_log.notice("SDAT block size: 0x%08X", EDAT.block_size);
|
||||
edat_log.notice("SDAT file size: 0x%08X", EDAT.file_size);
|
||||
}
|
||||
|
||||
// Generate SDAT key.
|
||||
@@ -668,10 +670,10 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
LOG_NOTICE(LOADER, "EDAT HEADER");
|
||||
LOG_NOTICE(LOADER, "EDAT flags: 0x%08X", EDAT.flags);
|
||||
LOG_NOTICE(LOADER, "EDAT block size: 0x%08X", EDAT.block_size);
|
||||
LOG_NOTICE(LOADER, "EDAT file size: 0x%08X", EDAT.file_size);
|
||||
edat_log.notice("EDAT HEADER");
|
||||
edat_log.notice("EDAT flags: 0x%08X", EDAT.flags);
|
||||
edat_log.notice("EDAT block size: 0x%08X", EDAT.block_size);
|
||||
edat_log.notice("EDAT file size: 0x%08X", EDAT.file_size);
|
||||
}
|
||||
|
||||
// Perform header validation (EDAT only).
|
||||
@@ -682,7 +684,7 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
|
||||
// Ignore header validation in DEBUG data.
|
||||
if ((EDAT.flags & EDAT_DEBUG_DATA_FLAG) != EDAT_DEBUG_DATA_FLAG)
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: NPD hash validation failed!");
|
||||
edat_log.error("EDAT: NPD hash validation failed!");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -707,48 +709,48 @@ bool extract_all_data(const fs::file* input, const fs::file* output, const char*
|
||||
|
||||
if (!test)
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: A valid RAP file is needed for this EDAT file!");
|
||||
edat_log.error("EDAT: A valid RAP file is needed for this EDAT file!");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if ((NPD.license & 0x1) == 0x1) // Type 1: Use network activation.
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: Network license not supported!");
|
||||
edat_log.error("EDAT: Network license not supported!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
int i;
|
||||
LOG_NOTICE(LOADER, "DEVKLIC: ");
|
||||
edat_log.notice("DEVKLIC: ");
|
||||
for (i = 0; i < 0x10; i++)
|
||||
LOG_NOTICE(LOADER, "%02X", devklic[i]);
|
||||
edat_log.notice("%02X", devklic[i]);
|
||||
|
||||
LOG_NOTICE(LOADER, "RIF KEY: ");
|
||||
edat_log.notice("RIF KEY: ");
|
||||
for (i = 0; i < 0x10; i++)
|
||||
LOG_NOTICE(LOADER, "%02X", rifkey[i]);
|
||||
edat_log.notice("%02X", rifkey[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
int i;
|
||||
LOG_NOTICE(LOADER, "DECRYPTION KEY: ");
|
||||
edat_log.notice("DECRYPTION KEY: ");
|
||||
for (i = 0; i < 0x10; i++)
|
||||
LOG_NOTICE(LOADER, "%02X", key[i]);
|
||||
edat_log.notice("%02X", key[i]);
|
||||
}
|
||||
|
||||
input->seek(0);
|
||||
if (check_data(key, &EDAT, &NPD, input, verbose))
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: Data parsing failed!");
|
||||
edat_log.error("EDAT: Data parsing failed!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
input->seek(0);
|
||||
if (decrypt_data(input, output, &EDAT, &NPD, key, verbose))
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: Data decryption failed!");
|
||||
edat_log.error("EDAT: Data decryption failed!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -779,13 +781,13 @@ bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& inpu
|
||||
unsigned char npd_magic[4] = { 0x4E, 0x50, 0x44, 0x00 }; //NPD0
|
||||
if (memcmp(&NPD.magic, npd_magic, 4))
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: %s has invalid NPD header or already decrypted.", input_file_name);
|
||||
edat_log.error("EDAT: %s has invalid NPD header or already decrypted.", input_file_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((EDAT.flags & SDAT_FLAG) == SDAT_FLAG)
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: SDATA file given to edat function");
|
||||
edat_log.error("EDAT: SDATA file given to edat function");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -797,7 +799,7 @@ bool VerifyEDATHeaderWithKLicense(const fs::file& input, const std::string& inpu
|
||||
// Ignore header validation in DEBUG data.
|
||||
if ((EDAT.flags & EDAT_DEBUG_DATA_FLAG) != EDAT_DEBUG_DATA_FLAG)
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: NPD hash validation failed!");
|
||||
edat_log.error("EDAT: NPD hash validation failed!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -848,18 +850,18 @@ fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name,
|
||||
memcpy(devklic, custom_klic, 0x10);
|
||||
else
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: Invalid custom klic!");
|
||||
edat_log.error("EDAT: Invalid custom klic!");
|
||||
return fs::file{};
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR(LOADER, "EDAT: Invalid mode!");
|
||||
edat_log.error("EDAT: Invalid mode!");
|
||||
return fs::file{};
|
||||
}
|
||||
|
||||
// Read the RAP file, if provided.
|
||||
if (rap_file_name.size())
|
||||
if (!rap_file_name.empty())
|
||||
{
|
||||
fs::file rap(rap_file_name);
|
||||
|
||||
@@ -901,7 +903,7 @@ bool EDATADecrypter::ReadHeader()
|
||||
// verify key
|
||||
if (validate_dev_klic(dev_key.data(), &npdHeader) == 0)
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: Failed validating klic");
|
||||
edat_log.error("EDAT: Failed validating klic");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -914,12 +916,12 @@ bool EDATADecrypter::ReadHeader()
|
||||
|
||||
if (dec_key == std::array<u8, 0x10>{0})
|
||||
{
|
||||
LOG_WARNING(LOADER, "EDAT: Empty Dec key!");
|
||||
edat_log.warning("EDAT: Empty Dec key!");
|
||||
}
|
||||
}
|
||||
else if ((npdHeader.license & 0x1) == 0x1) // Type 1: Use network activation.
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: Network license not supported!");
|
||||
edat_log.error("EDAT: Network license not supported!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -964,9 +966,9 @@ u64 EDATADecrypter::ReadData(u64 pos, u8* data, u64 size)
|
||||
{
|
||||
edata_file.seek(0);
|
||||
u64 res = decrypt_block(&edata_file, &data_buf[writeOffset], &edatHeader, &npdHeader, dec_key.data(), i, total_blocks, edatHeader.file_size);
|
||||
if (res == -1)
|
||||
if (res == umax)
|
||||
{
|
||||
LOG_ERROR(LOADER, "Error Decrypting data");
|
||||
edat_log.error("Error Decrypting data");
|
||||
return 0;
|
||||
}
|
||||
writeOffset += res;
|
||||
|
||||
+38
-29
@@ -1,4 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
#include "utils.h"
|
||||
#include "aes.h"
|
||||
#include "sha1.h"
|
||||
@@ -8,8 +8,16 @@
|
||||
#include "Emu/VFS.h"
|
||||
#include "unpkg.h"
|
||||
|
||||
LOG_CHANNEL(pkg_log, "PKG");
|
||||
|
||||
bool pkg_install(const std::string& path, atomic_t<double>& sync)
|
||||
{
|
||||
if (!fs::is_file(path))
|
||||
{
|
||||
pkg_log.error("PKG file not found!");
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::size_t BUF_SIZE = 8192 * 1024; // 8 MB
|
||||
|
||||
std::vector<fs::file> filelist;
|
||||
@@ -70,13 +78,13 @@ bool pkg_install(const std::string& path, atomic_t<double>& sync)
|
||||
|
||||
if (archive_read(&header, sizeof(header)) != sizeof(header))
|
||||
{
|
||||
LOG_ERROR(LOADER, "PKG file is too short!");
|
||||
pkg_log.error("PKG file is too short!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header.pkg_magic != "\x7FPKG"_u32)
|
||||
{
|
||||
LOG_ERROR(LOADER, "Not a PKG file!");
|
||||
pkg_log.error("Not a PKG file!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -86,7 +94,7 @@ bool pkg_install(const std::string& path, atomic_t<double>& sync)
|
||||
case PKG_RELEASE_TYPE_RELEASE: break;
|
||||
default:
|
||||
{
|
||||
LOG_ERROR(LOADER, "Unknown PKG type (0x%x)", type);
|
||||
pkg_log.error("Unknown PKG type (0x%x)", type);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -97,7 +105,7 @@ bool pkg_install(const std::string& path, atomic_t<double>& sync)
|
||||
case PKG_PLATFORM_TYPE_PSP: break;
|
||||
default:
|
||||
{
|
||||
LOG_ERROR(LOADER, "Unknown PKG platform (0x%x)", platform);
|
||||
pkg_log.error("Unknown PKG platform (0x%x)", platform);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -105,9 +113,9 @@ bool pkg_install(const std::string& path, atomic_t<double>& sync)
|
||||
if (header.pkg_size > filelist[0].size())
|
||||
{
|
||||
// Check if multi-files pkg
|
||||
if (path.size() < 7 || path.compare(path.size() - 7, 7, "_00.pkg", 7) != 0)
|
||||
if (!path.ends_with("_00.pkg"))
|
||||
{
|
||||
LOG_ERROR(LOADER, "PKG file size mismatch (pkg_size=0x%llx)", header.pkg_size);
|
||||
pkg_log.error("PKG file size mismatch (pkg_size=0x%llx)", header.pkg_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -120,7 +128,7 @@ bool pkg_install(const std::string& path, atomic_t<double>& sync)
|
||||
fs::file archive_file(archive_filename);
|
||||
if (!archive_file)
|
||||
{
|
||||
LOG_ERROR(LOADER, "Missing part of the multi-files pkg: %s", archive_filename);
|
||||
pkg_log.error("Missing part of the multi-files pkg: %s", archive_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -131,7 +139,7 @@ bool pkg_install(const std::string& path, atomic_t<double>& sync)
|
||||
|
||||
if (header.data_size + header.data_offset > header.pkg_size)
|
||||
{
|
||||
LOG_ERROR(LOADER, "PKG data size mismatch (data_size=0x%llx, data_offset=0x%llx, file_size=0x%llx)", header.data_size, header.data_offset, header.pkg_size);
|
||||
pkg_log.error("PKG data size mismatch (data_size=0x%llx, data_offset=0x%llx, file_size=0x%llx)", header.data_size, header.data_offset, header.pkg_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -205,7 +213,7 @@ bool pkg_install(const std::string& path, atomic_t<double>& sync)
|
||||
|
||||
if (!fs::create_path(dir))
|
||||
{
|
||||
LOG_ERROR(LOADER, "PKG: Could not create the installation directory %s", dir);
|
||||
pkg_log.error("PKG: Could not create the installation directory %s", dir);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -285,7 +293,7 @@ bool pkg_install(const std::string& path, atomic_t<double>& sync)
|
||||
const uchar psp2t3[] = {0xAF, 0x07, 0xFD, 0x59, 0x65, 0x25, 0x27, 0xBA, 0xF1, 0x33, 0x89, 0x66, 0x8B, 0x17, 0xD9, 0xEA};
|
||||
|
||||
aes_context ctx;
|
||||
aes_setkey_enc(&ctx, content_type == 0x15 ? psp2t1 : content_type == 0x16 ? psp2t2 : psp2t3, 128);
|
||||
aes_setkey_enc(&ctx, content_type == 0x15u ? psp2t1 : content_type == 0x16u ? psp2t2 : psp2t3, 128);
|
||||
aes_crypt_ecb(&ctx, AES_ENCRYPT, reinterpret_cast<const uchar*>(&header.klicensee), dec_key.data());
|
||||
decrypt(0, header.file_count * sizeof(PKGEntry), dec_key.data());
|
||||
}
|
||||
@@ -303,12 +311,12 @@ bool pkg_install(const std::string& path, atomic_t<double>& sync)
|
||||
|
||||
for (const auto& entry : entries)
|
||||
{
|
||||
const bool is_psp = (entry.type & PKG_FILE_ENTRY_PSP) != 0;
|
||||
const bool is_psp = (entry.type & PKG_FILE_ENTRY_PSP) != 0u;
|
||||
|
||||
if (entry.name_size > 256)
|
||||
{
|
||||
num_failures++;
|
||||
LOG_ERROR(LOADER, "PKG name size is too big (0x%x)", entry.name_size);
|
||||
pkg_log.error("PKG name size is too big (0x%x)", entry.name_size);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -316,7 +324,7 @@ bool pkg_install(const std::string& path, atomic_t<double>& sync)
|
||||
|
||||
std::string name{reinterpret_cast<char*>(buf.get()), entry.name_size};
|
||||
|
||||
LOG_NOTICE(LOADER, "Entry 0x%08x: %s", entry.type, name);
|
||||
pkg_log.notice("Entry 0x%08x: %s", entry.type, name);
|
||||
|
||||
switch (entry.type & 0xff)
|
||||
{
|
||||
@@ -331,14 +339,15 @@ bool pkg_install(const std::string& path, atomic_t<double>& sync)
|
||||
case 0x13:
|
||||
case 0x15:
|
||||
case 0x16:
|
||||
case 0x19:
|
||||
{
|
||||
const std::string path = dir + vfs::escape(name);
|
||||
|
||||
const bool did_overwrite = fs::is_file(path);
|
||||
|
||||
if (did_overwrite && (entry.type & PKG_FILE_ENTRY_OVERWRITE) == 0)
|
||||
if (did_overwrite && !(entry.type & PKG_FILE_ENTRY_OVERWRITE))
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Didn't overwrite %s", name);
|
||||
pkg_log.notice("Didn't overwrite %s", name);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -352,14 +361,14 @@ bool pkg_install(const std::string& path, atomic_t<double>& sync)
|
||||
if (decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : dec_key.data()) != block_size)
|
||||
{
|
||||
extract_success = false;
|
||||
LOG_ERROR(LOADER, "Failed to extract file %s", path);
|
||||
pkg_log.error("Failed to extract file %s", path);
|
||||
break;
|
||||
}
|
||||
|
||||
if (out.write(buf.get(), block_size) != block_size)
|
||||
{
|
||||
extract_success = false;
|
||||
LOG_ERROR(LOADER, "Failed to write file %s", path);
|
||||
pkg_log.error("Failed to write file %s", path);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -367,7 +376,7 @@ bool pkg_install(const std::string& path, atomic_t<double>& sync)
|
||||
{
|
||||
if (was_null)
|
||||
{
|
||||
LOG_ERROR(LOADER, "Package installation cancelled: %s", dir);
|
||||
pkg_log.error("Package installation cancelled: %s", dir);
|
||||
out.close();
|
||||
fs::remove_all(dir, true);
|
||||
return false;
|
||||
@@ -379,14 +388,14 @@ bool pkg_install(const std::string& path, atomic_t<double>& sync)
|
||||
}
|
||||
|
||||
if (extract_success)
|
||||
{
|
||||
{
|
||||
if (did_overwrite)
|
||||
{
|
||||
LOG_WARNING(LOADER, "Overwritten file %s", name);
|
||||
pkg_log.warning("Overwritten file %s", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Created file %s", name);
|
||||
pkg_log.notice("Created file %s", name);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -397,7 +406,7 @@ bool pkg_install(const std::string& path, atomic_t<double>& sync)
|
||||
else
|
||||
{
|
||||
num_failures++;
|
||||
LOG_ERROR(LOADER, "Failed to create file %s", path);
|
||||
pkg_log.error("Failed to create file %s", path);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -410,16 +419,16 @@ bool pkg_install(const std::string& path, atomic_t<double>& sync)
|
||||
|
||||
if (fs::create_dir(path))
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Created directory %s", name);
|
||||
pkg_log.notice("Created directory %s", name);
|
||||
}
|
||||
else if (fs::is_dir(path))
|
||||
{
|
||||
LOG_WARNING(LOADER, "Reused existing directory %s", name);
|
||||
pkg_log.warning("Reused existing directory %s", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
num_failures++;
|
||||
LOG_ERROR(LOADER, "Failed to create directory %s", path);
|
||||
pkg_log.error("Failed to create directory %s", path);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -428,19 +437,19 @@ bool pkg_install(const std::string& path, atomic_t<double>& sync)
|
||||
default:
|
||||
{
|
||||
num_failures++;
|
||||
LOG_ERROR(LOADER, "Unknown PKG entry type (0x%x) %s", entry.type, name);
|
||||
pkg_log.error("Unknown PKG entry type (0x%x) %s", entry.type, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (num_failures == 0)
|
||||
{
|
||||
LOG_SUCCESS(LOADER, "Package successfully installed to %s", dir);
|
||||
pkg_log.success("Package successfully installed to %s", dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
fs::remove_all(dir, true);
|
||||
LOG_ERROR(LOADER, "Package installation failed: %s", dir);
|
||||
pkg_log.error("Package installation failed: %s", dir);
|
||||
}
|
||||
return num_failures == 0;
|
||||
}
|
||||
|
||||
+118
-111
@@ -1,4 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
#include "aes.h"
|
||||
#include "sha1.h"
|
||||
#include "utils.h"
|
||||
@@ -203,10 +203,10 @@ void AppInfo::Load(const fs::file& f)
|
||||
|
||||
void AppInfo::Show()
|
||||
{
|
||||
LOG_NOTICE(LOADER, "AuthID: 0x%llx", authid);
|
||||
LOG_NOTICE(LOADER, "VendorID: 0x%08x", vendor_id);
|
||||
LOG_NOTICE(LOADER, "SELF type: 0x%08x", self_type);
|
||||
LOG_NOTICE(LOADER, "Version: 0x%llx", version);
|
||||
self_log.notice("AuthID: 0x%llx", authid);
|
||||
self_log.notice("VendorID: 0x%08x", vendor_id);
|
||||
self_log.notice("SELF type: 0x%08x", self_type);
|
||||
self_log.notice("Version: 0x%llx", version);
|
||||
}
|
||||
|
||||
void SectionInfo::Load(const fs::file& f)
|
||||
@@ -221,12 +221,12 @@ void SectionInfo::Load(const fs::file& f)
|
||||
|
||||
void SectionInfo::Show()
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Offset: 0x%llx", offset);
|
||||
LOG_NOTICE(LOADER, "Size: 0x%llx", size);
|
||||
LOG_NOTICE(LOADER, "Compressed: 0x%08x", compressed);
|
||||
LOG_NOTICE(LOADER, "Unknown1: 0x%08x", unknown1);
|
||||
LOG_NOTICE(LOADER, "Unknown2: 0x%08x", unknown2);
|
||||
LOG_NOTICE(LOADER, "Encrypted: 0x%08x", encrypted);
|
||||
self_log.notice("Offset: 0x%llx", offset);
|
||||
self_log.notice("Size: 0x%llx", size);
|
||||
self_log.notice("Compressed: 0x%08x", compressed);
|
||||
self_log.notice("Unknown1: 0x%08x", unknown1);
|
||||
self_log.notice("Unknown2: 0x%08x", unknown2);
|
||||
self_log.notice("Encrypted: 0x%08x", encrypted);
|
||||
}
|
||||
|
||||
void SCEVersionInfo::Load(const fs::file& f)
|
||||
@@ -239,10 +239,10 @@ void SCEVersionInfo::Load(const fs::file& f)
|
||||
|
||||
void SCEVersionInfo::Show()
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Sub-header type: 0x%08x", subheader_type);
|
||||
LOG_NOTICE(LOADER, "Present: 0x%08x", present);
|
||||
LOG_NOTICE(LOADER, "Size: 0x%08x", size);
|
||||
LOG_NOTICE(LOADER, "Unknown: 0x%08x", unknown);
|
||||
self_log.notice("Sub-header type: 0x%08x", subheader_type);
|
||||
self_log.notice("Present: 0x%08x", present);
|
||||
self_log.notice("Size: 0x%08x", size);
|
||||
self_log.notice("Unknown: 0x%08x", unknown);
|
||||
}
|
||||
|
||||
void ControlInfo::Load(const fs::file& f)
|
||||
@@ -293,20 +293,20 @@ void ControlInfo::Load(const fs::file& f)
|
||||
|
||||
void ControlInfo::Show()
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Type: 0x%08x", type);
|
||||
LOG_NOTICE(LOADER, "Size: 0x%08x", size);
|
||||
LOG_NOTICE(LOADER, "Next: 0x%llx", next);
|
||||
self_log.notice("Type: 0x%08x", type);
|
||||
self_log.notice("Size: 0x%08x", size);
|
||||
self_log.notice("Next: 0x%llx", next);
|
||||
|
||||
if (type == 1)
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Control flag 1: 0x%08x", control_flags.ctrl_flag1);
|
||||
LOG_NOTICE(LOADER, "Unknown1: 0x%08x", control_flags.unknown1);
|
||||
LOG_NOTICE(LOADER, "Unknown2: 0x%08x", control_flags.unknown2);
|
||||
LOG_NOTICE(LOADER, "Unknown3: 0x%08x", control_flags.unknown3);
|
||||
LOG_NOTICE(LOADER, "Unknown4: 0x%08x", control_flags.unknown4);
|
||||
LOG_NOTICE(LOADER, "Unknown5: 0x%08x", control_flags.unknown5);
|
||||
LOG_NOTICE(LOADER, "Unknown6: 0x%08x", control_flags.unknown6);
|
||||
LOG_NOTICE(LOADER, "Unknown7: 0x%08x", control_flags.unknown7);
|
||||
self_log.notice("Control flag 1: 0x%08x", control_flags.ctrl_flag1);
|
||||
self_log.notice("Unknown1: 0x%08x", control_flags.unknown1);
|
||||
self_log.notice("Unknown2: 0x%08x", control_flags.unknown2);
|
||||
self_log.notice("Unknown3: 0x%08x", control_flags.unknown3);
|
||||
self_log.notice("Unknown4: 0x%08x", control_flags.unknown4);
|
||||
self_log.notice("Unknown5: 0x%08x", control_flags.unknown5);
|
||||
self_log.notice("Unknown6: 0x%08x", control_flags.unknown6);
|
||||
self_log.notice("Unknown7: 0x%08x", control_flags.unknown7);
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
@@ -316,8 +316,8 @@ void ControlInfo::Show()
|
||||
for (int i = 0; i < 20; i++)
|
||||
digest_str += fmt::format("%02x", file_digest_30.digest[i]);
|
||||
|
||||
LOG_NOTICE(LOADER, "Digest: %s", digest_str.c_str());
|
||||
LOG_NOTICE(LOADER, "Unknown: 0x%llx", file_digest_30.unknown);
|
||||
self_log.notice("Digest: %s", digest_str.c_str());
|
||||
self_log.notice("Unknown: 0x%llx", file_digest_30.unknown);
|
||||
}
|
||||
else if (size == 0x40)
|
||||
{
|
||||
@@ -329,9 +329,9 @@ void ControlInfo::Show()
|
||||
digest_str2 += fmt::format("%02x", file_digest_40.digest2[i]);
|
||||
}
|
||||
|
||||
LOG_NOTICE(LOADER, "Digest1: %s", digest_str1.c_str());
|
||||
LOG_NOTICE(LOADER, "Digest2: %s", digest_str2.c_str());
|
||||
LOG_NOTICE(LOADER, "Unknown: 0x%llx", file_digest_40.unknown);
|
||||
self_log.notice("Digest1: %s", digest_str1.c_str());
|
||||
self_log.notice("Digest2: %s", digest_str2.c_str());
|
||||
self_log.notice("Unknown: 0x%llx", file_digest_40.unknown);
|
||||
}
|
||||
}
|
||||
else if (type == 3)
|
||||
@@ -349,16 +349,16 @@ void ControlInfo::Show()
|
||||
xordigest_str += fmt::format("%02x", npdrm.xordigest[i]);
|
||||
}
|
||||
|
||||
LOG_NOTICE(LOADER, "Magic: 0x%08x", npdrm.magic);
|
||||
LOG_NOTICE(LOADER, "Unknown1: 0x%08x", npdrm.unknown1);
|
||||
LOG_NOTICE(LOADER, "License: 0x%08x", npdrm.license);
|
||||
LOG_NOTICE(LOADER, "Type: 0x%08x", npdrm.type);
|
||||
LOG_NOTICE(LOADER, "ContentID: %s", contentid_str.c_str());
|
||||
LOG_NOTICE(LOADER, "Digest: %s", digest_str.c_str());
|
||||
LOG_NOTICE(LOADER, "Inverse digest: %s", invdigest_str.c_str());
|
||||
LOG_NOTICE(LOADER, "XOR digest: %s", xordigest_str.c_str());
|
||||
LOG_NOTICE(LOADER, "Unknown2: 0x%llx", npdrm.unknown2);
|
||||
LOG_NOTICE(LOADER, "Unknown3: 0x%llx", npdrm.unknown3);
|
||||
self_log.notice("Magic: 0x%08x", npdrm.magic);
|
||||
self_log.notice("Unknown1: 0x%08x", npdrm.unknown1);
|
||||
self_log.notice("License: 0x%08x", npdrm.license);
|
||||
self_log.notice("Type: 0x%08x", npdrm.type);
|
||||
self_log.notice("ContentID: %s", contentid_str.c_str());
|
||||
self_log.notice("Digest: %s", digest_str.c_str());
|
||||
self_log.notice("Inverse digest: %s", invdigest_str.c_str());
|
||||
self_log.notice("XOR digest: %s", xordigest_str.c_str());
|
||||
self_log.notice("Unknown2: 0x%llx", npdrm.unknown2);
|
||||
self_log.notice("Unknown3: 0x%llx", npdrm.unknown3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,10 +384,10 @@ void MetadataInfo::Show()
|
||||
iv_pad_str += fmt::format("%02x", iv_pad[i]);
|
||||
}
|
||||
|
||||
LOG_NOTICE(LOADER, "Key: %s", key_str.c_str());
|
||||
LOG_NOTICE(LOADER, "Key pad: %s", key_pad_str.c_str());
|
||||
LOG_NOTICE(LOADER, "IV: %s", iv_str.c_str());
|
||||
LOG_NOTICE(LOADER, "IV pad: %s", iv_pad_str.c_str());
|
||||
self_log.notice("Key: %s", key_str.c_str());
|
||||
self_log.notice("Key pad: %s", key_pad_str.c_str());
|
||||
self_log.notice("IV: %s", iv_str.c_str());
|
||||
self_log.notice("IV pad: %s", iv_pad_str.c_str());
|
||||
}
|
||||
|
||||
void MetadataHeader::Load(u8* in)
|
||||
@@ -412,13 +412,13 @@ void MetadataHeader::Load(u8* in)
|
||||
|
||||
void MetadataHeader::Show()
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Signature input length: 0x%llx", signature_input_length);
|
||||
LOG_NOTICE(LOADER, "Unknown1: 0x%08x", unknown1);
|
||||
LOG_NOTICE(LOADER, "Section count: 0x%08x", section_count);
|
||||
LOG_NOTICE(LOADER, "Key count: 0x%08x", key_count);
|
||||
LOG_NOTICE(LOADER, "Optional header size: 0x%08x", opt_header_size);
|
||||
LOG_NOTICE(LOADER, "Unknown2: 0x%08x", unknown2);
|
||||
LOG_NOTICE(LOADER, "Unknown3: 0x%08x", unknown3);
|
||||
self_log.notice("Signature input length: 0x%llx", signature_input_length);
|
||||
self_log.notice("Unknown1: 0x%08x", unknown1);
|
||||
self_log.notice("Section count: 0x%08x", section_count);
|
||||
self_log.notice("Key count: 0x%08x", key_count);
|
||||
self_log.notice("Optional header size: 0x%08x", opt_header_size);
|
||||
self_log.notice("Unknown2: 0x%08x", unknown2);
|
||||
self_log.notice("Unknown3: 0x%08x", unknown3);
|
||||
}
|
||||
|
||||
void MetadataSectionHeader::Load(u8* in)
|
||||
@@ -449,16 +449,16 @@ void MetadataSectionHeader::Load(u8* in)
|
||||
|
||||
void MetadataSectionHeader::Show()
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Data offset: 0x%llx", data_offset);
|
||||
LOG_NOTICE(LOADER, "Data size: 0x%llx", data_size);
|
||||
LOG_NOTICE(LOADER, "Type: 0x%08x", type);
|
||||
LOG_NOTICE(LOADER, "Program index: 0x%08x", program_idx);
|
||||
LOG_NOTICE(LOADER, "Hashed: 0x%08x", hashed);
|
||||
LOG_NOTICE(LOADER, "SHA1 index: 0x%08x", sha1_idx);
|
||||
LOG_NOTICE(LOADER, "Encrypted: 0x%08x", encrypted);
|
||||
LOG_NOTICE(LOADER, "Key index: 0x%08x", key_idx);
|
||||
LOG_NOTICE(LOADER, "IV index: 0x%08x", iv_idx);
|
||||
LOG_NOTICE(LOADER, "Compressed: 0x%08x", compressed);
|
||||
self_log.notice("Data offset: 0x%llx", data_offset);
|
||||
self_log.notice("Data size: 0x%llx", data_size);
|
||||
self_log.notice("Type: 0x%08x", type);
|
||||
self_log.notice("Program index: 0x%08x", program_idx);
|
||||
self_log.notice("Hashed: 0x%08x", hashed);
|
||||
self_log.notice("SHA1 index: 0x%08x", sha1_idx);
|
||||
self_log.notice("Encrypted: 0x%08x", encrypted);
|
||||
self_log.notice("Key index: 0x%08x", key_idx);
|
||||
self_log.notice("IV index: 0x%08x", iv_idx);
|
||||
self_log.notice("Compressed: 0x%08x", compressed);
|
||||
}
|
||||
|
||||
void SectionHash::Load(const fs::file& f)
|
||||
@@ -664,7 +664,7 @@ bool SCEDecrypter::LoadHeaders()
|
||||
// Check SCE magic.
|
||||
if (!sce_hdr.CheckMagic())
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: Not a SELF file!");
|
||||
self_log.error("SELF: Not a SELF file!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -708,7 +708,7 @@ bool SCEDecrypter::LoadMetadata(const u8 erk[32], const u8 riv[16])
|
||||
if ((meta_info.key_pad[0] != 0x00) ||
|
||||
(meta_info.iv_pad[0] != 0x00))
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: Failed to decrypt metadata info!");
|
||||
self_log.error("SELF: Failed to decrypt metadata info!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -832,8 +832,14 @@ std::vector<fs::file> SCEDecrypter::MakeFile()
|
||||
strm.avail_out = BUFSIZE;
|
||||
strm.next_in = data_buf.get()+data_buf_offset;
|
||||
strm.next_out = tempbuf;
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
#endif
|
||||
int ret = inflateInit(&strm);
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
while (strm.avail_in)
|
||||
{
|
||||
ret = inflate(&strm, Z_NO_FLUSH);
|
||||
@@ -881,7 +887,6 @@ std::vector<fs::file> SCEDecrypter::MakeFile()
|
||||
SELFDecrypter::SELFDecrypter(const fs::file& s)
|
||||
: self_f(s)
|
||||
, key_v()
|
||||
, data_buf_length(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -899,7 +904,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
|
||||
// Check SCE magic.
|
||||
if (!sce_hdr.CheckMagic())
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: Not a SELF file!");
|
||||
self_log.error("SELF: Not a SELF file!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -929,7 +934,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
|
||||
phdr32_arr.clear();
|
||||
if(elf32_hdr.e_phoff == 0 && elf32_hdr.e_phnum)
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: ELF program header offset is null!");
|
||||
self_log.error("SELF: ELF program header offset is null!");
|
||||
return false;
|
||||
}
|
||||
self_f.seek(self_hdr.se_phdroff);
|
||||
@@ -945,7 +950,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
|
||||
|
||||
if (elf64_hdr.e_phoff == 0 && elf64_hdr.e_phnum)
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: ELF program header offset is null!");
|
||||
self_log.error("SELF: ELF program header offset is null!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -997,7 +1002,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
|
||||
|
||||
if (elf32_hdr.e_shoff == 0 && elf32_hdr.e_shnum)
|
||||
{
|
||||
LOG_WARNING(LOADER, "SELF: ELF section header offset is null!");
|
||||
self_log.warning("SELF: ELF section header offset is null!");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1014,7 +1019,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
|
||||
shdr64_arr.clear();
|
||||
if (elf64_hdr.e_shoff == 0 && elf64_hdr.e_shnum)
|
||||
{
|
||||
LOG_WARNING(LOADER, "SELF: ELF section header offset is null!");
|
||||
self_log.warning("SELF: ELF section header offset is null!");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1037,46 +1042,46 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
|
||||
|
||||
void SELFDecrypter::ShowHeaders(bool isElf32)
|
||||
{
|
||||
LOG_NOTICE(LOADER, "SCE header");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
self_log.notice("SCE header");
|
||||
self_log.notice("----------------------------------------------------");
|
||||
sce_hdr.Show();
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "SELF header");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
self_log.notice("----------------------------------------------------");
|
||||
self_log.notice("SELF header");
|
||||
self_log.notice("----------------------------------------------------");
|
||||
self_hdr.Show();
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "APP INFO");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
self_log.notice("----------------------------------------------------");
|
||||
self_log.notice("APP INFO");
|
||||
self_log.notice("----------------------------------------------------");
|
||||
app_info.Show();
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "ELF header");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
self_log.notice("----------------------------------------------------");
|
||||
self_log.notice("ELF header");
|
||||
self_log.notice("----------------------------------------------------");
|
||||
isElf32 ? elf32_hdr.Show() : elf64_hdr.Show();
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "ELF program headers");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
self_log.notice("----------------------------------------------------");
|
||||
self_log.notice("ELF program headers");
|
||||
self_log.notice("----------------------------------------------------");
|
||||
for(unsigned int i = 0; i < ((isElf32) ? phdr32_arr.size() : phdr64_arr.size()); i++)
|
||||
isElf32 ? phdr32_arr[i].Show() : phdr64_arr[i].Show();
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "Section info");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
self_log.notice("----------------------------------------------------");
|
||||
self_log.notice("Section info");
|
||||
self_log.notice("----------------------------------------------------");
|
||||
for(unsigned int i = 0; i < secinfo_arr.size(); i++)
|
||||
secinfo_arr[i].Show();
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "SCE version info");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
self_log.notice("----------------------------------------------------");
|
||||
self_log.notice("SCE version info");
|
||||
self_log.notice("----------------------------------------------------");
|
||||
scev_info.Show();
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "Control info");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
self_log.notice("----------------------------------------------------");
|
||||
self_log.notice("Control info");
|
||||
self_log.notice("----------------------------------------------------");
|
||||
for(unsigned int i = 0; i < ctrlinfo_arr.size(); i++)
|
||||
ctrlinfo_arr[i].Show();
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "ELF section headers");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
self_log.notice("----------------------------------------------------");
|
||||
self_log.notice("ELF section headers");
|
||||
self_log.notice("----------------------------------------------------");
|
||||
for(unsigned int i = 0; i < ((isElf32) ? shdr32_arr.size() : shdr64_arr.size()); i++)
|
||||
isElf32 ? shdr32_arr[i].Show() : shdr64_arr[i].Show();
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
self_log.notice("----------------------------------------------------");
|
||||
}
|
||||
|
||||
bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
||||
@@ -1100,13 +1105,13 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
||||
// If not, the data has no NPDRM layer.
|
||||
if (!ctrl)
|
||||
{
|
||||
LOG_TRACE(LOADER, "SELF: No NPDRM control info found!");
|
||||
self_log.trace("SELF: No NPDRM control info found!");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ctrl->npdrm.license == 1) // Network license.
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: Can't decrypt network NPDRM!");
|
||||
self_log.error("SELF: Can't decrypt network NPDRM!");
|
||||
return false;
|
||||
}
|
||||
else if (ctrl->npdrm.license == 2) // Local license.
|
||||
@@ -1114,7 +1119,7 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
||||
// Try to find a RAP file to get the key.
|
||||
if (!GetKeyFromRap(ctrl->npdrm.content_id, npdrm_key))
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: Can't find RAP file for NPDRM decryption!");
|
||||
self_log.error("SELF: Can't find RAP file for NPDRM decryption!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1128,7 +1133,7 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: Invalid NPDRM license type!");
|
||||
self_log.error("SELF: Invalid NPDRM license type!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1194,7 +1199,7 @@ bool SELFDecrypter::LoadMetadata(u8* klic_key)
|
||||
if ((meta_info.key_pad[0] != 0x00) ||
|
||||
(meta_info.iv_pad[0] != 0x00))
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: Failed to decrypt metadata info!");
|
||||
self_log.error("SELF: Failed to decrypt metadata info!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1319,11 +1324,13 @@ bool SELFDecrypter::GetKeyFromRap(u8* content_id, u8* npdrm_key)
|
||||
|
||||
if (!rap_file)
|
||||
{
|
||||
LOG_FATAL(LOADER, "Failed to load RAP file: %s. Make sure the file extension is lowercase.", rap_path);
|
||||
self_log.fatal("Failed to locate the game license file: %s."
|
||||
"\nEnsure the .rap license file is placed in the dev_hdd0/home/00000001/exdata folder with a lowercase file extension."
|
||||
"\nIf you need assistance on dumping the license file from your PS3, read our quickstart guide: https://rpcs3.net/quickstart", rap_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_NOTICE(LOADER, "Loading RAP file %s.rap", ci_str);
|
||||
self_log.notice("Loading RAP file %s.rap", ci_str);
|
||||
rap_file.read(rap_key, 0x10);
|
||||
|
||||
// Convert the RAP key.
|
||||
@@ -1367,7 +1374,7 @@ static bool CheckDebugSelf(fs::file& s)
|
||||
// Check for DEBUG version.
|
||||
if (key_version == 0x80 || key_version == 0xc0)
|
||||
{
|
||||
LOG_WARNING(LOADER, "Debug SELF detected! Removing fake header...");
|
||||
self_log.warning("Debug SELF detected! Removing fake header...");
|
||||
|
||||
// Get the real elf offset.
|
||||
s.seek(0x10);
|
||||
@@ -1419,21 +1426,21 @@ fs::file decrypt_self(fs::file elf_or_self, u8* klic_key, SelfAdditionalInfo* ou
|
||||
// Load the SELF file headers.
|
||||
if (!self_dec.LoadHeaders(isElf32, out_info))
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: Failed to load SELF file headers!");
|
||||
self_log.error("SELF: Failed to load SELF file headers!");
|
||||
return fs::file{};
|
||||
}
|
||||
|
||||
// Load and decrypt the SELF file metadata.
|
||||
if (!self_dec.LoadMetadata(klic_key))
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: Failed to load SELF file metadata!");
|
||||
self_log.error("SELF: Failed to load SELF file metadata!");
|
||||
return fs::file{};
|
||||
}
|
||||
|
||||
// Decrypt the SELF file data.
|
||||
if (!self_dec.DecryptData())
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: Failed to decrypt SELF file data!");
|
||||
self_log.error("SELF: Failed to decrypt SELF file data!");
|
||||
return fs::file{};
|
||||
}
|
||||
|
||||
@@ -1462,14 +1469,14 @@ bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key)
|
||||
// Load the SELF file headers.
|
||||
if (!self_dec.LoadHeaders(isElf32))
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: Failed to load SELF file headers!");
|
||||
self_log.error("SELF: Failed to load SELF file headers!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load and decrypt the SELF file metadata.
|
||||
if (!self_dec.LoadMetadata(klic_key))
|
||||
{
|
||||
LOG_ERROR(LOADER, "SELF: Failed to load SELF file metadata!");
|
||||
self_log.error("SELF: Failed to load SELF file metadata!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
#include "Utilities/File.h"
|
||||
#include "Utilities/Log.h"
|
||||
|
||||
struct AppInfo
|
||||
LOG_CHANNEL(self_log, "SELF");
|
||||
|
||||
struct AppInfo
|
||||
{
|
||||
u64 authid;
|
||||
u32 vendor_id;
|
||||
@@ -338,7 +340,7 @@ struct SelfHeader
|
||||
u64 se_controloff;
|
||||
u64 se_controlsize;
|
||||
u64 pad;
|
||||
|
||||
|
||||
void Load(const fs::file& f);
|
||||
void Show(){}
|
||||
};
|
||||
@@ -387,7 +389,7 @@ class SELFDecrypter
|
||||
SceHeader sce_hdr;
|
||||
SelfHeader self_hdr;
|
||||
AppInfo app_info;
|
||||
|
||||
|
||||
// ELF64 header and program header/section header arrays.
|
||||
Elf64_Ehdr elf64_hdr;
|
||||
std::vector<Elf64_Shdr> shdr64_arr;
|
||||
@@ -412,7 +414,7 @@ class SELFDecrypter
|
||||
std::unique_ptr<u8[]> data_keys;
|
||||
u32 data_keys_length;
|
||||
std::unique_ptr<u8[]> data_buf;
|
||||
u32 data_buf_length;
|
||||
u32 data_buf_length = 0;
|
||||
|
||||
// Main key vault instance.
|
||||
KeyVault key_v;
|
||||
@@ -469,9 +471,9 @@ private:
|
||||
// Check for errors (TODO: Probably safe to remove this once these changes have passed testing.)
|
||||
switch (rv)
|
||||
{
|
||||
case Z_MEM_ERROR: LOG_ERROR(LOADER, "MakeELF encountered a Z_MEM_ERROR!"); break;
|
||||
case Z_BUF_ERROR: LOG_ERROR(LOADER, "MakeELF encountered a Z_BUF_ERROR!"); break;
|
||||
case Z_DATA_ERROR: LOG_ERROR(LOADER, "MakeELF encountered a Z_DATA_ERROR!"); break;
|
||||
case Z_MEM_ERROR: self_log.error("MakeELF encountered a Z_MEM_ERROR!"); break;
|
||||
case Z_BUF_ERROR: self_log.error("MakeELF encountered a Z_BUF_ERROR!"); break;
|
||||
case Z_DATA_ERROR: self_log.error("MakeELF encountered a Z_DATA_ERROR!"); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
#include "OpenALBackend.h"
|
||||
|
||||
@@ -7,23 +6,23 @@
|
||||
#pragma comment(lib, "OpenAL32.lib")
|
||||
#endif
|
||||
|
||||
LOG_CHANNEL(OpenAL);
|
||||
|
||||
#define checkForAlError(sit) do { ALenum g_last_al_error = alGetError(); if(g_last_al_error != AL_NO_ERROR) fmt::throw_exception("%s: OpenAL error 0x%04x", sit, g_last_al_error); } while(0)
|
||||
#define checkForAlcError(sit) do { ALCenum g_last_alc_error = alcGetError(m_device); if(g_last_alc_error != ALC_NO_ERROR) fmt::throw_exception("%s: OpenALC error 0x%04x", sit, g_last_alc_error); } while(0)
|
||||
|
||||
#define checkForAlError(sit) do { ALenum g_last_al_error = alGetError(); if(g_last_al_error != AL_NO_ERROR) OpenAL.error("%s: OpenAL error 0x%04x", sit, g_last_al_error); } while(0)
|
||||
#define checkForAlcError(sit) do { ALCenum g_last_alc_error = alcGetError(m_device); if(g_last_alc_error != ALC_NO_ERROR) { OpenAL.error("%s: OpenALC error 0x%04x", sit, g_last_alc_error); return; }} while(0)
|
||||
|
||||
OpenALBackend::OpenALBackend()
|
||||
: m_sampling_rate(get_sampling_rate())
|
||||
, m_sample_size(get_sample_size())
|
||||
{
|
||||
ALCdevice* m_device = alcOpenDevice(nullptr);
|
||||
checkForAlcError("OpenALBackend->alcOpenDevice");
|
||||
checkForAlcError("alcOpenDevice");
|
||||
|
||||
ALCcontext* m_context = alcCreateContext(m_device, nullptr);
|
||||
checkForAlcError("OpenALBackend->alcCreateContext");
|
||||
checkForAlcError("alcCreateContext");
|
||||
|
||||
alcMakeContextCurrent(m_context);
|
||||
checkForAlcError("OpenALBackend->alcMakeContextCurrent");
|
||||
checkForAlcError("alcMakeContextCurrent");
|
||||
|
||||
if (get_channels() == 2)
|
||||
{
|
||||
@@ -128,7 +127,7 @@ bool OpenALBackend::AddData(const void* src, u32 num_samples)
|
||||
// Fail if there are no free buffers remaining
|
||||
if (m_num_unqueued == 0)
|
||||
{
|
||||
LOG_WARNING(GENERAL, "OpenALBackend : no unqueued buffers remaining");
|
||||
OpenAL.warning("No unqueued buffers remaining");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,14 +3,15 @@
|
||||
#endif
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/system_config.h"
|
||||
|
||||
#include "ALSABackend.h"
|
||||
|
||||
LOG_CHANNEL(ALSA);
|
||||
|
||||
static void error(int err, const char* reason)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "ALSA: %s failed: %s\n", reason, snd_strerror(err));
|
||||
ALSA.error("ALSA: %s failed: %s\n", reason, snd_strerror(err));
|
||||
}
|
||||
|
||||
static bool check(int err, const char* reason)
|
||||
@@ -105,7 +106,7 @@ void ALSABackend::Open(u32 num_buffers)
|
||||
if (!check(snd_pcm_prepare(tls_handle), "snd_pcm_prepare"))
|
||||
return;
|
||||
|
||||
LOG_NOTICE(GENERAL, "ALSA: bufsize_frames=%u, period_frames=%u", bufsize_frames, period_frames);
|
||||
ALSA.notice("bufsize_frames=%u, period_frames=%u", bufsize_frames, period_frames);
|
||||
}
|
||||
|
||||
void ALSABackend::Close()
|
||||
@@ -137,7 +138,7 @@ bool ALSABackend::AddData(const void* src, u32 num_samples)
|
||||
|
||||
if (res == -EAGAIN)
|
||||
{
|
||||
LOG_WARNING(GENERAL, "ALSA: EAGAIN");
|
||||
ALSA.warning("EAGAIN");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -147,16 +148,16 @@ bool ALSABackend::AddData(const void* src, u32 num_samples)
|
||||
|
||||
if (res < 0)
|
||||
{
|
||||
LOG_WARNING(GENERAL, "ALSA: failed to recover (%d)", res);
|
||||
ALSA.warning("Failed to recover (%d)", res);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (res != num_frames)
|
||||
if (res + 0u != num_frames)
|
||||
{
|
||||
LOG_WARNING(GENERAL, "ALSA: error (%d)", res);
|
||||
ALSA.warning("Error (%d)", res);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "stdafx.h"
|
||||
#include "AudioBackend.h"
|
||||
#include "Emu/system_config.h"
|
||||
|
||||
/*
|
||||
* Helper methods
|
||||
*/
|
||||
u32 AudioBackend::get_sampling_rate()
|
||||
{
|
||||
const u32 sampling_period_multiplier_u32 = g_cfg.audio.sampling_period_multiplier;
|
||||
|
||||
if (sampling_period_multiplier_u32 == 100)
|
||||
return DEFAULT_AUDIO_SAMPLING_RATE;
|
||||
|
||||
const f32 sampling_period_multiplier = sampling_period_multiplier_u32 / 100.0f;
|
||||
const f32 sampling_rate_multiplier = 1.0f / sampling_period_multiplier;
|
||||
return static_cast<u32>(f32{DEFAULT_AUDIO_SAMPLING_RATE} * sampling_rate_multiplier);
|
||||
}
|
||||
|
||||
u32 AudioBackend::get_sample_size()
|
||||
{
|
||||
return g_cfg.audio.convert_to_u16 ? sizeof(u16) : sizeof(float);
|
||||
}
|
||||
|
||||
u32 AudioBackend::get_channels()
|
||||
{
|
||||
return g_cfg.audio.downmix_to_2ch ? 2 : 8;
|
||||
}
|
||||
|
||||
bool AudioBackend::has_capability(u32 cap) const
|
||||
{
|
||||
return (cap & GetCapabilities()) == cap;
|
||||
}
|
||||
|
||||
void AudioBackend::dump_capabilities(std::string& out) const
|
||||
{
|
||||
u32 count = 0;
|
||||
u32 capabilities = GetCapabilities();
|
||||
|
||||
if (capabilities & PLAY_PAUSE_FLUSH)
|
||||
{
|
||||
fmt::append(out, "PLAY_PAUSE_FLUSH");
|
||||
count++;
|
||||
}
|
||||
|
||||
if (capabilities & IS_PLAYING)
|
||||
{
|
||||
fmt::append(out, "%sIS_PLAYING", count > 0 ? " | " : "");
|
||||
count++;
|
||||
}
|
||||
|
||||
if (capabilities & GET_NUM_ENQUEUED_SAMPLES)
|
||||
{
|
||||
fmt::append(out, "%sGET_NUM_ENQUEUED_SAMPLES", count > 0 ? " | " : "");
|
||||
count++;
|
||||
}
|
||||
|
||||
if (capabilities & SET_FREQUENCY_RATIO)
|
||||
{
|
||||
fmt::append(out, "%sSET_FREQUENCY_RATIO", count > 0 ? " | " : "");
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
fmt::append(out, "NONE");
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/types.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
enum : u32
|
||||
{
|
||||
@@ -35,6 +34,12 @@ public:
|
||||
virtual bool AddData(const void* src, u32 num_samples) = 0;
|
||||
|
||||
|
||||
/*
|
||||
* This virtual method should be reimplemented if backend can fail to be initialized under non-error conditions
|
||||
* eg. when there is no audio devices attached
|
||||
*/
|
||||
virtual bool Initialized() const { return true; }
|
||||
|
||||
/*
|
||||
* Virtual methods - should be implemented depending on backend capabilities
|
||||
*/
|
||||
@@ -89,65 +94,13 @@ public:
|
||||
/*
|
||||
* Helper methods
|
||||
*/
|
||||
static u32 get_sampling_rate()
|
||||
{
|
||||
const u32 sampling_period_multiplier_u32 = g_cfg.audio.sampling_period_multiplier;
|
||||
static u32 get_sampling_rate();
|
||||
|
||||
if (sampling_period_multiplier_u32 == 100)
|
||||
return DEFAULT_AUDIO_SAMPLING_RATE;
|
||||
static u32 get_sample_size();
|
||||
|
||||
const f32 sampling_period_multiplier = sampling_period_multiplier_u32 / 100.0f;
|
||||
const f32 sampling_rate_multiplier = 1.0f / sampling_period_multiplier;
|
||||
return static_cast<u32>(DEFAULT_AUDIO_SAMPLING_RATE * sampling_rate_multiplier);
|
||||
}
|
||||
static u32 get_channels();
|
||||
|
||||
static u32 get_sample_size()
|
||||
{
|
||||
return g_cfg.audio.convert_to_u16 ? sizeof(u16) : sizeof(float);
|
||||
}
|
||||
bool has_capability(u32 cap) const;
|
||||
|
||||
static u32 get_channels()
|
||||
{
|
||||
return g_cfg.audio.downmix_to_2ch ? 2 : 8;
|
||||
}
|
||||
|
||||
bool has_capability(u32 cap) const
|
||||
{
|
||||
return (cap & GetCapabilities()) == cap;
|
||||
}
|
||||
|
||||
void dump_capabilities(std::string& out) const
|
||||
{
|
||||
u32 count = 0;
|
||||
u32 capabilities = GetCapabilities();
|
||||
|
||||
if (capabilities & PLAY_PAUSE_FLUSH)
|
||||
{
|
||||
fmt::append(out, "PLAY_PAUSE_FLUSH");
|
||||
count++;
|
||||
}
|
||||
|
||||
if (capabilities & IS_PLAYING)
|
||||
{
|
||||
fmt::append(out, "%sIS_PLAYING", count > 0 ? " | " : "");
|
||||
count++;
|
||||
}
|
||||
|
||||
if (capabilities & GET_NUM_ENQUEUED_SAMPLES)
|
||||
{
|
||||
fmt::append(out, "%sGET_NUM_ENQUEUED_SAMPLES", count > 0 ? " | " : "");
|
||||
count++;
|
||||
}
|
||||
|
||||
if (capabilities & SET_FREQUENCY_RATIO)
|
||||
{
|
||||
fmt::append(out, "%sSET_FREQUENCY_RATIO", count > 0 ? " | " : "");
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
fmt::append(out, "NONE");
|
||||
}
|
||||
}
|
||||
void dump_capabilities(std::string& out) const;
|
||||
};
|
||||
|
||||
@@ -15,8 +15,8 @@ struct WAVHeader
|
||||
|
||||
RIFFHeader(u32 size)
|
||||
: ID("RIFF"_u32)
|
||||
, WAVE("WAVE"_u32)
|
||||
, Size(size)
|
||||
, WAVE("WAVE"_u32)
|
||||
{
|
||||
}
|
||||
} RIFF;
|
||||
@@ -53,10 +53,10 @@ struct WAVHeader
|
||||
WAVHeader() = default;
|
||||
|
||||
WAVHeader(u16 ch)
|
||||
: ID("data"_u32)
|
||||
, Size(0)
|
||||
: RIFF(sizeof(RIFFHeader) + sizeof(FMTHeader))
|
||||
, FMT(ch)
|
||||
, RIFF(sizeof(RIFFHeader) + sizeof(FMTHeader))
|
||||
, ID("data"_u32)
|
||||
, Size(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
#error "FAudio support disabled but still being built."
|
||||
#endif
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "FAudioBackend.h"
|
||||
#include "Emu/system_config.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
LOG_CHANNEL(FAudio_, "FAudio");
|
||||
|
||||
FAudioBackend::FAudioBackend()
|
||||
{
|
||||
@@ -11,13 +16,15 @@ FAudioBackend::FAudioBackend()
|
||||
res = FAudioCreate(&m_instance, 0, FAUDIO_DEFAULT_PROCESSOR);
|
||||
if (res)
|
||||
{
|
||||
fmt::throw_exception("FAudioCreate() failed(0x%08x)", res);
|
||||
FAudio_.fatal("FAudioCreate() failed(0x%08x)", res);
|
||||
return;
|
||||
}
|
||||
|
||||
res = FAudio_CreateMasteringVoice(m_instance, &m_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000, 0, 0, nullptr);
|
||||
if (res)
|
||||
{
|
||||
fmt::throw_exception("FAudio_CreateMasteringVoice() failed(0x%08x)", res);
|
||||
FAudio_.fatal("FAudio_CreateMasteringVoice() failed(0x%08x)", res);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +55,7 @@ void FAudioBackend::Play()
|
||||
u32 res = FAudioSourceVoice_Start(m_source_voice, 0, FAUDIO_COMMIT_NOW);
|
||||
if (res)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "FAudioSourceVoice_Start() failed(0x%08x)", res);
|
||||
FAudio_.error("FAudioSourceVoice_Start() failed(0x%08x)", res);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
@@ -60,7 +67,7 @@ void FAudioBackend::Pause()
|
||||
u32 res = FAudioSourceVoice_Stop(m_source_voice, 0, FAUDIO_COMMIT_NOW);
|
||||
if (res)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "FAudioSourceVoice_Stop() failed(0x%08x)", res);
|
||||
FAudio_.error("FAudioSourceVoice_Stop() failed(0x%08x)", res);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
@@ -72,7 +79,7 @@ void FAudioBackend::Flush()
|
||||
u32 res = FAudioSourceVoice_FlushSourceBuffers(m_source_voice);
|
||||
if (res)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "FAudioSourceVoice_FlushSourceBuffers() failed(0x%08x)", res);
|
||||
FAudio_.error("FAudioSourceVoice_FlushSourceBuffers() failed(0x%08x)", res);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
@@ -111,7 +118,7 @@ void FAudioBackend::Open(u32 /* num_buffers */)
|
||||
u32 res = FAudio_CreateSourceVoice(m_instance, &m_source_voice, &waveformatex, 0, FAUDIO_DEFAULT_FREQ_RATIO, nullptr, nullptr, nullptr);
|
||||
if (res)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "FAudio_CreateSourceVoice() failed(0x%08x)", res);
|
||||
FAudio_.error("FAudio_CreateSourceVoice() failed(0x%08x)", res);
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
@@ -128,7 +135,7 @@ bool FAudioBackend::AddData(const void* src, u32 num_samples)
|
||||
|
||||
if (state.BuffersQueued >= MAX_AUDIO_BUFFERS)
|
||||
{
|
||||
LOG_WARNING(GENERAL, "XAudio2Backend : too many buffers enqueued (%d)", state.BuffersQueued);
|
||||
FAudio_.warning("Too many buffers enqueued (%d)", state.BuffersQueued);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -146,7 +153,7 @@ bool FAudioBackend::AddData(const void* src, u32 num_samples)
|
||||
u32 res = FAudioSourceVoice_SubmitSourceBuffer(m_source_voice, &buffer, nullptr);
|
||||
if (res)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "FAudioSourceVoice_SubmitSourceBuffer() failed(0x%08x)", res);
|
||||
FAudio_.error("FAudioSourceVoice_SubmitSourceBuffer() failed(0x%08x)", res);
|
||||
Emu.Pause();
|
||||
return false;
|
||||
}
|
||||
@@ -170,7 +177,7 @@ f32 FAudioBackend::SetFrequencyRatio(f32 new_ratio)
|
||||
u32 res = FAudioSourceVoice_SetFrequencyRatio(m_source_voice, new_ratio, FAUDIO_COMMIT_NOW);
|
||||
if (res)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "FAudioSourceVoice_SetFrequencyRatio() failed(0x%08x)", res);
|
||||
FAudio_.error("FAudioSourceVoice_SetFrequencyRatio() failed(0x%08x)", res);
|
||||
Emu.Pause();
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
#ifndef _WIN32
|
||||
#error "XAudio27 can only be built on Windows."
|
||||
#endif
|
||||
|
||||
#include "Utilities/Log.h"
|
||||
#include "Utilities/StrFmt.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
#include "XAudio2Backend.h"
|
||||
#include "3rdparty/XAudio2_7/XAudio2.h"
|
||||
|
||||
class XAudio27Library : public XAudio2Backend::XAudio2Library
|
||||
{
|
||||
const HMODULE tls_xaudio2_lib;
|
||||
IXAudio2* tls_xaudio2_instance{};
|
||||
IXAudio2MasteringVoice* tls_master_voice{};
|
||||
IXAudio2SourceVoice* tls_source_voice{};
|
||||
|
||||
public:
|
||||
XAudio27Library(void* lib2_7)
|
||||
: tls_xaudio2_lib(static_cast<HMODULE>(lib2_7))
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "XAudio2Backend : CoInitializeEx() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
|
||||
hr = XAudio2Create(&tls_xaudio2_instance, 0, XAUDIO2_DEFAULT_PROCESSOR);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "XAudio2Backend : XAudio2Create() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
|
||||
hr = tls_xaudio2_instance->CreateMasteringVoice(&tls_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "XAudio2Backend : CreateMasteringVoice() failed(0x%08x)", (u32)hr);
|
||||
tls_xaudio2_instance->Release();
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
~XAudio27Library()
|
||||
{
|
||||
if (tls_source_voice != nullptr)
|
||||
{
|
||||
tls_source_voice->Stop();
|
||||
tls_source_voice->DestroyVoice();
|
||||
}
|
||||
|
||||
if (tls_master_voice != nullptr)
|
||||
{
|
||||
tls_master_voice->DestroyVoice();
|
||||
}
|
||||
|
||||
if (tls_xaudio2_instance != nullptr)
|
||||
{
|
||||
tls_xaudio2_instance->StopEngine();
|
||||
tls_xaudio2_instance->Release();
|
||||
}
|
||||
|
||||
CoUninitialize();
|
||||
|
||||
FreeLibrary(tls_xaudio2_lib);
|
||||
}
|
||||
|
||||
virtual void play() override
|
||||
{
|
||||
HRESULT hr = tls_source_voice->Start();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "XAudio2Backend : Start() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void flush() override
|
||||
{
|
||||
HRESULT hr = tls_source_voice->FlushSourceBuffers();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "XAudio2Backend : FlushSourceBuffers() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void stop() override
|
||||
{
|
||||
HRESULT hr = tls_source_voice->Stop();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "XAudio2Backend : Stop() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool is_playing() override
|
||||
{
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
tls_source_voice->GetState(&state);
|
||||
|
||||
return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr;
|
||||
}
|
||||
|
||||
virtual void open() override
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
const u32 sample_size = AudioBackend::get_sample_size();
|
||||
const u32 channels = AudioBackend::get_channels();
|
||||
const u32 sampling_rate = AudioBackend::get_sampling_rate();
|
||||
|
||||
WAVEFORMATEX waveformatex;
|
||||
waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
|
||||
waveformatex.nChannels = channels;
|
||||
waveformatex.nSamplesPerSec = sampling_rate;
|
||||
waveformatex.nAvgBytesPerSec = static_cast<DWORD>(sampling_rate * channels * sample_size);
|
||||
waveformatex.nBlockAlign = channels * sample_size;
|
||||
waveformatex.wBitsPerSample = sample_size * 8;
|
||||
waveformatex.cbSize = 0;
|
||||
|
||||
hr = tls_xaudio2_instance->CreateSourceVoice(&tls_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "XAudio2Backend : CreateSourceVoice() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
|
||||
tls_source_voice->SetVolume(channels == 2 ? 1.0f : 4.0f);
|
||||
}
|
||||
|
||||
virtual bool add(const void* src, u32 num_samples) override
|
||||
{
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
tls_source_voice->GetState(&state);
|
||||
|
||||
// XAudio 2.7 bug workaround, when it says "SimpList: non-growable list ran out of room for new elements" and hits int 3
|
||||
if (state.BuffersQueued >= MAX_AUDIO_BUFFERS)
|
||||
{
|
||||
LOG_WARNING(GENERAL, "XAudio2Backend : too many buffers enqueued (%d, pos=%u)", state.BuffersQueued, state.SamplesPlayed);
|
||||
return false;
|
||||
}
|
||||
|
||||
XAUDIO2_BUFFER buffer;
|
||||
|
||||
buffer.AudioBytes = num_samples * AudioBackend::get_sample_size();
|
||||
buffer.Flags = 0;
|
||||
buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION;
|
||||
buffer.LoopCount = 0;
|
||||
buffer.LoopLength = 0;
|
||||
buffer.pAudioData = (const BYTE*)src;
|
||||
buffer.pContext = 0;
|
||||
buffer.PlayBegin = 0;
|
||||
buffer.PlayLength = AUDIO_BUFFER_SAMPLES;
|
||||
|
||||
HRESULT hr = tls_source_voice->SubmitSourceBuffer(&buffer);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "XAudio2Backend : AddData() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual u64 enqueued_samples() override
|
||||
{
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
tls_source_voice->GetState(&state);
|
||||
|
||||
// all buffers contain AUDIO_BUFFER_SAMPLES, so we can easily calculate how many samples there are remaining
|
||||
return (AUDIO_BUFFER_SAMPLES - state.SamplesPlayed % AUDIO_BUFFER_SAMPLES) + (state.BuffersQueued * AUDIO_BUFFER_SAMPLES);
|
||||
}
|
||||
|
||||
virtual f32 set_freq_ratio(f32 new_ratio) override
|
||||
{
|
||||
new_ratio = std::clamp(new_ratio, XAUDIO2_MIN_FREQ_RATIO, XAUDIO2_DEFAULT_FREQ_RATIO);
|
||||
|
||||
HRESULT hr = tls_source_voice->SetFrequencyRatio(new_ratio);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "XAudio2Backend : SetFrequencyRatio() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
return new_ratio;
|
||||
}
|
||||
};
|
||||
|
||||
XAudio2Backend::XAudio2Library* XAudio2Backend::xa27_init(void* lib2_7)
|
||||
{
|
||||
return new XAudio27Library(lib2_7);
|
||||
}
|
||||
@@ -1,215 +0,0 @@
|
||||
#ifndef _WIN32
|
||||
#error "XAudio28 can only be built on Windows."
|
||||
#endif
|
||||
|
||||
#include "Utilities/Log.h"
|
||||
#include "Utilities/StrFmt.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
#include "XAudio2Backend.h"
|
||||
#include "3rdparty/minidx12/Include/xaudio2.h"
|
||||
|
||||
class XAudio28Library : public XAudio2Backend::XAudio2Library
|
||||
{
|
||||
const HMODULE tls_xaudio2_lib;
|
||||
IXAudio2* tls_xaudio2_instance{};
|
||||
IXAudio2MasteringVoice* tls_master_voice{};
|
||||
IXAudio2SourceVoice* tls_source_voice{};
|
||||
|
||||
public:
|
||||
XAudio28Library(void* lib2_8)
|
||||
: tls_xaudio2_lib(static_cast<HMODULE>(lib2_8))
|
||||
{
|
||||
const auto create = (XAudio2Create)GetProcAddress(tls_xaudio2_lib, "XAudio2Create");
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "XAudio2Backend : CoInitializeEx() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
|
||||
hr = create(&tls_xaudio2_instance, 0, XAUDIO2_DEFAULT_PROCESSOR);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "XAudio2Backend : XAudio2Create() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
|
||||
hr = tls_xaudio2_instance->CreateMasteringVoice(&tls_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "XAudio2Backend : CreateMasteringVoice() failed(0x%08x)", (u32)hr);
|
||||
tls_xaudio2_instance->Release();
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
~XAudio28Library()
|
||||
{
|
||||
if (tls_source_voice != nullptr)
|
||||
{
|
||||
tls_source_voice->Stop();
|
||||
tls_source_voice->DestroyVoice();
|
||||
}
|
||||
|
||||
if (tls_master_voice != nullptr)
|
||||
{
|
||||
tls_master_voice->DestroyVoice();
|
||||
}
|
||||
|
||||
if (tls_xaudio2_instance != nullptr)
|
||||
{
|
||||
tls_xaudio2_instance->StopEngine();
|
||||
tls_xaudio2_instance->Release();
|
||||
}
|
||||
|
||||
CoUninitialize();
|
||||
|
||||
FreeLibrary(tls_xaudio2_lib);
|
||||
}
|
||||
|
||||
virtual void play() override
|
||||
{
|
||||
AUDIT(tls_source_voice != nullptr);
|
||||
|
||||
HRESULT hr = tls_source_voice->Start();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "XAudio2Backend : Start() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void flush() override
|
||||
{
|
||||
AUDIT(tls_source_voice != nullptr);
|
||||
|
||||
HRESULT hr = tls_source_voice->FlushSourceBuffers();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "XAudio2Backend : FlushSourceBuffers() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void stop() override
|
||||
{
|
||||
AUDIT(tls_source_voice != nullptr);
|
||||
|
||||
HRESULT hr = tls_source_voice->Stop();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "XAudio2Backend : Stop() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool is_playing() override
|
||||
{
|
||||
AUDIT(tls_source_voice != nullptr);
|
||||
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
tls_source_voice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
|
||||
|
||||
return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr;
|
||||
}
|
||||
|
||||
virtual void open() override
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
const u32 sample_size = AudioBackend::get_sample_size();
|
||||
const u32 channels = AudioBackend::get_channels();
|
||||
const u32 sampling_rate = AudioBackend::get_sampling_rate();
|
||||
|
||||
WAVEFORMATEX waveformatex;
|
||||
waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
|
||||
waveformatex.nChannels = channels;
|
||||
waveformatex.nSamplesPerSec = sampling_rate;
|
||||
waveformatex.nAvgBytesPerSec = static_cast<DWORD>(sampling_rate * channels * sample_size);
|
||||
waveformatex.nBlockAlign = channels * sample_size;
|
||||
waveformatex.wBitsPerSample = sample_size * 8;
|
||||
waveformatex.cbSize = 0;
|
||||
|
||||
hr = tls_xaudio2_instance->CreateSourceVoice(&tls_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "XAudio2Backend : CreateSourceVoice() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
|
||||
AUDIT(tls_source_voice != nullptr);
|
||||
tls_source_voice->SetVolume(channels == 2 ? 1.0f : 4.0f);
|
||||
}
|
||||
|
||||
virtual bool add(const void* src, u32 num_samples) override
|
||||
{
|
||||
AUDIT(tls_source_voice != nullptr);
|
||||
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
tls_source_voice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
|
||||
|
||||
if (state.BuffersQueued >= MAX_AUDIO_BUFFERS)
|
||||
{
|
||||
LOG_WARNING(GENERAL, "XAudio2Backend : too many buffers enqueued (%d)", state.BuffersQueued);
|
||||
return false;
|
||||
}
|
||||
|
||||
XAUDIO2_BUFFER buffer;
|
||||
|
||||
buffer.AudioBytes = num_samples * AudioBackend::get_sample_size();
|
||||
buffer.Flags = 0;
|
||||
buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION;
|
||||
buffer.LoopCount = 0;
|
||||
buffer.LoopLength = 0;
|
||||
buffer.pAudioData = (const BYTE*)src;
|
||||
buffer.pContext = 0;
|
||||
buffer.PlayBegin = 0;
|
||||
buffer.PlayLength = AUDIO_BUFFER_SAMPLES;
|
||||
|
||||
HRESULT hr = tls_source_voice->SubmitSourceBuffer(&buffer);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "XAudio2Backend : AddData() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual u64 enqueued_samples() override
|
||||
{
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
tls_source_voice->GetState(&state);
|
||||
|
||||
// all buffers contain AUDIO_BUFFER_SAMPLES, so we can easily calculate how many samples there are remaining
|
||||
return (AUDIO_BUFFER_SAMPLES - state.SamplesPlayed % AUDIO_BUFFER_SAMPLES) + (state.BuffersQueued * AUDIO_BUFFER_SAMPLES);
|
||||
}
|
||||
|
||||
virtual f32 set_freq_ratio(f32 new_ratio) override
|
||||
{
|
||||
new_ratio = std::clamp(new_ratio, XAUDIO2_MIN_FREQ_RATIO, XAUDIO2_DEFAULT_FREQ_RATIO);
|
||||
|
||||
HRESULT hr = tls_source_voice->SetFrequencyRatio(new_ratio);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "XAudio2Backend : SetFrequencyRatio() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
return new_ratio;
|
||||
}
|
||||
};
|
||||
|
||||
XAudio2Backend::XAudio2Library* XAudio2Backend::xa28_init(void* lib2_8)
|
||||
{
|
||||
return new XAudio28Library(lib2_8);
|
||||
}
|
||||
@@ -4,89 +4,196 @@
|
||||
|
||||
#include "Utilities/Log.h"
|
||||
#include "Utilities/StrFmt.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/system_config.h"
|
||||
|
||||
#include "XAudio2Backend.h"
|
||||
#include <Windows.h>
|
||||
|
||||
#pragma comment(lib, "xaudio2_9redist.lib")
|
||||
|
||||
LOG_CHANNEL(XAudio);
|
||||
|
||||
XAudio2Backend::XAudio2Backend()
|
||||
{
|
||||
Microsoft::WRL::ComPtr<IXAudio2> instance;
|
||||
|
||||
HRESULT hr = XAudio2Create(instance.GetAddressOf(), 0, XAUDIO2_DEFAULT_PROCESSOR);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("XAudio2Create() failed(0x%08x)", (u32)hr);
|
||||
return;
|
||||
}
|
||||
|
||||
hr = instance->CreateMasteringVoice(&m_master_voice, g_cfg.audio.downmix_to_2ch ? 2 : 8, 48000);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("CreateMasteringVoice() failed(0x%08x)", (u32)hr);
|
||||
return;
|
||||
}
|
||||
|
||||
// All succeeded, "commit"
|
||||
m_xaudio2_instance = std::move(instance);
|
||||
}
|
||||
|
||||
XAudio2Backend::~XAudio2Backend()
|
||||
{
|
||||
if (m_source_voice != nullptr)
|
||||
{
|
||||
m_source_voice->Stop();
|
||||
m_source_voice->DestroyVoice();
|
||||
}
|
||||
|
||||
if (m_master_voice != nullptr)
|
||||
{
|
||||
m_master_voice->DestroyVoice();
|
||||
}
|
||||
|
||||
if (m_xaudio2_instance != nullptr)
|
||||
{
|
||||
m_xaudio2_instance->StopEngine();
|
||||
}
|
||||
}
|
||||
|
||||
void XAudio2Backend::Play()
|
||||
{
|
||||
lib->play();
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
HRESULT hr = m_source_voice->Start();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("Start() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
void XAudio2Backend::Close()
|
||||
{
|
||||
lib->stop();
|
||||
lib->flush();
|
||||
Pause();
|
||||
Flush();
|
||||
}
|
||||
|
||||
void XAudio2Backend::Pause()
|
||||
{
|
||||
lib->stop();
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
HRESULT hr = m_source_voice->Stop();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("Stop() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
void XAudio2Backend::Open(u32 /* num_buffers */)
|
||||
{
|
||||
if (lib.get() == nullptr)
|
||||
HRESULT hr;
|
||||
|
||||
const u32 sample_size = AudioBackend::get_sample_size();
|
||||
const u32 channels = AudioBackend::get_channels();
|
||||
const u32 sampling_rate = AudioBackend::get_sampling_rate();
|
||||
|
||||
WAVEFORMATEX waveformatex;
|
||||
waveformatex.wFormatTag = g_cfg.audio.convert_to_u16 ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT;
|
||||
waveformatex.nChannels = channels;
|
||||
waveformatex.nSamplesPerSec = sampling_rate;
|
||||
waveformatex.nAvgBytesPerSec = static_cast<DWORD>(sampling_rate * channels * sample_size);
|
||||
waveformatex.nBlockAlign = channels * sample_size;
|
||||
waveformatex.wBitsPerSample = sample_size * 8;
|
||||
waveformatex.cbSize = 0;
|
||||
|
||||
hr = m_xaudio2_instance->CreateSourceVoice(&m_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
void* hmodule;
|
||||
|
||||
if (hmodule = LoadLibraryExW(L"XAudio2_9.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))
|
||||
{
|
||||
// XAudio 2.9 uses the same code as XAudio 2.8
|
||||
lib.reset(xa28_init(hmodule));
|
||||
|
||||
LOG_SUCCESS(GENERAL, "XAudio 2.9 initialized");
|
||||
}
|
||||
else if (hmodule = LoadLibraryExW(L"XAudio2_8.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))
|
||||
{
|
||||
lib.reset(xa28_init(hmodule));
|
||||
|
||||
LOG_SUCCESS(GENERAL, "XAudio 2.8 initialized");
|
||||
}
|
||||
else if (hmodule = LoadLibraryExW(L"XAudio2_7.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))
|
||||
{
|
||||
lib.reset(xa27_init(hmodule));
|
||||
|
||||
LOG_SUCCESS(GENERAL, "XAudio 2.7 initialized");
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::throw_exception("No supported XAudio2 library found");
|
||||
}
|
||||
XAudio.error("CreateSourceVoice() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
|
||||
lib->open();
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
m_source_voice->SetVolume(channels == 2 ? 1.0f : 4.0f);
|
||||
}
|
||||
|
||||
bool XAudio2Backend::IsPlaying()
|
||||
{
|
||||
return lib->is_playing();
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
m_source_voice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
|
||||
|
||||
return state.BuffersQueued > 0 || state.pCurrentBufferContext != nullptr;
|
||||
}
|
||||
|
||||
bool XAudio2Backend::AddData(const void* src, u32 num_samples)
|
||||
{
|
||||
return lib->add(src, num_samples);
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
m_source_voice->GetState(&state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
|
||||
|
||||
if (state.BuffersQueued >= MAX_AUDIO_BUFFERS)
|
||||
{
|
||||
XAudio.warning("Too many buffers enqueued (%d)", state.BuffersQueued);
|
||||
return false;
|
||||
}
|
||||
|
||||
XAUDIO2_BUFFER buffer;
|
||||
|
||||
buffer.AudioBytes = num_samples * AudioBackend::get_sample_size();
|
||||
buffer.Flags = 0;
|
||||
buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION;
|
||||
buffer.LoopCount = 0;
|
||||
buffer.LoopLength = 0;
|
||||
buffer.pAudioData = static_cast<const BYTE*>(src);
|
||||
buffer.pContext = nullptr;
|
||||
buffer.PlayBegin = 0;
|
||||
buffer.PlayLength = AUDIO_BUFFER_SAMPLES;
|
||||
|
||||
HRESULT hr = m_source_voice->SubmitSourceBuffer(&buffer);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("AddData() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void XAudio2Backend::Flush()
|
||||
{
|
||||
lib->flush();
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
HRESULT hr = m_source_voice->FlushSourceBuffers();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("FlushSourceBuffers() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
u64 XAudio2Backend::GetNumEnqueuedSamples()
|
||||
{
|
||||
return lib->enqueued_samples();
|
||||
AUDIT(m_source_voice != nullptr);
|
||||
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
m_source_voice->GetState(&state);
|
||||
|
||||
// all buffers contain AUDIO_BUFFER_SAMPLES, so we can easily calculate how many samples there are remaining
|
||||
return static_cast<u64>(AUDIO_BUFFER_SAMPLES - state.SamplesPlayed % AUDIO_BUFFER_SAMPLES) + (state.BuffersQueued * AUDIO_BUFFER_SAMPLES);
|
||||
}
|
||||
|
||||
f32 XAudio2Backend::SetFrequencyRatio(f32 new_ratio)
|
||||
{
|
||||
return lib->set_freq_ratio(new_ratio);
|
||||
new_ratio = std::clamp(new_ratio, XAUDIO2_MIN_FREQ_RATIO, XAUDIO2_DEFAULT_FREQ_RATIO);
|
||||
|
||||
HRESULT hr = m_source_voice->SetFrequencyRatio(new_ratio);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
XAudio.error("SetFrequencyRatio() failed(0x%08x)", (u32)hr);
|
||||
Emu.Pause();
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
return new_ratio;
|
||||
}
|
||||
|
||||
@@ -6,28 +6,16 @@
|
||||
|
||||
#include "Emu/Audio/AudioBackend.h"
|
||||
|
||||
#include <xaudio2redist.h>
|
||||
#include <wrl/client.h>
|
||||
|
||||
class XAudio2Backend : public AudioBackend
|
||||
|
||||
class XAudio2Backend final : public AudioBackend
|
||||
{
|
||||
public:
|
||||
class XAudio2Library
|
||||
{
|
||||
public:
|
||||
virtual void play() = 0;
|
||||
virtual void flush() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual void open() = 0;
|
||||
virtual bool is_playing() = 0;
|
||||
virtual bool add(const void*, u32) = 0;
|
||||
virtual u64 enqueued_samples() = 0;
|
||||
virtual f32 set_freq_ratio(f32) = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
static XAudio2Library* xa27_init(void*);
|
||||
static XAudio2Library* xa28_init(void*);
|
||||
|
||||
std::unique_ptr<XAudio2Library> lib = nullptr;
|
||||
Microsoft::WRL::ComPtr<IXAudio2> m_xaudio2_instance;
|
||||
IXAudio2MasteringVoice* m_master_voice{};
|
||||
IXAudio2SourceVoice* m_source_voice{};
|
||||
|
||||
public:
|
||||
XAudio2Backend();
|
||||
@@ -38,6 +26,8 @@ public:
|
||||
static const u32 capabilities = PLAY_PAUSE_FLUSH | IS_PLAYING | GET_NUM_ENQUEUED_SAMPLES | SET_FREQUENCY_RATIO;
|
||||
virtual u32 GetCapabilities() const override { return capabilities; };
|
||||
|
||||
virtual bool Initialized() const override { return m_xaudio2_instance != nullptr; }
|
||||
|
||||
virtual void Open(u32 /* num_buffers */) override;
|
||||
virtual void Close() override;
|
||||
|
||||
|
||||
+39
-12
@@ -1,8 +1,11 @@
|
||||
add_library(rpcs3_emu
|
||||
IdManager.cpp
|
||||
System.cpp
|
||||
system_config.cpp
|
||||
system_config_types.cpp
|
||||
VFS.cpp
|
||||
GDB.cpp
|
||||
title.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(rpcs3_emu
|
||||
@@ -26,6 +29,8 @@ target_include_directories(rpcs3_emu
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
../util/atomic.cpp
|
||||
../util/atomic2.cpp
|
||||
../util/shared_cptr.cpp
|
||||
../util/fixed_typemap.cpp
|
||||
../../Utilities/bin_patch.cpp
|
||||
../../Utilities/cond.cpp
|
||||
../../Utilities/Config.cpp
|
||||
@@ -88,6 +93,7 @@ target_sources(rpcs3_emu PRIVATE
|
||||
# Audio
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
Audio/AudioDumper.cpp
|
||||
Audio/AudioBackend.cpp
|
||||
Audio/AL/OpenALBackend.cpp
|
||||
)
|
||||
|
||||
@@ -110,13 +116,12 @@ if(USE_FAUDIO AND SDL2_FOUND AND NOT SDL2_VERSION VERSION_LESS 2.0.9)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_include_directories(rpcs3_emu PUBLIC "${RPCS3_SRC_DIR}/../3rdparty/XAudio2Redist/include")
|
||||
target_link_libraries(rpcs3_emu PRIVATE "${RPCS3_SRC_DIR}/../3rdparty/XAudio2Redist/libs/xaudio2_9redist.lib")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DELAYLOAD:xaudio2_9redist.dll")
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
Audio/XAudio2/XAudio27Backend.cpp
|
||||
Audio/XAudio2/XAudio28Backend.cpp
|
||||
Audio/XAudio2/XAudio2Backend.cpp
|
||||
)
|
||||
# Slimmed down version of minidx9 for XAudio2_7 only
|
||||
include_directories(BEFORE "${RPCS3_SRC_DIR}/../3rdparty/XAudio2_7")
|
||||
endif()
|
||||
|
||||
target_link_libraries(rpcs3_emu
|
||||
@@ -142,7 +147,11 @@ target_sources(rpcs3_emu PRIVATE
|
||||
Cell/SPURecompiler.cpp
|
||||
Cell/SPUThread.cpp
|
||||
Cell/lv2/lv2.cpp
|
||||
Cell/lv2/sys_bdemu.cpp
|
||||
Cell/lv2/sys_btsetting.cpp
|
||||
Cell/lv2/sys_cond.cpp
|
||||
Cell/lv2/sys_console.cpp
|
||||
Cell/lv2/sys_crypto_engine.cpp
|
||||
Cell/lv2/sys_config.cpp
|
||||
Cell/lv2/sys_dbg.cpp
|
||||
Cell/lv2/sys_event.cpp
|
||||
@@ -150,7 +159,9 @@ target_sources(rpcs3_emu PRIVATE
|
||||
Cell/lv2/sys_fs.cpp
|
||||
Cell/lv2/sys_gamepad.cpp
|
||||
Cell/lv2/sys_gpio.cpp
|
||||
Cell/lv2/sys_hid.cpp
|
||||
Cell/lv2/sys_interrupt.cpp
|
||||
Cell/lv2/sys_io.cpp
|
||||
Cell/lv2/sys_lwcond.cpp
|
||||
Cell/lv2/sys_lwmutex.cpp
|
||||
Cell/lv2/sys_memory.cpp
|
||||
@@ -162,14 +173,18 @@ target_sources(rpcs3_emu PRIVATE
|
||||
Cell/lv2/sys_process.cpp
|
||||
Cell/lv2/sys_prx.cpp
|
||||
Cell/lv2/sys_rsx.cpp
|
||||
Cell/lv2/sys_rsxaudio.cpp
|
||||
Cell/lv2/sys_rwlock.cpp
|
||||
Cell/lv2/sys_semaphore.cpp
|
||||
Cell/lv2/sys_spu.cpp
|
||||
Cell/lv2/sys_sm.cpp
|
||||
Cell/lv2/sys_ss.cpp
|
||||
Cell/lv2/sys_storage.cpp
|
||||
Cell/lv2/sys_time.cpp
|
||||
Cell/lv2/sys_timer.cpp
|
||||
Cell/lv2/sys_trace.cpp
|
||||
Cell/lv2/sys_tty.cpp
|
||||
Cell/lv2/sys_uart.cpp
|
||||
Cell/lv2/sys_usbd.cpp
|
||||
Cell/lv2/sys_vm.cpp
|
||||
Cell/Modules/cellAdec.cpp
|
||||
@@ -177,6 +192,7 @@ target_sources(rpcs3_emu PRIVATE
|
||||
Cell/Modules/cellAtracMulti.cpp
|
||||
Cell/Modules/cellAudio.cpp
|
||||
Cell/Modules/cellAudioOut.cpp
|
||||
Cell/Modules/cellAuthDialog.cpp
|
||||
Cell/Modules/cellAvconfExt.cpp
|
||||
Cell/Modules/cellBgdl.cpp
|
||||
Cell/Modules/cellCamera.cpp
|
||||
@@ -284,7 +300,7 @@ target_sources(rpcs3_emu PRIVATE
|
||||
Cell/Modules/StaticHLE.cpp
|
||||
Cell/Modules/sys_game.cpp
|
||||
Cell/Modules/sys_heap.cpp
|
||||
Cell/Modules/sys_io.cpp
|
||||
Cell/Modules/sys_io_.cpp
|
||||
Cell/Modules/sys_libc_.cpp
|
||||
Cell/Modules/sys_libc.cpp
|
||||
Cell/Modules/sys_lv2dbg.cpp
|
||||
@@ -327,9 +343,12 @@ target_link_libraries(rpcs3_emu
|
||||
# Io
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
Io/KeyboardHandler.cpp
|
||||
Io/pad_config.cpp
|
||||
Io/pad_config_types.cpp
|
||||
Io/PadHandler.cpp
|
||||
Io/usb_device.cpp
|
||||
Io/Skylander.cpp
|
||||
Io/GHLtar.cpp
|
||||
)
|
||||
|
||||
|
||||
@@ -359,23 +378,28 @@ target_sources(rpcs3_emu PRIVATE
|
||||
RSX/Common/TextureUtils.cpp
|
||||
RSX/Common/VertexProgramDecompiler.cpp
|
||||
RSX/Null/NullGSRender.cpp
|
||||
RSX/Overlays/overlay_animation.cpp
|
||||
RSX/Overlays/overlay_edit_text.cpp
|
||||
RSX/Overlays/overlay_font.cpp
|
||||
RSX/Overlays/overlay_fonts.cpp
|
||||
RSX/Overlays/overlay_list_view.cpp
|
||||
RSX/Overlays/overlay_message_dialog.cpp
|
||||
RSX/Overlays/overlay_osk.cpp
|
||||
RSX/Overlays/overlay_perf_metrics.cpp
|
||||
RSX/Overlays/overlay_progress_bar.cpp
|
||||
RSX/Overlays/overlay_save_dialog.cpp
|
||||
RSX/Overlays/overlay_utils.cpp
|
||||
RSX/Overlays/overlays.cpp
|
||||
RSX/Overlays/overlay_shader_compile_notification.cpp
|
||||
RSX/Overlays/overlay_trophy_notification.cpp
|
||||
RSX/Overlays/Shaders/shader_loading_dialog.cpp
|
||||
RSX/Overlays/Shaders/shader_loading_dialog_native.cpp
|
||||
RSX/Capture/rsx_capture.cpp
|
||||
RSX/Capture/rsx_replay.cpp
|
||||
RSX/GL/GLCommonDecompiler.cpp
|
||||
RSX/GL/GLFragmentProgram.cpp
|
||||
RSX/GL/GLGSRender.cpp
|
||||
RSX/GL/GLHelpers.cpp
|
||||
RSX/GL/GLPresent.cpp
|
||||
RSX/GL/GLRenderTargets.cpp
|
||||
RSX/GL/GLTexture.cpp
|
||||
RSX/GL/GLVertexBuffers.cpp
|
||||
@@ -394,6 +418,7 @@ if(TARGET 3rdparty_vulkan)
|
||||
RSX/VK/VKGSRender.cpp
|
||||
RSX/VK/VKHelpers.cpp
|
||||
RSX/VK/VKMemAlloc.cpp
|
||||
RSX/VK/VKPresent.cpp
|
||||
RSX/VK/VKProgramPipeline.cpp
|
||||
RSX/VK/VKRenderPass.cpp
|
||||
RSX/VK/VKResolveHelper.cpp
|
||||
@@ -415,11 +440,13 @@ target_link_libraries(rpcs3_emu
|
||||
)
|
||||
|
||||
|
||||
# Setup cotire
|
||||
option(UNITY_BUILD_EMU "Use unity build for rpcs3_emu target" OFF)
|
||||
if (USE_COTIRE)
|
||||
# Setup cotire
|
||||
option(UNITY_BUILD_EMU "Use unity build for rpcs3_emu target" OFF)
|
||||
|
||||
set_target_properties(rpcs3_emu PROPERTIES
|
||||
COTIRE_CXX_PREFIX_HEADER_INIT "${RPCS3_SRC_DIR}/stdafx.h"
|
||||
COTIRE_ADD_UNITY_BUILD ${UNITY_BUILD_EMU})
|
||||
set_target_properties(rpcs3_emu PROPERTIES
|
||||
COTIRE_CXX_PREFIX_HEADER_INIT "${RPCS3_SRC_DIR}/stdafx.h"
|
||||
COTIRE_ADD_UNITY_BUILD ${UNITY_BUILD_EMU})
|
||||
|
||||
cotire(rpcs3_emu)
|
||||
cotire(rpcs3_emu)
|
||||
endif()
|
||||
|
||||
+49
-40
@@ -2,6 +2,7 @@
|
||||
#include "CPUThread.h"
|
||||
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/system_config.h"
|
||||
#include "Emu/Memory/vm_locking.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/GDB.h"
|
||||
@@ -15,6 +16,9 @@
|
||||
DECLARE(cpu_thread::g_threads_created){0};
|
||||
DECLARE(cpu_thread::g_threads_deleted){0};
|
||||
|
||||
LOG_CHANNEL(profiler);
|
||||
LOG_CHANNEL(sys_log, "SYS");
|
||||
|
||||
template <>
|
||||
void fmt_class_string<cpu_flag>::format(std::string& out, u64 arg)
|
||||
{
|
||||
@@ -115,7 +119,7 @@ struct cpu_prof
|
||||
}
|
||||
}
|
||||
|
||||
LOG_NOTICE(GENERAL, "Thread [0x%08x]: %u samples (%.4f%% idle):%s", id, samples, 100. * idle / samples, results);
|
||||
profiler.notice("Thread [0x%08x]: %u samples (%.4f%% idle):%s", id, samples, 100. * idle / samples, results);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -149,7 +153,7 @@ struct cpu_prof
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_FATAL(GENERAL, "Invalid Thread ID: 0x%08x", id);
|
||||
profiler.error("Invalid Thread ID: 0x%08x", id);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -211,7 +215,7 @@ struct cpu_prof
|
||||
|
||||
if (flush)
|
||||
{
|
||||
LOG_SUCCESS(GENERAL, "Flushing profiling results...");
|
||||
profiler.success("Flushing profiling results...");
|
||||
|
||||
// Print all results and cleanup
|
||||
for (auto& [id, info] : threads)
|
||||
@@ -293,7 +297,7 @@ void cpu_thread::operator()()
|
||||
|
||||
if (c != 0)
|
||||
{
|
||||
LOG_FATAL(GENERAL,"could not disable denormals");
|
||||
sys_log.fatal("Could not disable denormals.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,7 +314,7 @@ void cpu_thread::operator()()
|
||||
// Register thread in g_cpu_array
|
||||
if (!g_cpu_array_sema.try_inc(sizeof(g_cpu_array_bits) * 8))
|
||||
{
|
||||
LOG_FATAL(GENERAL, "Too many threads");
|
||||
sys_log.fatal("Too many threads.");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
@@ -319,27 +323,23 @@ void cpu_thread::operator()()
|
||||
|
||||
for (u32 i = 0;; i = (i + 1) % ::size32(g_cpu_array_bits))
|
||||
{
|
||||
if (LIKELY(~g_cpu_array_bits[i]))
|
||||
const auto [bits, ok] = g_cpu_array_bits[i].fetch_op([](u64& bits) -> u64
|
||||
{
|
||||
const u64 found = g_cpu_array_bits[i].atomic_op([](u64& bits) -> u64
|
||||
if (~bits) [[likely]]
|
||||
{
|
||||
// Find empty array slot and set its bit
|
||||
if (LIKELY(~bits))
|
||||
{
|
||||
const u64 bit = utils::cnttz64(~bits, true);
|
||||
bits |= 1ull << bit;
|
||||
return bit;
|
||||
}
|
||||
|
||||
return 64;
|
||||
});
|
||||
|
||||
if (LIKELY(found < 64))
|
||||
{
|
||||
// Fixup
|
||||
array_slot = i * 64 + found;
|
||||
break;
|
||||
// Set lowest clear bit
|
||||
bits |= bits + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (ok) [[likely]]
|
||||
{
|
||||
// Get actual slot number
|
||||
array_slot = i * 64 + utils::cnttz64(~bits, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,8 +362,8 @@ void cpu_thread::operator()()
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
Emu.Pause();
|
||||
LOG_FATAL(GENERAL, "%s thrown: %s", typeid(e).name(), e.what());
|
||||
LOG_NOTICE(GENERAL, "\n%s", dump());
|
||||
sys_log.fatal("%s thrown: %s", typeid(e).name(), e.what());
|
||||
sys_log.notice("\n%s", dump());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -387,11 +387,6 @@ void cpu_thread::operator()()
|
||||
g_cpu_suspend_lock.lock_unlock();
|
||||
}
|
||||
|
||||
void cpu_thread::on_abort()
|
||||
{
|
||||
state += cpu_flag::exit;
|
||||
}
|
||||
|
||||
cpu_thread::~cpu_thread()
|
||||
{
|
||||
vm::cleanup_unlock(*this);
|
||||
@@ -517,7 +512,7 @@ void cpu_thread::notify()
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::throw_exception("Invalid cpu_thread type");
|
||||
fmt::throw_exception("Invalid cpu_thread type" HERE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,7 +529,24 @@ void cpu_thread::abort()
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::throw_exception("Invalid cpu_thread type");
|
||||
fmt::throw_exception("Invalid cpu_thread type" HERE);
|
||||
}
|
||||
}
|
||||
|
||||
std::string cpu_thread::get_name() const
|
||||
{
|
||||
// Downcast to correct type
|
||||
if (id_type() == 1)
|
||||
{
|
||||
return thread_ctrl::get_name(*static_cast<const named_thread<ppu_thread>*>(this));
|
||||
}
|
||||
else if (id_type() == 2)
|
||||
{
|
||||
return thread_ctrl::get_name(*static_cast<const named_thread<spu_thread>*>(this));
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::throw_exception("Invalid cpu_thread type" HERE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -572,7 +584,7 @@ cpu_thread::suspend_all::suspend_all(cpu_thread* _this) noexcept
|
||||
}
|
||||
});
|
||||
|
||||
if (LIKELY(ok))
|
||||
if (ok) [[likely]]
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -609,7 +621,7 @@ void cpu_thread::stop_all() noexcept
|
||||
if (g_tls_current_cpu_thread)
|
||||
{
|
||||
// Report unsupported but unnecessary case
|
||||
LOG_FATAL(GENERAL, "cpu_thread::stop_all() has been called from a CPU thread.");
|
||||
sys_log.fatal("cpu_thread::stop_all() has been called from a CPU thread.");
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -623,24 +635,21 @@ void cpu_thread::stop_all() noexcept
|
||||
});
|
||||
}
|
||||
|
||||
LOG_NOTICE(GENERAL, "All CPU threads have been signaled.");
|
||||
sys_log.notice("All CPU threads have been signaled.");
|
||||
|
||||
while (g_cpu_array_sema)
|
||||
{
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
|
||||
// Workaround for remaining threads (TODO)
|
||||
std::this_thread::sleep_for(1300ms);
|
||||
|
||||
LOG_NOTICE(GENERAL, "All CPU threads have been stopped.");
|
||||
sys_log.notice("All CPU threads have been stopped.");
|
||||
}
|
||||
|
||||
void cpu_thread::flush_profilers() noexcept
|
||||
{
|
||||
if (!g_fxo->get<cpu_profiler>())
|
||||
{
|
||||
LOG_FATAL(GENERAL, "cpu_thread::flush_profilers() has been called incorrectly." HERE);
|
||||
profiler.fatal("cpu_thread::flush_profilers() has been called incorrectly." HERE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ protected:
|
||||
public:
|
||||
virtual ~cpu_thread();
|
||||
void operator()();
|
||||
void on_abort();
|
||||
|
||||
// Self identifier
|
||||
const u32 id;
|
||||
@@ -75,7 +74,7 @@ public:
|
||||
}
|
||||
|
||||
// Check thread type
|
||||
u32 id_type()
|
||||
u32 id_type() const
|
||||
{
|
||||
return id >> 24;
|
||||
}
|
||||
@@ -89,8 +88,8 @@ public:
|
||||
// Thread stats for external observation
|
||||
static atomic_t<u64> g_threads_created, g_threads_deleted;
|
||||
|
||||
// Get thread name
|
||||
virtual std::string get_name() const = 0;
|
||||
// Get thread name (as assigned to named_thread)
|
||||
std::string get_name() const;
|
||||
|
||||
// Get CPU state dump
|
||||
virtual std::string dump() const;
|
||||
|
||||
@@ -40,7 +40,7 @@ void cpu_translator::initialize(llvm::LLVMContext& context, llvm::ExecutionEngin
|
||||
cpu == "bdver2" ||
|
||||
cpu == "bdver3" ||
|
||||
cpu == "bdver4" ||
|
||||
cpu.substr(0, 5) == "znver")
|
||||
cpu.startswith("znver"))
|
||||
{
|
||||
m_use_fma = true;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#ifdef LLVM_AVAILABLE
|
||||
|
||||
@@ -2729,6 +2729,23 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: Support doubles
|
||||
auto fre(value_t<f32[4]> a)
|
||||
{
|
||||
decltype(a) result;
|
||||
const auto av = a.eval(m_ir);
|
||||
result.value = m_ir->CreateCall(m_module->getOrInsertFunction("llvm.x86.sse.rcp.ps", av->getType(), av->getType()).getCallee(), {av});
|
||||
return result;
|
||||
}
|
||||
|
||||
auto frsqe(value_t<f32[4]> a)
|
||||
{
|
||||
decltype(a) result;
|
||||
const auto av = a.eval(m_ir);
|
||||
result.value = m_ir->CreateCall(m_module->getOrInsertFunction("llvm.x86.sse.rsqrt.ps", av->getType(), av->getType()).getCallee(), {av});
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
value_t<u8[16]> pshufb(T1 a, T2 b)
|
||||
{
|
||||
@@ -2824,4 +2841,8 @@ struct fmt_unveil<llvm::TypeSize, void>
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
#include "MFC.h"
|
||||
|
||||
#include "Utilities/sysinfo.h"
|
||||
#include "Emu/Memory/vm.h"
|
||||
#include "Emu/Cell/SPUThread.h"
|
||||
#include "Emu/Cell/lv2/sys_sync.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
template <>
|
||||
void fmt_class_string<MFC>::format(std::string& out, u64 arg)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
#include "Emu/Cell/lv2/sys_sync.h"
|
||||
@@ -265,15 +264,15 @@ class AudioDecoder : public ppu_thread
|
||||
{
|
||||
public:
|
||||
squeue_t<AdecTask> job;
|
||||
volatile bool is_closed;
|
||||
volatile bool is_finished;
|
||||
bool just_started;
|
||||
bool just_finished;
|
||||
volatile bool is_closed = false;
|
||||
volatile bool is_finished = false;
|
||||
bool just_started = false;
|
||||
bool just_finished = false;
|
||||
|
||||
AVCodec* codec;
|
||||
AVInputFormat* input_format;
|
||||
AVCodecContext* ctx;
|
||||
AVFormatContext* fmt;
|
||||
AVCodec* codec = nullptr;
|
||||
AVInputFormat* input_format = nullptr;
|
||||
AVCodecContext* ctx = nullptr;
|
||||
AVFormatContext* fmt = nullptr;
|
||||
u8* io_buf;
|
||||
|
||||
struct AudioReader
|
||||
@@ -297,7 +296,7 @@ public:
|
||||
const u32 memSize;
|
||||
const vm::ptr<CellAdecCbMsg> cbFunc;
|
||||
const u32 cbArg;
|
||||
u32 memBias;
|
||||
u32 memBias = 0;
|
||||
|
||||
AdecTask task;
|
||||
u64 last_pts, first_pts;
|
||||
@@ -313,20 +312,11 @@ public:
|
||||
, type(type)
|
||||
, memAddr(addr)
|
||||
, memSize(size)
|
||||
, memBias(0)
|
||||
, cbFunc(func)
|
||||
, cbArg(arg)
|
||||
, is_closed(false)
|
||||
, is_finished(false)
|
||||
, just_started(false)
|
||||
, just_finished(false)
|
||||
, codec(nullptr)
|
||||
, input_format(nullptr)
|
||||
, ctx(nullptr)
|
||||
, fmt(nullptr)
|
||||
{
|
||||
av_register_all();
|
||||
avcodec_register_all();
|
||||
//av_register_all();
|
||||
//avcodec_register_all();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@@ -453,7 +443,7 @@ public:
|
||||
reader.addr = task.au.addr;
|
||||
reader.size = task.au.size;
|
||||
reader.has_ats = use_ats_headers;
|
||||
//LOG_NOTICE(HLE, "Audio AU: size = 0x%x, pts = 0x%llx", task.au.size, task.au.pts);
|
||||
//cellAdec.notice("Audio AU: size = 0x%x, pts = 0x%llx", task.au.size, task.au.pts);
|
||||
|
||||
if (just_started)
|
||||
{
|
||||
@@ -513,7 +503,7 @@ public:
|
||||
{
|
||||
fmt::throw_exception("avformat_new_stream() failed" HERE);
|
||||
}
|
||||
ctx = fmt->streams[0]->codec; // TODO: check data
|
||||
//ctx = fmt->streams[0]->codec; // TODO: check data
|
||||
|
||||
opts = nullptr;
|
||||
av_dict_set(&opts, "refcounted_frames", "1", 0);
|
||||
@@ -573,7 +563,7 @@ public:
|
||||
|
||||
int got_frame = 0;
|
||||
|
||||
int decode = avcodec_decode_audio4(ctx, frame.data, &got_frame, &au);
|
||||
int decode = 0; //avcodec_decode_audio4(ctx, frame.data, &got_frame, &au);
|
||||
|
||||
if (decode <= 0)
|
||||
{
|
||||
@@ -610,7 +600,7 @@ public:
|
||||
frame.userdata = task.au.userdata;
|
||||
frame.size = frame.data->nb_samples * frame.data->channels * nbps;
|
||||
|
||||
//LOG_NOTICE(HLE, "got audio frame (pts=0x%llx, nb_samples=%d, ch=%d, sample_rate=%d, nbps=%d)",
|
||||
//cellAdec.notice("got audio frame (pts=0x%llx, nb_samples=%d, ch=%d, sample_rate=%d, nbps=%d)",
|
||||
//frame.pts, frame.data->nb_samples, frame.data->channels, frame.data->sample_rate, nbps);
|
||||
|
||||
if (frames.push(frame, &is_closed))
|
||||
@@ -714,7 +704,7 @@ next:
|
||||
adec.reader.addr = adec.task.au.addr;
|
||||
adec.reader.size = adec.task.au.size;
|
||||
adec.reader.has_ats = adec.use_ats_headers;
|
||||
//LOG_NOTICE(HLE, "Audio AU: size = 0x%x, pts = 0x%llx", adec.task.au.size, adec.task.au.pts);
|
||||
//cellAdec.notice("Audio AU: size = 0x%x, pts = 0x%llx", adec.task.au.size, adec.task.au.pts);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
#include "cellAtrac.h"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
#include "cellAtracMulti.h"
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
#include "Emu/Cell/lv2/sys_process.h"
|
||||
@@ -59,8 +57,8 @@ cell_audio_config::cell_audio_config()
|
||||
|
||||
|
||||
audio_ringbuffer::audio_ringbuffer(cell_audio_config& _cfg)
|
||||
: cfg(_cfg)
|
||||
, backend(_cfg.backend)
|
||||
: backend(_cfg.backend)
|
||||
, cfg(_cfg)
|
||||
, buf_sz(AUDIO_BUFFER_SAMPLES * _cfg.audio_channels)
|
||||
, emu_paused(Emu.IsPaused())
|
||||
{
|
||||
@@ -458,11 +456,37 @@ void cell_audio_thread::advance(u64 timestamp, bool reset)
|
||||
std::array<u64, MAX_AUDIO_EVENT_QUEUES> event_sources;
|
||||
u32 queue_count = 0;
|
||||
|
||||
for (const auto& key_pair : keys)
|
||||
event_period++;
|
||||
|
||||
for (const auto& key_inf : keys)
|
||||
{
|
||||
if (auto queue = lv2_event_queue::find(key_pair.first))
|
||||
if (const auto queue = lv2_event_queue::find(key_inf.key))
|
||||
{
|
||||
event_sources[queue_count] = key_pair.second;
|
||||
if (key_inf.flags & CELL_AUDIO_EVENTFLAG_NOMIX)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
u32 periods = 1;
|
||||
|
||||
if (key_inf.flags & CELL_AUDIO_EVENTFLAG_DECIMATE_2)
|
||||
{
|
||||
periods *= 2;
|
||||
}
|
||||
|
||||
if (key_inf.flags & CELL_AUDIO_EVENTFLAG_DECIMATE_4)
|
||||
{
|
||||
// If both flags are set periods is set to x8
|
||||
periods *= 4;
|
||||
}
|
||||
|
||||
if ((event_period ^ key_inf.start_period) & (periods - 1))
|
||||
{
|
||||
// The time has not come for this key to receive event
|
||||
continue;
|
||||
}
|
||||
|
||||
event_sources[queue_count] = key_inf.source;
|
||||
queues[queue_count++] = queue;
|
||||
}
|
||||
}
|
||||
@@ -982,6 +1006,7 @@ error_code cellAudioQuit(ppu_thread& ppu)
|
||||
// TODO
|
||||
g_audio->keys.clear();
|
||||
g_audio->key_count = 0;
|
||||
g_audio->event_period = 0;
|
||||
g_audio->init = 0;
|
||||
|
||||
return CELL_OK;
|
||||
@@ -1375,10 +1400,8 @@ error_code cellAudioCreateNotifyEventQueueEx(vm::ptr<u32> id, vm::ptr<u64> key,
|
||||
return AudioCreateNotifyEventQueue(id, key, queue_type);
|
||||
}
|
||||
|
||||
error_code cellAudioSetNotifyEventQueue(u64 key)
|
||||
error_code AudioSetNotifyEventQueue(u64 key, u32 iFlags)
|
||||
{
|
||||
cellAudio.warning("cellAudioSetNotifyEventQueue(key=0x%llx)", key);
|
||||
|
||||
const auto g_audio = g_fxo->get<cell_audio>();
|
||||
|
||||
std::lock_guard lock(g_audio->mutex);
|
||||
@@ -1395,32 +1418,40 @@ error_code cellAudioSetNotifyEventQueue(u64 key)
|
||||
|
||||
for (const auto& k : g_audio->keys) // check for duplicates
|
||||
{
|
||||
if (k.first == key)
|
||||
if (k.key == key)
|
||||
{
|
||||
return CELL_AUDIO_ERROR_TRANS_EVENT;
|
||||
}
|
||||
}
|
||||
|
||||
// Set unique source associated with the key
|
||||
g_audio->keys.emplace_back(key, ((process_getpid() + 1ull) << 32) + (lv2_event_port::id_base + g_audio->key_count * lv2_event_port::id_step));
|
||||
g_audio->key_count = (g_audio->key_count + 1) % lv2_event_port::id_count;
|
||||
g_audio->keys.push_back({g_audio->event_period, iFlags, ((process_getpid() + u64{}) << 32) + lv2_event_port::id_base + (g_audio->key_count++ * lv2_event_port::id_step), key});
|
||||
g_audio->key_count %= lv2_event_port::id_count;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellAudioSetNotifyEventQueue(u64 key)
|
||||
{
|
||||
cellAudio.warning("cellAudioSetNotifyEventQueue(key=0x%llx)", key);
|
||||
|
||||
return AudioSetNotifyEventQueue(key, 0);
|
||||
}
|
||||
|
||||
error_code cellAudioSetNotifyEventQueueEx(u64 key, u32 iFlags)
|
||||
{
|
||||
cellAudio.todo("cellAudioSetNotifyEventQueueEx(key=0x%llx, iFlags=0x%x)", key, iFlags);
|
||||
|
||||
// TODO
|
||||
if (iFlags & (~0u >> 5))
|
||||
{
|
||||
return CELL_AUDIO_ERROR_PARAM;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
return AudioSetNotifyEventQueue(key, iFlags);
|
||||
}
|
||||
|
||||
error_code cellAudioRemoveNotifyEventQueue(u64 key)
|
||||
error_code AudioRemoveNotifyEventQueue(u64 key, u32 iFlags)
|
||||
{
|
||||
cellAudio.warning("cellAudioRemoveNotifyEventQueue(key=0x%llx)", key);
|
||||
|
||||
const auto g_audio = g_fxo->get<cell_audio>();
|
||||
|
||||
std::lock_guard lock(g_audio->mutex);
|
||||
@@ -1432,8 +1463,13 @@ error_code cellAudioRemoveNotifyEventQueue(u64 key)
|
||||
|
||||
for (auto i = g_audio->keys.cbegin(); i != g_audio->keys.cend(); i++)
|
||||
{
|
||||
if (i->first == key)
|
||||
if (i->key == key)
|
||||
{
|
||||
if (i->flags != iFlags)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
g_audio->keys.erase(i);
|
||||
|
||||
return CELL_OK;
|
||||
@@ -1443,13 +1479,23 @@ error_code cellAudioRemoveNotifyEventQueue(u64 key)
|
||||
return CELL_AUDIO_ERROR_TRANS_EVENT;
|
||||
}
|
||||
|
||||
error_code cellAudioRemoveNotifyEventQueue(u64 key)
|
||||
{
|
||||
cellAudio.warning("cellAudioRemoveNotifyEventQueue(key=0x%llx)", key);
|
||||
|
||||
return AudioRemoveNotifyEventQueue(key, 0);
|
||||
}
|
||||
|
||||
error_code cellAudioRemoveNotifyEventQueueEx(u64 key, u32 iFlags)
|
||||
{
|
||||
cellAudio.todo("cellAudioRemoveNotifyEventQueueEx(key=0x%llx, iFlags=0x%x)", key, iFlags);
|
||||
|
||||
// TODO
|
||||
if (iFlags & (~0u >> 5))
|
||||
{
|
||||
return CELL_AUDIO_ERROR_PARAM;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
return AudioRemoveNotifyEventQueue(key, iFlags);
|
||||
}
|
||||
|
||||
error_code cellAudioAddData(u32 portNum, vm::ptr<float> src, u32 samples, float volume)
|
||||
|
||||
@@ -194,7 +194,7 @@ public:
|
||||
const u64 minimum_block_period = audio_block_period / 2; // the block period will not be dynamically lowered below this value (usecs)
|
||||
const u64 maximum_block_period = (6 * audio_block_period) / 5; // the block period will not be dynamically increased above this value (usecs)
|
||||
|
||||
const u32 desired_full_buffers = buffering_enabled ? static_cast<u32>(desired_buffer_duration / audio_block_period) + 1 : 2;
|
||||
const u32 desired_full_buffers = buffering_enabled ? static_cast<u32>(desired_buffer_duration / audio_block_period) + 3 : 2;
|
||||
const u32 num_allocated_buffers = desired_full_buffers + EXTRA_AUDIO_BUFFERS; // number of ringbuffer buffers
|
||||
|
||||
const f32 period_average_alpha = 0.02f; // alpha factor for the m_average_period rolling average
|
||||
@@ -235,7 +235,7 @@ private:
|
||||
std::unique_ptr<AudioDumper> m_dump;
|
||||
|
||||
std::unique_ptr<float[]> buffer[MAX_AUDIO_BUFFERS];
|
||||
const float silence_buffer[AUDIO_MAX_CHANNELS_COUNT * AUDIO_BUFFER_SAMPLES] = { 0 };
|
||||
const float silence_buffer[u32{AUDIO_MAX_CHANNELS_COUNT} * u32{AUDIO_BUFFER_SAMPLES}] = { 0 };
|
||||
|
||||
bool backend_open = false;
|
||||
bool playing = false;
|
||||
@@ -342,7 +342,17 @@ public:
|
||||
atomic_t<u32> init = 0;
|
||||
|
||||
u32 key_count = 0;
|
||||
std::vector<std::pair<u64, u64>> keys;
|
||||
u8 event_period = 0;
|
||||
|
||||
struct key_info
|
||||
{
|
||||
u8 start_period; // Starting event_period
|
||||
u32 flags; // iFlags
|
||||
u64 source; // Event source
|
||||
u64 key; // Key
|
||||
};
|
||||
|
||||
std::vector<key_info> keys;
|
||||
std::array<audio_port, AUDIO_PORT_COUNT> ports;
|
||||
|
||||
u64 m_last_period_end = 0;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/BEType.h"
|
||||
|
||||
@@ -15,23 +15,24 @@ enum CellAudioInError
|
||||
CELL_AUDIO_IN_ERROR_CONDITION_BUSY = 0x8002b267,
|
||||
};
|
||||
|
||||
enum
|
||||
enum CellAudioInDeviceMode
|
||||
{
|
||||
CELL_AUDIO_IN_SINGLE_DEVICE_MODE = 0,
|
||||
CELL_AUDIO_IN_MULTI_DEVICE_MODE = 1,
|
||||
CELL_AUDIO_IN_MULTI_DEVICE_MODE_2 = 2,
|
||||
CELL_AUDIO_IN_SINGLE_DEVICE_MODE = 0,
|
||||
CELL_AUDIO_IN_MULTI_DEVICE_MODE = 1,
|
||||
CELL_AUDIO_IN_MULTI_DEVICE_MODE_2 = 2,
|
||||
CELL_AUDIO_IN_MULTI_DEVICE_MODE_10 = 10,
|
||||
};
|
||||
|
||||
enum CellAudioInPortType
|
||||
{
|
||||
CELL_AUDIO_IN_PORT_USB = 3,
|
||||
CELL_AUDIO_IN_PORT_USB = 3,
|
||||
CELL_AUDIO_IN_PORT_BLUETOOTH = 4,
|
||||
};
|
||||
|
||||
enum CellAudioInDeviceState
|
||||
{
|
||||
CELL_AUDIO_IN_DEVICE_STATE_UNAVAILABLE = 0,
|
||||
CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE = 1,
|
||||
CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE = 1,
|
||||
};
|
||||
|
||||
enum CellAudioInCodingType
|
||||
@@ -42,19 +43,19 @@ enum CellAudioInCodingType
|
||||
enum CellAudioInChnum
|
||||
{
|
||||
CELL_AUDIO_IN_CHNUM_NONE = 0,
|
||||
CELL_AUDIO_IN_CHNUM_1 = 1,
|
||||
CELL_AUDIO_IN_CHNUM_2 = 2,
|
||||
CELL_AUDIO_IN_CHNUM_1 = 1,
|
||||
CELL_AUDIO_IN_CHNUM_2 = 2,
|
||||
};
|
||||
|
||||
enum CellAudioInFs
|
||||
{
|
||||
CELL_AUDIO_IN_FS_UNDEFINED = 0x00,
|
||||
CELL_AUDIO_IN_FS_8KHZ = 0x01,
|
||||
CELL_AUDIO_IN_FS_12KHZ = 0x02,
|
||||
CELL_AUDIO_IN_FS_16KHZ = 0x04,
|
||||
CELL_AUDIO_IN_FS_24KHZ = 0x08,
|
||||
CELL_AUDIO_IN_FS_32KHZ = 0x10,
|
||||
CELL_AUDIO_IN_FS_48KHZ = 0x20,
|
||||
CELL_AUDIO_IN_FS_8KHZ = 0x01,
|
||||
CELL_AUDIO_IN_FS_12KHZ = 0x02,
|
||||
CELL_AUDIO_IN_FS_16KHZ = 0x04,
|
||||
CELL_AUDIO_IN_FS_24KHZ = 0x08,
|
||||
CELL_AUDIO_IN_FS_32KHZ = 0x10,
|
||||
CELL_AUDIO_IN_FS_48KHZ = 0x20,
|
||||
};
|
||||
|
||||
struct CellAudioInSoundMode
|
||||
@@ -80,7 +81,7 @@ struct CellAudioInDeviceInfo
|
||||
|
||||
struct CellAudioInRegistrationOption
|
||||
{
|
||||
//(Omitted)
|
||||
be_t<u32> reserved;
|
||||
};
|
||||
|
||||
struct CellAudioInDeviceConfiguration
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "cellAudioOut.h"
|
||||
|
||||
extern logs::channel cellSysutil;
|
||||
LOG_CHANNEL(cellSysutil);
|
||||
|
||||
template<>
|
||||
void fmt_class_string<CellAudioOutError>::format(std::string& out, u64 arg)
|
||||
@@ -283,18 +283,6 @@ error_code cellAudioOutSetCopyControl(u32 audioOut, u32 control)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellAudioOutConfigure2()
|
||||
{
|
||||
cellSysutil.todo("cellAudioOutConfigure2()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellAudioOutGetConfiguration2()
|
||||
{
|
||||
cellSysutil.todo("cellAudioOutGetConfiguration2()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellAudioOutRegisterCallback()
|
||||
{
|
||||
cellSysutil.todo("cellAudioOutRegisterCallback()");
|
||||
@@ -312,13 +300,11 @@ void cellSysutil_AudioOut_init()
|
||||
{
|
||||
REG_FUNC(cellSysutil, cellAudioOutGetState);
|
||||
REG_FUNC(cellSysutil, cellAudioOutConfigure);
|
||||
REG_FUNC(cellSysutil, cellAudioOutConfigure2);
|
||||
REG_FUNC(cellSysutil, cellAudioOutGetSoundAvailability);
|
||||
REG_FUNC(cellSysutil, cellAudioOutGetSoundAvailability2);
|
||||
REG_FUNC(cellSysutil, cellAudioOutGetDeviceInfo);
|
||||
REG_FUNC(cellSysutil, cellAudioOutGetNumberOfDevice);
|
||||
REG_FUNC(cellSysutil, cellAudioOutGetConfiguration);
|
||||
REG_FUNC(cellSysutil, cellAudioOutGetConfiguration2);
|
||||
REG_FUNC(cellSysutil, cellAudioOutSetCopyControl);
|
||||
REG_FUNC(cellSysutil, cellAudioOutRegisterCallback);
|
||||
REG_FUNC(cellSysutil, cellAudioOutUnregisterCallback);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user