Compare commits
547 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
334e859ab1 | ||
|
|
17b16cf6f6 | ||
|
|
3d9126ba87 | ||
|
|
7fd54fed92 | ||
|
|
5d9ee12b1a | ||
|
|
bad00085ca | ||
|
|
e56e2a1528 | ||
|
|
99ac33de20 | ||
|
|
d43c49264f | ||
|
|
6b365f7703 | ||
|
|
41dde2394b | ||
|
|
5a579f66a0 | ||
|
|
16198f979e | ||
|
|
843dd62c81 | ||
|
|
e6242ab5e6 | ||
|
|
acede1f1d3 | ||
|
|
8475496630 | ||
|
|
3c40496409 | ||
|
|
abc23416e8 | ||
|
|
4f120a9ec0 | ||
|
|
18f8012233 | ||
|
|
3e0ec3dbd7 | ||
|
|
3cfe77ae75 | ||
|
|
3062eb52f4 | ||
|
|
376f6397c6 | ||
|
|
6a3d59fdc1 | ||
|
|
bc43946140 | ||
|
|
7391741a20 | ||
|
|
f1f7f2cba9 | ||
|
|
4ac9b47dca | ||
|
|
c33755e2b9 | ||
|
|
87a92ef062 | ||
|
|
c9d7abe9c9 | ||
|
|
37fa9a15cd | ||
|
|
3dd3cdeafd | ||
|
|
623d772476 | ||
|
|
4f281b3829 | ||
|
|
08da0b7acc | ||
|
|
f81b915fd8 | ||
|
|
dd6c67c627 | ||
|
|
42d43ea741 | ||
|
|
d0825c9519 | ||
|
|
1913cf4783 | ||
|
|
40dee76c57 | ||
|
|
23d68a07dc | ||
|
|
60746e4e52 | ||
|
|
20d86d8a36 | ||
|
|
e9ad8e9185 | ||
|
|
1740aa5444 | ||
|
|
5ab597041f | ||
|
|
1dd4861d38 | ||
|
|
a6da2b93c1 | ||
|
|
378c881427 | ||
|
|
b1109931b9 | ||
|
|
c16cfbbc6c | ||
|
|
a994446b6e | ||
|
|
e2f2a49d2d | ||
|
|
3f78a61f09 | ||
|
|
5aafc83cc9 | ||
|
|
6d00780045 | ||
|
|
59dae03dbe | ||
|
|
22420612db | ||
|
|
b7551e457b | ||
|
|
2ba4e2263c | ||
|
|
0369ee7248 | ||
|
|
ea3151f475 | ||
|
|
6c9ca8cbca | ||
|
|
c30cd898fc | ||
|
|
f1a4a004fb | ||
|
|
0a023cfb4f | ||
|
|
9022d926eb | ||
|
|
fbb3cd110c | ||
|
|
bc0f1896fc | ||
|
|
4415e00181 | ||
|
|
cc2e14ec2a | ||
|
|
10c6d89119 | ||
|
|
239ac8abe2 | ||
|
|
9e11a76e92 | ||
|
|
e8c2bb24b2 | ||
|
|
b7953d2ebf | ||
|
|
d08cfb55fe | ||
|
|
88eb612718 | ||
|
|
bd9c2aa51f | ||
|
|
bfe49edb2a | ||
|
|
82413a6c89 | ||
|
|
62c69f4a1e | ||
|
|
2a3f3bf977 | ||
|
|
32ece18bb6 | ||
|
|
13f9cf2bd0 | ||
|
|
72b497e876 | ||
|
|
285d8d8b7d | ||
|
|
022fc59dcd | ||
|
|
47054327c2 | ||
|
|
28b92db7fd | ||
|
|
dabfd90dfe | ||
|
|
9cd7485cd7 | ||
|
|
8fc4003dab | ||
|
|
b5b613ea29 | ||
|
|
299f943202 | ||
|
|
d1b23b2b51 | ||
|
|
c6a740d7c2 | ||
|
|
8d32bf9a96 | ||
|
|
d652e41365 | ||
|
|
e74dbfc572 | ||
|
|
5483c08b44 | ||
|
|
f85d880ac6 | ||
|
|
7495142688 | ||
|
|
a0179e5ca5 | ||
|
|
07dc0bbf3e | ||
|
|
f208953585 | ||
|
|
0214351f4f | ||
|
|
bf25299272 | ||
|
|
d4f87e9af4 | ||
|
|
3967f9c6ef | ||
|
|
55d0b0609d | ||
|
|
9531a29283 | ||
|
|
46572d027d | ||
|
|
0d6eafe11a | ||
|
|
e4bd0bddea | ||
|
|
e862c50a70 | ||
|
|
f823c1d599 | ||
|
|
010227e149 | ||
|
|
27650499bc | ||
|
|
df669bc540 | ||
|
|
f3137d3bc1 | ||
|
|
ebb8e06df0 | ||
|
|
c079cf4eec | ||
|
|
62937798a0 | ||
|
|
f48d5e4c4c | ||
|
|
f8764bb5d3 | ||
|
|
f8a037ead4 | ||
|
|
d08fd7e86d | ||
|
|
8b28dc55e6 | ||
|
|
e1630c4d43 | ||
|
|
9f6d305eab | ||
|
|
8ac3a3f45e | ||
|
|
634d9ee18b | ||
|
|
ba6f3e8f9f | ||
|
|
17a0ef1e1e | ||
|
|
c3a8ea76f1 | ||
|
|
0a5e01b710 | ||
|
|
a70ed9c8ae | ||
|
|
013778aa21 | ||
|
|
be155f4d9d | ||
|
|
5fdfbfe25a | ||
|
|
b18ccf9399 | ||
|
|
e81a2080eb | ||
|
|
1723b4d8d4 | ||
|
|
2e7ce96b1d | ||
|
|
eafdcc1b8a | ||
|
|
ab71997b2c | ||
|
|
7db0b8d74f | ||
|
|
659a612368 | ||
|
|
bec05db746 | ||
|
|
1df3a7710e | ||
|
|
d03fc77475 | ||
|
|
2e0a9f66a0 | ||
|
|
326b044c19 | ||
|
|
87f89ac82d | ||
|
|
fae2dd0344 | ||
|
|
a904d70afe | ||
|
|
b11f6f90e7 | ||
|
|
4d96997447 | ||
|
|
b5c204ac6f | ||
|
|
701dd649e6 | ||
|
|
79c1ed80e9 | ||
|
|
cb267093bb | ||
|
|
b2febaff2f | ||
|
|
956e200f12 | ||
|
|
0eba5911f2 | ||
|
|
b134e6afcf | ||
|
|
d9e316e353 | ||
|
|
902fc61ef8 | ||
|
|
16ffecd8fb | ||
|
|
e8e5041955 | ||
|
|
ccca5e7c28 | ||
|
|
2c8afe1140 | ||
|
|
2ef04f69b2 | ||
|
|
14bf88a777 | ||
|
|
3990da488b | ||
|
|
80982748c8 | ||
|
|
e61a4dd485 | ||
|
|
b05f8ea5b5 | ||
|
|
3841ec4200 | ||
|
|
17ad56c1dc | ||
|
|
f633b0c875 | ||
|
|
e3b6f6c016 | ||
|
|
412b31ad72 | ||
|
|
aa26baa3db | ||
|
|
4ef392906b | ||
|
|
3f49210234 | ||
|
|
fe84842137 | ||
|
|
5367935d35 | ||
|
|
8a47e7e493 | ||
|
|
e90a12f80c | ||
|
|
d019bb16f6 | ||
|
|
057170928c | ||
|
|
de18592179 | ||
|
|
60e6e8953e | ||
|
|
2985056340 | ||
|
|
ce4f159b1c | ||
|
|
6a999cf800 | ||
|
|
43d98ca8fe | ||
|
|
5b3fab6766 | ||
|
|
b2c1672e10 | ||
|
|
d3f9ea90e7 | ||
|
|
48d4efbd69 | ||
|
|
a3e82e8e1f | ||
|
|
ac09b5a2e9 | ||
|
|
6b63aaa5b4 | ||
|
|
db5f2bfa7e | ||
|
|
f600f6eebd | ||
|
|
c93ea96366 | ||
|
|
71b4a3b9f6 | ||
|
|
9dc0d13ba5 | ||
|
|
7222d9a4c3 | ||
|
|
9df8e924fb | ||
|
|
3ed8a1cac7 | ||
|
|
4a8eb6745e | ||
|
|
531c25386e | ||
|
|
174cba5c58 | ||
|
|
e59126809c | ||
|
|
1f6fe062ca | ||
|
|
ed542a7309 | ||
|
|
ef2d5ab0c1 | ||
|
|
59f4ff4659 | ||
|
|
5a28dce9eb | ||
|
|
8d4899d6ea | ||
|
|
95144cc39c | ||
|
|
8b4443c966 | ||
|
|
5ba71369ac | ||
|
|
5d529698c9 | ||
|
|
5b9bcbf438 | ||
|
|
5922f2c46d | ||
|
|
2b082e2710 | ||
|
|
de580ccdd5 | ||
|
|
e52a87b98a | ||
|
|
0905dc1ff4 | ||
|
|
636ad34707 | ||
|
|
7fc516cc1a | ||
|
|
77bdc49343 | ||
|
|
1a1af3fda3 | ||
|
|
83aa38b239 | ||
|
|
c03795300a | ||
|
|
44e09ba807 | ||
|
|
d6d7d0989c | ||
|
|
ac628f139d | ||
|
|
477aab5960 | ||
|
|
14ac40436e | ||
|
|
b8825fbf10 | ||
|
|
b60834ac41 | ||
|
|
bddad50dd4 | ||
|
|
e128e90350 | ||
|
|
7da47da66e | ||
|
|
34264879b3 | ||
|
|
73d9c494ea | ||
|
|
bb0c3fc828 | ||
|
|
c9b511da08 | ||
|
|
1957640ea2 | ||
|
|
ae58e46036 | ||
|
|
2b9a6b3281 | ||
|
|
43f0f163e1 | ||
|
|
9f66cae865 | ||
|
|
778be45103 | ||
|
|
fdca7b5f7a | ||
|
|
9cab6809f2 | ||
|
|
1b41b875dc | ||
|
|
e6224fec27 | ||
|
|
eabeedf6af | ||
|
|
0d408b965b | ||
|
|
86135864da | ||
|
|
7639667562 | ||
|
|
5a47832221 | ||
|
|
50023bdae7 | ||
|
|
a992aac5eb | ||
|
|
958c98bdae | ||
|
|
0ca8fce9d0 | ||
|
|
beddc8afd2 | ||
|
|
85d77a3d24 | ||
|
|
51f37f5061 | ||
|
|
35aca0bf1f | ||
|
|
33bb53571b | ||
|
|
5617831d5f | ||
|
|
459826a705 | ||
|
|
8aa21a03b3 | ||
|
|
10953495c1 | ||
|
|
2fcbb35ad2 | ||
|
|
45fd7c4a37 | ||
|
|
da1114ca59 | ||
|
|
4f2b2d0bc5 | ||
|
|
dbfd106ba0 | ||
|
|
ed7e597b44 | ||
|
|
4e7e0f8112 | ||
|
|
0315fe8c3d | ||
|
|
c6ab2c94d9 | ||
|
|
660991cffb | ||
|
|
e10248f308 | ||
|
|
56d2958aaf | ||
|
|
b1556309fe | ||
|
|
b7369f99ec | ||
|
|
9629736625 | ||
|
|
39f75350bb | ||
|
|
cc89b7bfcb | ||
|
|
a155d3b7ff | ||
|
|
88f1fe79c6 | ||
|
|
177bdb94df | ||
|
|
4d1a2509df | ||
|
|
ac50d2cd60 | ||
|
|
2d2de1422e | ||
|
|
9e2f30ab4a | ||
|
|
be50a6ceef | ||
|
|
7788178f01 | ||
|
|
20c97c60d5 | ||
|
|
ae5e2d07c6 | ||
|
|
ee3ca32fa3 | ||
|
|
ed2da0ef70 | ||
|
|
c0011fdacd | ||
|
|
a886e3bc2a | ||
|
|
4cf4a5ecdc | ||
|
|
c79c9755b4 | ||
|
|
434cffa37d | ||
|
|
0cc2e7d81d | ||
|
|
84d39530cf | ||
|
|
3769a80fac | ||
|
|
227bc78cbe | ||
|
|
e0fb6a188c | ||
|
|
d79558a6f0 | ||
|
|
222ba939f2 | ||
|
|
f16eb90b8f | ||
|
|
0b855f1c21 | ||
|
|
dcc27d6dc1 | ||
|
|
b0ca330e14 | ||
|
|
cb3183212d | ||
|
|
65faeb9b2a | ||
|
|
b258403f0d | ||
|
|
65ea52394b | ||
|
|
73eaef9c05 | ||
|
|
b305646c44 | ||
|
|
c28ed85875 | ||
|
|
ca96b04a0c | ||
|
|
0171ec606b | ||
|
|
f73a280eeb | ||
|
|
ad1810e895 | ||
|
|
37041ea12c | ||
|
|
358050cfc6 | ||
|
|
68183e7b5a | ||
|
|
f9945f8a3b | ||
|
|
d1d7582a5b | ||
|
|
1f37dd02ce | ||
|
|
27dbbd8227 | ||
|
|
cfc28e0c1a | ||
|
|
ca17f581f5 | ||
|
|
20bd26dc7d | ||
|
|
40bccd74d3 | ||
|
|
4c0cf3d5ff | ||
|
|
3d4dfefaec | ||
|
|
910b02d74b | ||
|
|
9d08a11c1d | ||
|
|
99ae9dbf49 | ||
|
|
9eb485702f | ||
|
|
b87a588c37 | ||
|
|
bb9093ed57 | ||
|
|
c2e0820ac2 | ||
|
|
c824648db5 | ||
|
|
6cd1482354 | ||
|
|
c82a4df000 | ||
|
|
467858633f | ||
|
|
1aafb0f3a3 | ||
|
|
2863e1edb9 | ||
|
|
c9845c486e | ||
|
|
a66204eb5c | ||
|
|
6022bc8394 | ||
|
|
f92594d744 | ||
|
|
3413f1f7ce | ||
|
|
11b4ab9685 | ||
|
|
1ec8d2123d | ||
|
|
72b90494e7 | ||
|
|
f4ba523992 | ||
|
|
b6b7d78ded | ||
|
|
eef097bdc7 | ||
|
|
88582b84a5 | ||
|
|
b27ab46bde | ||
|
|
b3298465cf | ||
|
|
9cba0f1794 | ||
|
|
1b7dc84132 | ||
|
|
b55dc9c85e | ||
|
|
78e974ba68 | ||
|
|
86095e62cc | ||
|
|
f6893969b3 | ||
|
|
deaf6f9e35 | ||
|
|
cf643df792 | ||
|
|
4900c51864 | ||
|
|
57eca6374a | ||
|
|
36e60c217a | ||
|
|
be4c7ed082 | ||
|
|
16b14aa7e3 | ||
|
|
b30aa7007e | ||
|
|
a5e9745380 | ||
|
|
aa0f596a6e | ||
|
|
98f0352728 | ||
|
|
10738588a4 | ||
|
|
8004af0d05 | ||
|
|
78a81614ee | ||
|
|
1a28f4fa8c | ||
|
|
212a6ab937 | ||
|
|
94f4009c3b | ||
|
|
5ecf152c8e | ||
|
|
f1423fcbc1 | ||
|
|
c97ff4460c | ||
|
|
12b05c719e | ||
|
|
b4bf099793 | ||
|
|
5e343edc9e | ||
|
|
d8f745382b | ||
|
|
c33abac275 | ||
|
|
d30110348b | ||
|
|
67bc2f5ecd | ||
|
|
666d53299c | ||
|
|
ac19e3d061 | ||
|
|
a6cab532f8 | ||
|
|
d4fb8a887c | ||
|
|
527ce12ce4 | ||
|
|
d89bfec5f5 | ||
|
|
1bfc0dc2db | ||
|
|
0a5832798a | ||
|
|
7504df52fc | ||
|
|
c1ccbf332f | ||
|
|
d732142b66 | ||
|
|
c2dbdefedf | ||
|
|
cd8bb6ea9b | ||
|
|
4369af6b7e | ||
|
|
3754e0fdfd | ||
|
|
15925b8293 | ||
|
|
0ee38e1363 | ||
|
|
0162a2d5cb | ||
|
|
33c0bf9dc5 | ||
|
|
ed2134784e | ||
|
|
8041d72a1f | ||
|
|
170ac3f9ee | ||
|
|
94c70693f9 | ||
|
|
1a9df83535 | ||
|
|
f934da0e43 | ||
|
|
010ea89013 | ||
|
|
4697025b73 | ||
|
|
56e2013c1f | ||
|
|
6afe9e0105 | ||
|
|
3357e8d9ba | ||
|
|
75da830c13 | ||
|
|
10d6b07161 | ||
|
|
99d86deb1f | ||
|
|
b326369704 | ||
|
|
8c8da93693 | ||
|
|
e9315ace9f | ||
|
|
a0933d92fc | ||
|
|
91e67ed430 | ||
|
|
d248b90c85 | ||
|
|
692639e9b7 | ||
|
|
6f27edccb2 | ||
|
|
bde3e667be | ||
|
|
868f7f18b9 | ||
|
|
0ce52b1da2 | ||
|
|
2c785bd06c | ||
|
|
39e60cfeb1 | ||
|
|
025d111308 | ||
|
|
1c31e2b3d2 | ||
|
|
1ad97c75a0 | ||
|
|
77fd0d47e7 | ||
|
|
1b8d798835 | ||
|
|
71ebc3e90d | ||
|
|
46945b5c96 | ||
|
|
88c9608eac | ||
|
|
31816aac38 | ||
|
|
9b9de30086 | ||
|
|
a10baacf9e | ||
|
|
d561e4acc8 | ||
|
|
4ed54738fc | ||
|
|
a397a9e9a4 | ||
|
|
b7da9d5a54 | ||
|
|
0f8401906b | ||
|
|
054393917e | ||
|
|
b5f3e7951b | ||
|
|
68658ce4b0 | ||
|
|
fd0a7c0aaf | ||
|
|
7ce4a03188 | ||
|
|
4c06d55a81 | ||
|
|
b36b627d4d | ||
|
|
1a158dfcd6 | ||
|
|
11047d7fd5 | ||
|
|
cdf541fb5b | ||
|
|
ec4e1a3685 | ||
|
|
32fd57f0c8 | ||
|
|
5ded39f5d8 | ||
|
|
9ee33350de | ||
|
|
633abd5a94 | ||
|
|
c2c55e0811 | ||
|
|
e12c2cf8c6 | ||
|
|
a0b1235f82 | ||
|
|
f61b9f7338 | ||
|
|
63d3924b5b | ||
|
|
6ced80bb47 | ||
|
|
740310113b | ||
|
|
ee5f5a2c2d | ||
|
|
47cac816f6 | ||
|
|
8a250de987 | ||
|
|
bfe45774f1 | ||
|
|
c6362543d4 | ||
|
|
f707c2dac4 | ||
|
|
7c3a263839 | ||
|
|
3a6604e8fa | ||
|
|
656de23d93 | ||
|
|
4daf91fc69 | ||
|
|
8afdbf6a1f | ||
|
|
b5c03088bc | ||
|
|
8529d84f31 | ||
|
|
47f96fe13a | ||
|
|
3b558eebee | ||
|
|
95e747cd06 | ||
|
|
ec5ede68e7 | ||
|
|
2ab021da14 | ||
|
|
7fa3bf02ca | ||
|
|
34b733e70e | ||
|
|
3cdf6c536d | ||
|
|
eff3f60b73 | ||
|
|
4721ea4523 | ||
|
|
c450d264eb | ||
|
|
6673ed1274 | ||
|
|
ae28a52277 | ||
|
|
0b3ab30762 | ||
|
|
8c8de2efe9 | ||
|
|
6e3222363c | ||
|
|
9c468e0c55 | ||
|
|
d7b1ebe4a8 | ||
|
|
0485ee499f | ||
|
|
21bac2d7d7 | ||
|
|
6d90d99d12 | ||
|
|
e1d7b9fc2c | ||
|
|
a9ba2c2000 | ||
|
|
fc44261dd1 | ||
|
|
4bdb46e4c2 | ||
|
|
a3e10b1a72 | ||
|
|
db0cfb8e8b | ||
|
|
0e4b9cdde4 | ||
|
|
a1cf5020e6 | ||
|
|
6a0902e56d | ||
|
|
808704c78c | ||
|
|
c4ca802b9d | ||
|
|
c875a7984e | ||
|
|
ec204a27dc |
39
.appveyor/UtilityFunctions.ps1
Normal file
@@ -0,0 +1,39 @@
|
||||
# Set-up Visual Studio Command Prompt environment for PowerShell
|
||||
pushd "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\"
|
||||
cmd /c "VsDevCmd.bat -arch=x64 & set" | foreach {
|
||||
if ($_ -match "=") {
|
||||
$v = $_.split("="); Set-Item -Force -Path "ENV:\$($v[0])" -Value "$($v[1])"
|
||||
}
|
||||
}
|
||||
popd
|
||||
|
||||
function Which ($search_path, $name) {
|
||||
($search_path).Split(";") | Get-ChildItem -Filter $name | Select -First 1 -Exp FullName
|
||||
}
|
||||
|
||||
function GetDeps ($search_path, $binary) {
|
||||
((dumpbin /dependents $binary).Where({ $_ -match "dependencies:"}, "SkipUntil") | Select-String "[^ ]*\.dll").Matches | foreach {
|
||||
Which $search_path $_.Value
|
||||
}
|
||||
}
|
||||
|
||||
function RecursivelyGetDeps ($search_path, $binary) {
|
||||
$final_deps = @()
|
||||
$deps_to_process = GetDeps $search_path $binary
|
||||
while ($deps_to_process.Count -gt 0) {
|
||||
$current, $deps_to_process = $deps_to_process
|
||||
if ($final_deps -contains $current) { continue }
|
||||
|
||||
# Is this a system dll file?
|
||||
# We use the same algorithm that cmake uses to determine this.
|
||||
if ($current -match "$([regex]::Escape($env:SystemRoot))\\sys") { continue }
|
||||
if ($current -match "$([regex]::Escape($env:WinDir))\\sys") { continue }
|
||||
if ($current -match "\\msvc[^\\]+dll") { continue }
|
||||
if ($current -match "\\api-ms-win-[^\\]+dll") { continue }
|
||||
|
||||
$final_deps += $current
|
||||
$new_deps = GetDeps $search_path $current
|
||||
$deps_to_process += ($new_deps | ?{-not ($final_deps -contains $_)})
|
||||
}
|
||||
return $final_deps
|
||||
}
|
||||
2
.gitmodules
vendored
@@ -18,7 +18,7 @@
|
||||
url = https://github.com/fmtlib/fmt.git
|
||||
[submodule "lz4"]
|
||||
path = externals/lz4
|
||||
url = http://github.com/lz4/lz4.git
|
||||
url = https://github.com/lz4/lz4.git
|
||||
[submodule "unicorn"]
|
||||
path = externals/unicorn
|
||||
url = https://github.com/yuzu-emu/unicorn
|
||||
|
||||
@@ -23,7 +23,7 @@ matrix:
|
||||
- os: osx
|
||||
env: NAME="macos build"
|
||||
sudo: false
|
||||
osx_image: xcode9.2
|
||||
osx_image: xcode9.3
|
||||
install: "./.travis/macos/deps.sh"
|
||||
script: "./.travis/macos/build.sh"
|
||||
after_success: "./.travis/macos/upload.sh"
|
||||
|
||||
@@ -160,6 +160,9 @@ set_property(DIRECTORY APPEND PROPERTY
|
||||
COMPILE_DEFINITIONS $<$<CONFIG:Debug>:_DEBUG> $<$<NOT:$<CONFIG:Debug>>:NDEBUG>)
|
||||
|
||||
|
||||
math(EXPR EMU_ARCH_BITS ${CMAKE_SIZEOF_VOID_P}*8)
|
||||
add_definitions(-DEMU_ARCH_BITS=${EMU_ARCH_BITS})
|
||||
|
||||
# System imported libraries
|
||||
# ======================
|
||||
|
||||
@@ -275,7 +278,7 @@ endif()
|
||||
if (ENABLE_QT)
|
||||
if (YUZU_USE_BUNDLED_QT)
|
||||
if (MSVC14 AND ARCHITECTURE_x86_64)
|
||||
set(QT_VER qt-5.7-msvc2015_64)
|
||||
set(QT_VER qt-5.10.0-msvc2015_64)
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable YUZU_USE_BUNDLED_QT and provide your own.")
|
||||
endif()
|
||||
|
||||
@@ -7,7 +7,7 @@ yuzu is an experimental open-source emulator for the Nintendo Switch from the cr
|
||||
|
||||
It is written in C++ with portability in mind, with builds actively maintained for Windows, Linux and macOS. The emulator is currently only useful for homebrew development and research purposes.
|
||||
|
||||
yuzu only emulates a subset of Switch hardware and therefore is generally only useful for running/debugging homebrew applications. At this time, yuzu does not run any commercial Switch games. yuzu can boot some games, to varying degrees of success, but does not implement any of the necessary GPU features to render 3D graphics.
|
||||
yuzu only emulates a subset of Switch hardware and therefore is generally only useful for running/debugging homebrew applications. At this time, yuzu cannot play any commercial games without major problems. yuzu can boot some games, to varying degrees of success, but does not implement any of the necessary GPU features to render 3D graphics.
|
||||
|
||||
yuzu is licensed under the GPLv2 (or any later version). Refer to the license.txt file included.
|
||||
|
||||
|
||||
23
appveyor.yml
@@ -121,23 +121,16 @@ after_build:
|
||||
Get-ChildItem "$CMAKE_BINARY_DIR" -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST
|
||||
Copy-Item -path "$CMAKE_SOURCE_DIR/license.txt" -destination $RELEASE_DIST
|
||||
Copy-Item -path "$CMAKE_SOURCE_DIR/README.md" -destination $RELEASE_DIST
|
||||
|
||||
# copy all the dll dependencies to the release folder
|
||||
# hardcoded list because we don't build static and determining the list of dlls from the binary is a pain.
|
||||
$MingwDLLs = "Qt5Core.dll","Qt5Widgets.dll","Qt5Gui.dll","Qt5OpenGL.dll",
|
||||
# QT dll dependencies
|
||||
"libbz2-*.dll","libicudt*.dll","libicuin*.dll","libicuuc*.dll","libffi-*.dll",
|
||||
"libfreetype-*.dll","libglib-*.dll","libgobject-*.dll","libgraphite2.dll","libiconv-*.dll",
|
||||
"libharfbuzz-*.dll","libintl-*.dll","libpcre-*.dll","libpcre2-16-*.dll","libpcre16-*.dll","libpng16-*.dll",
|
||||
# Runtime/Other dependencies
|
||||
"libgcc_s_seh-*.dll","libstdc++-*.dll","libwinpthread-*.dll","SDL2.dll","zlib1.dll"
|
||||
. "./.appveyor/UtilityFunctions.ps1"
|
||||
$DLLSearchPath = "C:\msys64\mingw64\bin;$env:PATH"
|
||||
$MingwDLLs = RecursivelyGetDeps $DLLSearchPath "$RELEASE_DIST\yuzu.exe"
|
||||
$MingwDLLs += RecursivelyGetDeps $DLLSearchPath "$RELEASE_DIST\yuzu_cmd.exe"
|
||||
Write-Host "Detected the following dependencies:"
|
||||
Write-Host $MingwDLLs
|
||||
foreach ($file in $MingwDLLs) {
|
||||
Copy-Item -path "C:/msys64/mingw64/bin/$file" -force -destination "$RELEASE_DIST"
|
||||
}
|
||||
# the above list copies a few extra debug dlls that aren't needed (thanks globbing patterns!)
|
||||
# so we can remove them by hardcoding another list of extra dlls to remove
|
||||
$DebugDLLs = "libicudtd*.dll","libicuind*.dll","libicuucd*.dll"
|
||||
foreach ($file in $DebugDLLs) {
|
||||
Remove-Item -path "$RELEASE_DIST/$file"
|
||||
Copy-Item -path "$file" -force -destination "$RELEASE_DIST"
|
||||
}
|
||||
|
||||
# copy the qt windows plugin dll to platforms
|
||||
|
||||
5
dist/icons/icons.qrc
vendored
@@ -1,5 +0,0 @@
|
||||
<RCC>
|
||||
<qresource prefix="icons">
|
||||
<file>yuzu.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
BIN
dist/icons/yuzu.png
vendored
|
Before Width: | Height: | Size: 7.5 KiB |
11
dist/qt_themes/default/default.qrc
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
<RCC>
|
||||
<qresource prefix="icons/default">
|
||||
<file alias="index.theme">icons/index.theme</file>
|
||||
|
||||
<file alias="16x16/checked.png">icons/16x16/checked.png</file>
|
||||
|
||||
<file alias="16x16/failed.png">icons/16x16/failed.png</file>
|
||||
|
||||
<file alias="256x256/yuzu.png">icons/256x256/yuzu.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
BIN
dist/qt_themes/default/icons/16x16/checked.png
vendored
Normal file
|
After Width: | Height: | Size: 451 B |
BIN
dist/qt_themes/default/icons/16x16/failed.png
vendored
Normal file
|
After Width: | Height: | Size: 428 B |
BIN
dist/qt_themes/default/icons/256x256/yuzu.png
vendored
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
10
dist/qt_themes/default/icons/index.theme
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
[Icon Theme]
|
||||
Name=default
|
||||
Comment=default theme
|
||||
Directories=16x16,256x256
|
||||
|
||||
[16x16]
|
||||
Size=16
|
||||
|
||||
[256x256]
|
||||
Size=256
|
||||
11
dist/qt_themes/qdarkstyle/icons/index.theme
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
[Icon Theme]
|
||||
Name=qdarkstyle
|
||||
Comment=dark theme
|
||||
Inherits=default
|
||||
Directories=16x16,256x256
|
||||
|
||||
[16x16]
|
||||
Size=16
|
||||
|
||||
[256x256]
|
||||
Size=256
|
||||
BIN
dist/qt_themes/qdarkstyle/rc/Hmovetoolbar.png
vendored
Normal file
|
After Width: | Height: | Size: 220 B |
BIN
dist/qt_themes/qdarkstyle/rc/Hsepartoolbar.png
vendored
Normal file
|
After Width: | Height: | Size: 172 B |
BIN
dist/qt_themes/qdarkstyle/rc/Vmovetoolbar.png
vendored
Normal file
|
After Width: | Height: | Size: 228 B |
BIN
dist/qt_themes/qdarkstyle/rc/Vsepartoolbar.png
vendored
Normal file
|
After Width: | Height: | Size: 187 B |
BIN
dist/qt_themes/qdarkstyle/rc/branch_closed-on.png
vendored
Normal file
|
After Width: | Height: | Size: 147 B |
BIN
dist/qt_themes/qdarkstyle/rc/branch_closed.png
vendored
Normal file
|
After Width: | Height: | Size: 160 B |
BIN
dist/qt_themes/qdarkstyle/rc/branch_open-on.png
vendored
Normal file
|
After Width: | Height: | Size: 150 B |
BIN
dist/qt_themes/qdarkstyle/rc/branch_open.png
vendored
Normal file
|
After Width: | Height: | Size: 166 B |
BIN
dist/qt_themes/qdarkstyle/rc/checkbox_checked.png
vendored
Normal file
|
After Width: | Height: | Size: 492 B |
BIN
dist/qt_themes/qdarkstyle/rc/checkbox_checked_disabled.png
vendored
Normal file
|
After Width: | Height: | Size: 491 B |
BIN
dist/qt_themes/qdarkstyle/rc/checkbox_checked_focus.png
vendored
Normal file
|
After Width: | Height: | Size: 252 B |
BIN
dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate.png
vendored
Normal file
|
After Width: | Height: | Size: 493 B |
BIN
dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_disabled.png
vendored
Normal file
|
After Width: | Height: | Size: 492 B |
BIN
dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_focus.png
vendored
Normal file
|
After Width: | Height: | Size: 249 B |
BIN
dist/qt_themes/qdarkstyle/rc/checkbox_unchecked.png
vendored
Normal file
|
After Width: | Height: | Size: 464 B |
BIN
dist/qt_themes/qdarkstyle/rc/checkbox_unchecked_disabled.png
vendored
Normal file
|
After Width: | Height: | Size: 464 B |
BIN
dist/qt_themes/qdarkstyle/rc/checkbox_unchecked_focus.png
vendored
Normal file
|
After Width: | Height: | Size: 240 B |
BIN
dist/qt_themes/qdarkstyle/rc/close-hover.png
vendored
Normal file
|
After Width: | Height: | Size: 598 B |
BIN
dist/qt_themes/qdarkstyle/rc/close-pressed.png
vendored
Normal file
|
After Width: | Height: | Size: 598 B |
BIN
dist/qt_themes/qdarkstyle/rc/close.png
vendored
Normal file
|
After Width: | Height: | Size: 586 B |
BIN
dist/qt_themes/qdarkstyle/rc/down_arrow.png
vendored
Normal file
|
After Width: | Height: | Size: 165 B |
BIN
dist/qt_themes/qdarkstyle/rc/down_arrow_disabled.png
vendored
Normal file
|
After Width: | Height: | Size: 166 B |
BIN
dist/qt_themes/qdarkstyle/rc/left_arrow.png
vendored
Normal file
|
After Width: | Height: | Size: 166 B |
BIN
dist/qt_themes/qdarkstyle/rc/left_arrow_disabled.png
vendored
Normal file
|
After Width: | Height: | Size: 166 B |
BIN
dist/qt_themes/qdarkstyle/rc/radio_checked.png
vendored
Normal file
|
After Width: | Height: | Size: 940 B |
BIN
dist/qt_themes/qdarkstyle/rc/radio_checked_disabled.png
vendored
Normal file
|
After Width: | Height: | Size: 972 B |
BIN
dist/qt_themes/qdarkstyle/rc/radio_checked_focus.png
vendored
Normal file
|
After Width: | Height: | Size: 846 B |
BIN
dist/qt_themes/qdarkstyle/rc/radio_unchecked.png
vendored
Normal file
|
After Width: | Height: | Size: 728 B |
BIN
dist/qt_themes/qdarkstyle/rc/radio_unchecked_disabled.png
vendored
Normal file
|
After Width: | Height: | Size: 760 B |
BIN
dist/qt_themes/qdarkstyle/rc/radio_unchecked_focus.png
vendored
Normal file
|
After Width: | Height: | Size: 646 B |
BIN
dist/qt_themes/qdarkstyle/rc/right_arrow.png
vendored
Normal file
|
After Width: | Height: | Size: 160 B |
BIN
dist/qt_themes/qdarkstyle/rc/right_arrow_disabled.png
vendored
Normal file
|
After Width: | Height: | Size: 160 B |
BIN
dist/qt_themes/qdarkstyle/rc/sizegrip.png
vendored
Normal file
|
After Width: | Height: | Size: 129 B |
BIN
dist/qt_themes/qdarkstyle/rc/stylesheet-branch-end.png
vendored
Normal file
|
After Width: | Height: | Size: 224 B |
BIN
dist/qt_themes/qdarkstyle/rc/stylesheet-branch-more.png
vendored
Normal file
|
After Width: | Height: | Size: 182 B |
BIN
dist/qt_themes/qdarkstyle/rc/stylesheet-vline.png
vendored
Normal file
|
After Width: | Height: | Size: 239 B |
BIN
dist/qt_themes/qdarkstyle/rc/transparent.png
vendored
Normal file
|
After Width: | Height: | Size: 195 B |
BIN
dist/qt_themes/qdarkstyle/rc/undock.png
vendored
Normal file
|
After Width: | Height: | Size: 578 B |
BIN
dist/qt_themes/qdarkstyle/rc/up_arrow.png
vendored
Normal file
|
After Width: | Height: | Size: 158 B |
BIN
dist/qt_themes/qdarkstyle/rc/up_arrow_disabled.png
vendored
Normal file
|
After Width: | Height: | Size: 159 B |
49
dist/qt_themes/qdarkstyle/style.qrc
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
<RCC>
|
||||
<qresource prefix="icons/qdarkstyle">
|
||||
<file alias="index.theme">icons/index.theme</file>
|
||||
</qresource>
|
||||
<qresource prefix="qss_icons">
|
||||
<file>rc/up_arrow_disabled.png</file>
|
||||
<file>rc/Hmovetoolbar.png</file>
|
||||
<file>rc/stylesheet-branch-end.png</file>
|
||||
<file>rc/branch_closed-on.png</file>
|
||||
<file>rc/stylesheet-vline.png</file>
|
||||
<file>rc/branch_closed.png</file>
|
||||
<file>rc/branch_open-on.png</file>
|
||||
<file>rc/transparent.png</file>
|
||||
<file>rc/right_arrow_disabled.png</file>
|
||||
<file>rc/sizegrip.png</file>
|
||||
<file>rc/close.png</file>
|
||||
<file>rc/close-hover.png</file>
|
||||
<file>rc/close-pressed.png</file>
|
||||
<file>rc/down_arrow.png</file>
|
||||
<file>rc/Vmovetoolbar.png</file>
|
||||
<file>rc/left_arrow.png</file>
|
||||
<file>rc/stylesheet-branch-more.png</file>
|
||||
<file>rc/up_arrow.png</file>
|
||||
<file>rc/right_arrow.png</file>
|
||||
<file>rc/left_arrow_disabled.png</file>
|
||||
<file>rc/Hsepartoolbar.png</file>
|
||||
<file>rc/branch_open.png</file>
|
||||
<file>rc/Vsepartoolbar.png</file>
|
||||
<file>rc/down_arrow_disabled.png</file>
|
||||
<file>rc/undock.png</file>
|
||||
<file>rc/checkbox_checked_disabled.png</file>
|
||||
<file>rc/checkbox_checked_focus.png</file>
|
||||
<file>rc/checkbox_checked.png</file>
|
||||
<file>rc/checkbox_indeterminate.png</file>
|
||||
<file>rc/checkbox_indeterminate_focus.png</file>
|
||||
<file>rc/checkbox_unchecked_disabled.png</file>
|
||||
<file>rc/checkbox_unchecked_focus.png</file>
|
||||
<file>rc/checkbox_unchecked.png</file>
|
||||
<file>rc/radio_checked_disabled.png</file>
|
||||
<file>rc/radio_checked_focus.png</file>
|
||||
<file>rc/radio_checked.png</file>
|
||||
<file>rc/radio_unchecked_disabled.png</file>
|
||||
<file>rc/radio_unchecked_focus.png</file>
|
||||
<file>rc/radio_unchecked.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="qdarkstyle">
|
||||
<file>style.qss</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
1268
dist/qt_themes/qdarkstyle/style.qss
vendored
Normal file
1
externals/CMakeLists.txt
vendored
@@ -17,6 +17,7 @@ endif()
|
||||
|
||||
# libfmt
|
||||
add_subdirectory(fmt)
|
||||
add_library(fmt::fmt ALIAS fmt)
|
||||
|
||||
# getopt
|
||||
if (MSVC)
|
||||
|
||||
2
externals/dynarmic
vendored
2
externals/fmt
vendored
2
externals/glad/Readme.md
vendored
@@ -1,5 +1,5 @@
|
||||
These files were generated by the [glad](https://github.com/Dav1dde/glad) OpenGL loader generator and have been checked in as-is. You can re-generate them using glad with the following command:
|
||||
|
||||
```
|
||||
python -m glad --profile core --out-path glad/ --api gl=3.3,gles=3.0
|
||||
python -m glad --profile core --out-path glad/ --api gl=3.3 --generator=c
|
||||
```
|
||||
|
||||
6
externals/glad/include/KHR/khrplatform.h
vendored
@@ -26,7 +26,7 @@
|
||||
|
||||
/* Khronos platform-specific types and definitions.
|
||||
*
|
||||
* $Revision: 23298 $ on $Date: 2013-09-30 17:07:13 -0700 (Mon, 30 Sep 2013) $
|
||||
* $Revision: 32517 $ on $Date: 2016-03-11 02:41:19 -0800 (Fri, 11 Mar 2016) $
|
||||
*
|
||||
* Adopters may modify this file to suit their platform. Adopters are
|
||||
* encouraged to submit platform specific modifications to the Khronos
|
||||
@@ -101,6 +101,8 @@
|
||||
# define KHRONOS_APICALL __declspec(dllimport)
|
||||
#elif defined (__SYMBIAN32__)
|
||||
# define KHRONOS_APICALL IMPORT_C
|
||||
#elif defined(__ANDROID__)
|
||||
# define KHRONOS_APICALL __attribute__((visibility("default")))
|
||||
#else
|
||||
# define KHRONOS_APICALL
|
||||
#endif
|
||||
@@ -223,7 +225,7 @@ typedef signed short int khronos_int16_t;
|
||||
typedef unsigned short int khronos_uint16_t;
|
||||
|
||||
/*
|
||||
* Types that differ between LLP64 and LP64 architectures - in LLP64,
|
||||
* Types that differ between LLP64 and LP64 architectures - in LLP64,
|
||||
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
|
||||
* to be the only LLP64 architecture in current use.
|
||||
*/
|
||||
|
||||
13755
externals/glad/include/glad/glad.h
vendored
8704
externals/glad/src/glad.c
vendored
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Enforce citra's whitespace policy
|
||||
# Enforce yuzu's whitespace policy
|
||||
git config --local core.whitespace tab-in-indent,trailing-space
|
||||
|
||||
paths_to_check="src/ CMakeLists.txt"
|
||||
|
||||
@@ -31,17 +31,15 @@ add_library(common STATIC
|
||||
bit_set.h
|
||||
break_points.cpp
|
||||
break_points.h
|
||||
chunk_file.h
|
||||
code_block.h
|
||||
cityhash.cpp
|
||||
cityhash.h
|
||||
color.h
|
||||
common_funcs.h
|
||||
common_paths.h
|
||||
common_types.h
|
||||
file_util.cpp
|
||||
file_util.h
|
||||
hash.cpp
|
||||
hash.h
|
||||
linear_disk_cache.h
|
||||
logging/backend.cpp
|
||||
logging/backend.h
|
||||
logging/filter.cpp
|
||||
@@ -58,7 +56,6 @@ add_library(common STATIC
|
||||
misc.cpp
|
||||
param_package.cpp
|
||||
param_package.h
|
||||
platform.h
|
||||
quaternion.h
|
||||
scm_rev.cpp
|
||||
scm_rev.h
|
||||
@@ -90,7 +87,7 @@ endif()
|
||||
|
||||
create_target_directory_groups(common)
|
||||
|
||||
target_link_libraries(common PUBLIC Boost::boost microprofile)
|
||||
target_link_libraries(common PUBLIC Boost::boost fmt microprofile)
|
||||
if (ARCHITECTURE_x86_64)
|
||||
target_link_libraries(common PRIVATE xbyak)
|
||||
endif()
|
||||
|
||||
@@ -30,14 +30,15 @@ __declspec(noinline, noreturn)
|
||||
#define ASSERT(_a_) \
|
||||
do \
|
||||
if (!(_a_)) { \
|
||||
assert_noinline_call([] { LOG_CRITICAL(Debug, "Assertion Failed!"); }); \
|
||||
assert_noinline_call([] { NGLOG_CRITICAL(Debug, "Assertion Failed!"); }); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define ASSERT_MSG(_a_, ...) \
|
||||
do \
|
||||
if (!(_a_)) { \
|
||||
assert_noinline_call([&] { LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \
|
||||
assert_noinline_call( \
|
||||
[&] { NGLOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ private:
|
||||
// assignment would copy the full storage value, rather than just the bits
|
||||
// relevant to this particular bit field.
|
||||
// We don't delete it because we want BitField to be trivially copyable.
|
||||
BitField& operator=(const BitField&) = default;
|
||||
constexpr BitField& operator=(const BitField&) = default;
|
||||
|
||||
// StorageType is T for non-enum types and the underlying type of T if
|
||||
// T is an enumeration. Note that T is wrapped within an enable_if in the
|
||||
@@ -166,20 +166,20 @@ public:
|
||||
// so that we can use this within unions
|
||||
constexpr BitField() = default;
|
||||
|
||||
FORCE_INLINE operator T() const {
|
||||
constexpr FORCE_INLINE operator T() const {
|
||||
return Value();
|
||||
}
|
||||
|
||||
FORCE_INLINE void Assign(const T& value) {
|
||||
constexpr FORCE_INLINE void Assign(const T& value) {
|
||||
storage = (storage & ~mask) | FormatValue(value);
|
||||
}
|
||||
|
||||
FORCE_INLINE T Value() const {
|
||||
constexpr T Value() const {
|
||||
return ExtractValue(storage);
|
||||
}
|
||||
|
||||
// TODO: we may want to change this to explicit operator bool() if it's bug-free in VS2015
|
||||
FORCE_INLINE bool ToBool() const {
|
||||
constexpr FORCE_INLINE bool ToBool() const {
|
||||
return Value() != 0;
|
||||
}
|
||||
|
||||
@@ -192,11 +192,6 @@ private:
|
||||
static_assert(position < 8 * sizeof(T), "Invalid position");
|
||||
static_assert(bits <= 8 * sizeof(T), "Invalid number of bits");
|
||||
static_assert(bits > 0, "Invalid number of bits");
|
||||
static_assert(std::is_pod<T>::value, "Invalid base type");
|
||||
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable in a BitField");
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
|
||||
static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value,
|
||||
"BitField must be trivially copyable");
|
||||
#endif
|
||||
|
||||
@@ -1,623 +0,0 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Extremely simple serialization framework.
|
||||
|
||||
// (mis)-features:
|
||||
// + Super fast
|
||||
// + Very simple
|
||||
// + Same code is used for serialization and deserializaition (in most cases)
|
||||
// - Zero backwards/forwards compatibility
|
||||
// - Serialization code for anything complex has to be manually written.
|
||||
|
||||
#include <cstring>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
template <class T>
|
||||
struct LinkedListItem : public T {
|
||||
LinkedListItem<T>* next;
|
||||
};
|
||||
|
||||
class PointerWrap;
|
||||
|
||||
class PointerWrapSection {
|
||||
public:
|
||||
PointerWrapSection(PointerWrap& p, int ver, const char* title)
|
||||
: p_(p), ver_(ver), title_(title) {}
|
||||
~PointerWrapSection();
|
||||
|
||||
bool operator==(const int& v) const {
|
||||
return ver_ == v;
|
||||
}
|
||||
bool operator!=(const int& v) const {
|
||||
return ver_ != v;
|
||||
}
|
||||
bool operator<=(const int& v) const {
|
||||
return ver_ <= v;
|
||||
}
|
||||
bool operator>=(const int& v) const {
|
||||
return ver_ >= v;
|
||||
}
|
||||
bool operator<(const int& v) const {
|
||||
return ver_ < v;
|
||||
}
|
||||
bool operator>(const int& v) const {
|
||||
return ver_ > v;
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return ver_ > 0;
|
||||
}
|
||||
|
||||
private:
|
||||
PointerWrap& p_;
|
||||
int ver_;
|
||||
const char* title_;
|
||||
};
|
||||
|
||||
// Wrapper class
|
||||
class PointerWrap {
|
||||
// This makes it a compile error if you forget to define DoState() on non-POD.
|
||||
// Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason...
|
||||
#ifdef _MSC_VER
|
||||
template <typename T, bool isPOD = std::is_pod<T>::value,
|
||||
bool isPointer = std::is_pointer<T>::value>
|
||||
#else
|
||||
template <typename T, bool isPOD = __is_pod(T), bool isPointer = std::is_pointer<T>::value>
|
||||
#endif
|
||||
struct DoHelper {
|
||||
static void DoArray(PointerWrap* p, T* x, int count) {
|
||||
for (int i = 0; i < count; ++i)
|
||||
p->Do(x[i]);
|
||||
}
|
||||
|
||||
static void Do(PointerWrap* p, T& x) {
|
||||
p->DoClass(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct DoHelper<T, true, false> {
|
||||
static void DoArray(PointerWrap* p, T* x, int count) {
|
||||
p->DoVoid((void*)x, sizeof(T) * count);
|
||||
}
|
||||
|
||||
static void Do(PointerWrap* p, T& x) {
|
||||
p->DoVoid((void*)&x, sizeof(x));
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
enum Mode {
|
||||
MODE_READ = 1, // load
|
||||
MODE_WRITE, // save
|
||||
MODE_MEASURE, // calculate size
|
||||
MODE_VERIFY, // compare
|
||||
};
|
||||
|
||||
enum Error {
|
||||
ERROR_NONE = 0,
|
||||
ERROR_WARNING = 1,
|
||||
ERROR_FAILURE = 2,
|
||||
};
|
||||
|
||||
u8** ptr;
|
||||
Mode mode;
|
||||
Error error;
|
||||
|
||||
public:
|
||||
PointerWrap(u8** ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {}
|
||||
PointerWrap(unsigned char** ptr_, int mode_)
|
||||
: ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {}
|
||||
|
||||
PointerWrapSection Section(const char* title, int ver) {
|
||||
return Section(title, ver, ver);
|
||||
}
|
||||
|
||||
// The returned object can be compared against the version that was loaded.
|
||||
// This can be used to support versions as old as minVer.
|
||||
// Version = 0 means the section was not found.
|
||||
PointerWrapSection Section(const char* title, int minVer, int ver) {
|
||||
char marker[16] = {0};
|
||||
int foundVersion = ver;
|
||||
|
||||
strncpy(marker, title, sizeof(marker));
|
||||
if (!ExpectVoid(marker, sizeof(marker))) {
|
||||
// Might be before we added name markers for safety.
|
||||
if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion)))
|
||||
DoMarker(title);
|
||||
// Wasn't found, but maybe we can still load the state.
|
||||
else
|
||||
foundVersion = 0;
|
||||
} else
|
||||
Do(foundVersion);
|
||||
|
||||
if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) {
|
||||
LOG_ERROR(Common, "Savestate failure: wrong version %d found for %s", foundVersion,
|
||||
title);
|
||||
SetError(ERROR_FAILURE);
|
||||
return PointerWrapSection(*this, -1, title);
|
||||
}
|
||||
return PointerWrapSection(*this, foundVersion, title);
|
||||
}
|
||||
|
||||
void SetMode(Mode mode_) {
|
||||
mode = mode_;
|
||||
}
|
||||
Mode GetMode() const {
|
||||
return mode;
|
||||
}
|
||||
u8** GetPPtr() {
|
||||
return ptr;
|
||||
}
|
||||
void SetError(Error error_) {
|
||||
if (error < error_)
|
||||
error = error_;
|
||||
if (error > ERROR_WARNING)
|
||||
mode = PointerWrap::MODE_MEASURE;
|
||||
}
|
||||
|
||||
bool ExpectVoid(void* data, int size) {
|
||||
switch (mode) {
|
||||
case MODE_READ:
|
||||
if (memcmp(data, *ptr, size) != 0)
|
||||
return false;
|
||||
break;
|
||||
case MODE_WRITE:
|
||||
memcpy(*ptr, data, size);
|
||||
break;
|
||||
case MODE_MEASURE:
|
||||
break; // MODE_MEASURE - don't need to do anything
|
||||
case MODE_VERIFY:
|
||||
for (int i = 0; i < size; i++) {
|
||||
DEBUG_ASSERT_MSG(
|
||||
((u8*)data)[i] == (*ptr)[i],
|
||||
"Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n",
|
||||
((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i],
|
||||
&(*ptr)[i]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break; // throw an error?
|
||||
}
|
||||
(*ptr) += size;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DoVoid(void* data, int size) {
|
||||
switch (mode) {
|
||||
case MODE_READ:
|
||||
memcpy(data, *ptr, size);
|
||||
break;
|
||||
case MODE_WRITE:
|
||||
memcpy(*ptr, data, size);
|
||||
break;
|
||||
case MODE_MEASURE:
|
||||
break; // MODE_MEASURE - don't need to do anything
|
||||
case MODE_VERIFY:
|
||||
for (int i = 0; i < size; i++) {
|
||||
DEBUG_ASSERT_MSG(
|
||||
((u8*)data)[i] == (*ptr)[i],
|
||||
"Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n",
|
||||
((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i],
|
||||
&(*ptr)[i]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break; // throw an error?
|
||||
}
|
||||
(*ptr) += size;
|
||||
}
|
||||
|
||||
template <class K, class T>
|
||||
void Do(std::map<K, T*>& x) {
|
||||
if (mode == MODE_READ) {
|
||||
for (auto it = x.begin(), end = x.end(); it != end; ++it) {
|
||||
if (it->second != nullptr)
|
||||
delete it->second;
|
||||
}
|
||||
}
|
||||
T* dv = nullptr;
|
||||
DoMap(x, dv);
|
||||
}
|
||||
|
||||
template <class K, class T>
|
||||
void Do(std::map<K, T>& x) {
|
||||
T dv = T();
|
||||
DoMap(x, dv);
|
||||
}
|
||||
|
||||
template <class K, class T>
|
||||
void DoMap(std::map<K, T>& x, T& default_val) {
|
||||
unsigned int number = (unsigned int)x.size();
|
||||
Do(number);
|
||||
switch (mode) {
|
||||
case MODE_READ: {
|
||||
x.clear();
|
||||
while (number > 0) {
|
||||
K first = K();
|
||||
Do(first);
|
||||
T second = default_val;
|
||||
Do(second);
|
||||
x[first] = second;
|
||||
--number;
|
||||
}
|
||||
} break;
|
||||
case MODE_WRITE:
|
||||
case MODE_MEASURE:
|
||||
case MODE_VERIFY: {
|
||||
typename std::map<K, T>::iterator itr = x.begin();
|
||||
while (number > 0) {
|
||||
K first = itr->first;
|
||||
Do(first);
|
||||
Do(itr->second);
|
||||
--number;
|
||||
++itr;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
template <class K, class T>
|
||||
void Do(std::multimap<K, T*>& x) {
|
||||
if (mode == MODE_READ) {
|
||||
for (auto it = x.begin(), end = x.end(); it != end; ++it) {
|
||||
if (it->second != nullptr)
|
||||
delete it->second;
|
||||
}
|
||||
}
|
||||
T* dv = nullptr;
|
||||
DoMultimap(x, dv);
|
||||
}
|
||||
|
||||
template <class K, class T>
|
||||
void Do(std::multimap<K, T>& x) {
|
||||
T dv = T();
|
||||
DoMultimap(x, dv);
|
||||
}
|
||||
|
||||
template <class K, class T>
|
||||
void DoMultimap(std::multimap<K, T>& x, T& default_val) {
|
||||
unsigned int number = (unsigned int)x.size();
|
||||
Do(number);
|
||||
switch (mode) {
|
||||
case MODE_READ: {
|
||||
x.clear();
|
||||
while (number > 0) {
|
||||
K first = K();
|
||||
Do(first);
|
||||
T second = default_val;
|
||||
Do(second);
|
||||
x.insert(std::make_pair(first, second));
|
||||
--number;
|
||||
}
|
||||
} break;
|
||||
case MODE_WRITE:
|
||||
case MODE_MEASURE:
|
||||
case MODE_VERIFY: {
|
||||
typename std::multimap<K, T>::iterator itr = x.begin();
|
||||
while (number > 0) {
|
||||
Do(itr->first);
|
||||
Do(itr->second);
|
||||
--number;
|
||||
++itr;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
// Store vectors.
|
||||
template <class T>
|
||||
void Do(std::vector<T*>& x) {
|
||||
T* dv = nullptr;
|
||||
DoVector(x, dv);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Do(std::vector<T>& x) {
|
||||
T dv = T();
|
||||
DoVector(x, dv);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void DoPOD(std::vector<T>& x) {
|
||||
T dv = T();
|
||||
DoVectorPOD(x, dv);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Do(std::vector<T>& x, T& default_val) {
|
||||
DoVector(x, default_val);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void DoVector(std::vector<T>& x, T& default_val) {
|
||||
u32 vec_size = (u32)x.size();
|
||||
Do(vec_size);
|
||||
x.resize(vec_size, default_val);
|
||||
if (vec_size > 0)
|
||||
DoArray(&x[0], vec_size);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void DoVectorPOD(std::vector<T>& x, T& default_val) {
|
||||
u32 vec_size = (u32)x.size();
|
||||
Do(vec_size);
|
||||
x.resize(vec_size, default_val);
|
||||
if (vec_size > 0)
|
||||
DoArray(&x[0], vec_size);
|
||||
}
|
||||
|
||||
// Store deques.
|
||||
template <class T>
|
||||
void Do(std::deque<T*>& x) {
|
||||
T* dv = nullptr;
|
||||
DoDeque(x, dv);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Do(std::deque<T>& x) {
|
||||
T dv = T();
|
||||
DoDeque(x, dv);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void DoDeque(std::deque<T>& x, T& default_val) {
|
||||
u32 deq_size = (u32)x.size();
|
||||
Do(deq_size);
|
||||
x.resize(deq_size, default_val);
|
||||
u32 i;
|
||||
for (i = 0; i < deq_size; i++)
|
||||
Do(x[i]);
|
||||
}
|
||||
|
||||
// Store STL lists.
|
||||
template <class T>
|
||||
void Do(std::list<T*>& x) {
|
||||
T* dv = nullptr;
|
||||
Do(x, dv);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Do(std::list<T>& x) {
|
||||
T dv = T();
|
||||
DoList(x, dv);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Do(std::list<T>& x, T& default_val) {
|
||||
DoList(x, default_val);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void DoList(std::list<T>& x, T& default_val) {
|
||||
u32 list_size = (u32)x.size();
|
||||
Do(list_size);
|
||||
x.resize(list_size, default_val);
|
||||
|
||||
typename std::list<T>::iterator itr, end;
|
||||
for (itr = x.begin(), end = x.end(); itr != end; ++itr)
|
||||
Do(*itr);
|
||||
}
|
||||
|
||||
// Store STL sets.
|
||||
template <class T>
|
||||
void Do(std::set<T*>& x) {
|
||||
if (mode == MODE_READ) {
|
||||
for (auto it = x.begin(), end = x.end(); it != end; ++it) {
|
||||
if (*it != nullptr)
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
DoSet(x);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Do(std::set<T>& x) {
|
||||
DoSet(x);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void DoSet(std::set<T>& x) {
|
||||
unsigned int number = (unsigned int)x.size();
|
||||
Do(number);
|
||||
|
||||
switch (mode) {
|
||||
case MODE_READ: {
|
||||
x.clear();
|
||||
while (number-- > 0) {
|
||||
T it = T();
|
||||
Do(it);
|
||||
x.insert(it);
|
||||
}
|
||||
} break;
|
||||
case MODE_WRITE:
|
||||
case MODE_MEASURE:
|
||||
case MODE_VERIFY: {
|
||||
typename std::set<T>::iterator itr = x.begin();
|
||||
while (number-- > 0)
|
||||
Do(*itr++);
|
||||
} break;
|
||||
|
||||
default:
|
||||
LOG_ERROR(Common, "Savestate error: invalid mode %d.", mode);
|
||||
}
|
||||
}
|
||||
|
||||
// Store strings.
|
||||
void Do(std::string& x) {
|
||||
int stringLen = (int)x.length() + 1;
|
||||
Do(stringLen);
|
||||
|
||||
switch (mode) {
|
||||
case MODE_READ:
|
||||
x = (char*)*ptr;
|
||||
break;
|
||||
case MODE_WRITE:
|
||||
memcpy(*ptr, x.c_str(), stringLen);
|
||||
break;
|
||||
case MODE_MEASURE:
|
||||
break;
|
||||
case MODE_VERIFY:
|
||||
DEBUG_ASSERT_MSG((x == (char*)*ptr),
|
||||
"Savestate verification failure: \"%s\" != \"%s\" (at %p).\n",
|
||||
x.c_str(), (char*)*ptr, ptr);
|
||||
break;
|
||||
}
|
||||
(*ptr) += stringLen;
|
||||
}
|
||||
|
||||
void Do(std::wstring& x) {
|
||||
int stringLen = sizeof(wchar_t) * ((int)x.length() + 1);
|
||||
Do(stringLen);
|
||||
|
||||
switch (mode) {
|
||||
case MODE_READ:
|
||||
x = (wchar_t*)*ptr;
|
||||
break;
|
||||
case MODE_WRITE:
|
||||
memcpy(*ptr, x.c_str(), stringLen);
|
||||
break;
|
||||
case MODE_MEASURE:
|
||||
break;
|
||||
case MODE_VERIFY:
|
||||
DEBUG_ASSERT_MSG((x == (wchar_t*)*ptr),
|
||||
"Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n",
|
||||
x.c_str(), (wchar_t*)*ptr, ptr);
|
||||
break;
|
||||
}
|
||||
(*ptr) += stringLen;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void DoClass(T& x) {
|
||||
x.DoState(*this);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void DoClass(T*& x) {
|
||||
if (mode == MODE_READ) {
|
||||
if (x != nullptr)
|
||||
delete x;
|
||||
x = new T();
|
||||
}
|
||||
x->DoState(*this);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void DoArray(T* x, int count) {
|
||||
DoHelper<T>::DoArray(this, x, count);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Do(T& x) {
|
||||
DoHelper<T>::Do(this, x);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void DoPOD(T& x) {
|
||||
DoHelper<T>::Do(this, x);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void DoPointer(T*& x, T* const base) {
|
||||
// pointers can be more than 2^31 apart, but you're using this function wrong if you need
|
||||
// that much range
|
||||
s32 offset = x - base;
|
||||
Do(offset);
|
||||
if (mode == MODE_READ)
|
||||
x = base + offset;
|
||||
}
|
||||
|
||||
template <class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*),
|
||||
void (*TDo)(PointerWrap&, T*)>
|
||||
void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end = nullptr) {
|
||||
LinkedListItem<T>* list_cur = list_start;
|
||||
LinkedListItem<T>* prev = nullptr;
|
||||
|
||||
while (true) {
|
||||
u8 shouldExist = (list_cur ? 1 : 0);
|
||||
Do(shouldExist);
|
||||
if (shouldExist == 1) {
|
||||
LinkedListItem<T>* cur = list_cur ? list_cur : TNew();
|
||||
TDo(*this, (T*)cur);
|
||||
if (!list_cur) {
|
||||
if (mode == MODE_READ) {
|
||||
cur->next = nullptr;
|
||||
list_cur = cur;
|
||||
if (prev)
|
||||
prev->next = cur;
|
||||
else
|
||||
list_start = cur;
|
||||
} else {
|
||||
TFree(cur);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (mode == MODE_READ) {
|
||||
if (prev)
|
||||
prev->next = nullptr;
|
||||
if (list_end)
|
||||
*list_end = prev;
|
||||
if (list_cur) {
|
||||
if (list_start == list_cur)
|
||||
list_start = nullptr;
|
||||
do {
|
||||
LinkedListItem<T>* next = list_cur->next;
|
||||
TFree(list_cur);
|
||||
list_cur = next;
|
||||
} while (list_cur);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev = list_cur;
|
||||
list_cur = list_cur->next;
|
||||
}
|
||||
}
|
||||
|
||||
void DoMarker(const char* prevName, u32 arbitraryNumber = 0x42) {
|
||||
u32 cookie = arbitraryNumber;
|
||||
Do(cookie);
|
||||
if (mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) {
|
||||
LOG_ERROR(Common,
|
||||
"After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). "
|
||||
"Aborting savestate load...",
|
||||
prevName, cookie, cookie, arbitraryNumber, arbitraryNumber);
|
||||
SetError(ERROR_FAILURE);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline PointerWrapSection::~PointerWrapSection() {
|
||||
if (ver_ > 0) {
|
||||
p_.DoMarker(title_);
|
||||
}
|
||||
}
|
||||
340
src/common/cityhash.cpp
Normal file
@@ -0,0 +1,340 @@
|
||||
// Copyright (c) 2011 Google, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// CityHash, by Geoff Pike and Jyrki Alakuijala
|
||||
//
|
||||
// This file provides CityHash64() and related functions.
|
||||
//
|
||||
// It's probably possible to create even faster hash functions by
|
||||
// writing a program that systematically explores some of the space of
|
||||
// possible hash functions, by using SIMD instructions, or by
|
||||
// compromising on hash quality.
|
||||
|
||||
#include <algorithm>
|
||||
#include <string.h> // for memcpy and memset
|
||||
#include "cityhash.h"
|
||||
#include "common/swap.h"
|
||||
|
||||
// #include "config.h"
|
||||
#ifdef __GNUC__
|
||||
#define HAVE_BUILTIN_EXPECT 1
|
||||
#endif
|
||||
#ifdef COMMON_BIG_ENDIAN
|
||||
#define WORDS_BIGENDIAN 1
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef uint8_t uint8;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
namespace Common {
|
||||
|
||||
static uint64 UNALIGNED_LOAD64(const char* p) {
|
||||
uint64 result;
|
||||
memcpy(&result, p, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint32 UNALIGNED_LOAD32(const char* p) {
|
||||
uint32 result;
|
||||
memcpy(&result, p, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define uint32_in_expected_order(x) (swap32(x))
|
||||
#define uint64_in_expected_order(x) (swap64(x))
|
||||
#else
|
||||
#define uint32_in_expected_order(x) (x)
|
||||
#define uint64_in_expected_order(x) (x)
|
||||
#endif
|
||||
|
||||
#if !defined(LIKELY)
|
||||
#if HAVE_BUILTIN_EXPECT
|
||||
#define LIKELY(x) (__builtin_expect(!!(x), 1))
|
||||
#else
|
||||
#define LIKELY(x) (x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static uint64 Fetch64(const char* p) {
|
||||
return uint64_in_expected_order(UNALIGNED_LOAD64(p));
|
||||
}
|
||||
|
||||
static uint32 Fetch32(const char* p) {
|
||||
return uint32_in_expected_order(UNALIGNED_LOAD32(p));
|
||||
}
|
||||
|
||||
// Some primes between 2^63 and 2^64 for various uses.
|
||||
static const uint64 k0 = 0xc3a5c85c97cb3127ULL;
|
||||
static const uint64 k1 = 0xb492b66fbe98f273ULL;
|
||||
static const uint64 k2 = 0x9ae16a3b2f90404fULL;
|
||||
|
||||
// Bitwise right rotate. Normally this will compile to a single
|
||||
// instruction, especially if the shift is a manifest constant.
|
||||
static uint64 Rotate(uint64 val, int shift) {
|
||||
// Avoid shifting by 64: doing so yields an undefined result.
|
||||
return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
|
||||
}
|
||||
|
||||
static uint64 ShiftMix(uint64 val) {
|
||||
return val ^ (val >> 47);
|
||||
}
|
||||
|
||||
static uint64 HashLen16(uint64 u, uint64 v) {
|
||||
return Hash128to64(uint128(u, v));
|
||||
}
|
||||
|
||||
static uint64 HashLen16(uint64 u, uint64 v, uint64 mul) {
|
||||
// Murmur-inspired hashing.
|
||||
uint64 a = (u ^ v) * mul;
|
||||
a ^= (a >> 47);
|
||||
uint64 b = (v ^ a) * mul;
|
||||
b ^= (b >> 47);
|
||||
b *= mul;
|
||||
return b;
|
||||
}
|
||||
|
||||
static uint64 HashLen0to16(const char* s, size_t len) {
|
||||
if (len >= 8) {
|
||||
uint64 mul = k2 + len * 2;
|
||||
uint64 a = Fetch64(s) + k2;
|
||||
uint64 b = Fetch64(s + len - 8);
|
||||
uint64 c = Rotate(b, 37) * mul + a;
|
||||
uint64 d = (Rotate(a, 25) + b) * mul;
|
||||
return HashLen16(c, d, mul);
|
||||
}
|
||||
if (len >= 4) {
|
||||
uint64 mul = k2 + len * 2;
|
||||
uint64 a = Fetch32(s);
|
||||
return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul);
|
||||
}
|
||||
if (len > 0) {
|
||||
uint8 a = s[0];
|
||||
uint8 b = s[len >> 1];
|
||||
uint8 c = s[len - 1];
|
||||
uint32 y = static_cast<uint32>(a) + (static_cast<uint32>(b) << 8);
|
||||
uint32 z = static_cast<uint32>(len) + (static_cast<uint32>(c) << 2);
|
||||
return ShiftMix(y * k2 ^ z * k0) * k2;
|
||||
}
|
||||
return k2;
|
||||
}
|
||||
|
||||
// This probably works well for 16-byte strings as well, but it may be overkill
|
||||
// in that case.
|
||||
static uint64 HashLen17to32(const char* s, size_t len) {
|
||||
uint64 mul = k2 + len * 2;
|
||||
uint64 a = Fetch64(s) * k1;
|
||||
uint64 b = Fetch64(s + 8);
|
||||
uint64 c = Fetch64(s + len - 8) * mul;
|
||||
uint64 d = Fetch64(s + len - 16) * k2;
|
||||
return HashLen16(Rotate(a + b, 43) + Rotate(c, 30) + d, a + Rotate(b + k2, 18) + c, mul);
|
||||
}
|
||||
|
||||
// Return a 16-byte hash for 48 bytes. Quick and dirty.
|
||||
// Callers do best to use "random-looking" values for a and b.
|
||||
static pair<uint64, uint64> WeakHashLen32WithSeeds(uint64 w, uint64 x, uint64 y, uint64 z, uint64 a,
|
||||
uint64 b) {
|
||||
a += w;
|
||||
b = Rotate(b + a + z, 21);
|
||||
uint64 c = a;
|
||||
a += x;
|
||||
a += y;
|
||||
b += Rotate(a, 44);
|
||||
return make_pair(a + z, b + c);
|
||||
}
|
||||
|
||||
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
|
||||
static pair<uint64, uint64> WeakHashLen32WithSeeds(const char* s, uint64 a, uint64 b) {
|
||||
return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), Fetch64(s + 24), a,
|
||||
b);
|
||||
}
|
||||
|
||||
// Return an 8-byte hash for 33 to 64 bytes.
|
||||
static uint64 HashLen33to64(const char* s, size_t len) {
|
||||
uint64 mul = k2 + len * 2;
|
||||
uint64 a = Fetch64(s) * k2;
|
||||
uint64 b = Fetch64(s + 8);
|
||||
uint64 c = Fetch64(s + len - 24);
|
||||
uint64 d = Fetch64(s + len - 32);
|
||||
uint64 e = Fetch64(s + 16) * k2;
|
||||
uint64 f = Fetch64(s + 24) * 9;
|
||||
uint64 g = Fetch64(s + len - 8);
|
||||
uint64 h = Fetch64(s + len - 16) * mul;
|
||||
uint64 u = Rotate(a + g, 43) + (Rotate(b, 30) + c) * 9;
|
||||
uint64 v = ((a + g) ^ d) + f + 1;
|
||||
uint64 w = swap64((u + v) * mul) + h;
|
||||
uint64 x = Rotate(e + f, 42) + c;
|
||||
uint64 y = (swap64((v + w) * mul) + g) * mul;
|
||||
uint64 z = e + f + c;
|
||||
a = swap64((x + z) * mul + y) + b;
|
||||
b = ShiftMix((z + a) * mul + d + h) * mul;
|
||||
return b + x;
|
||||
}
|
||||
|
||||
uint64 CityHash64(const char* s, size_t len) {
|
||||
if (len <= 32) {
|
||||
if (len <= 16) {
|
||||
return HashLen0to16(s, len);
|
||||
} else {
|
||||
return HashLen17to32(s, len);
|
||||
}
|
||||
} else if (len <= 64) {
|
||||
return HashLen33to64(s, len);
|
||||
}
|
||||
|
||||
// For strings over 64 bytes we hash the end first, and then as we
|
||||
// loop we keep 56 bytes of state: v, w, x, y, and z.
|
||||
uint64 x = Fetch64(s + len - 40);
|
||||
uint64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
|
||||
uint64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
|
||||
pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
|
||||
pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
|
||||
x = x * k1 + Fetch64(s);
|
||||
|
||||
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
|
||||
len = (len - 1) & ~static_cast<size_t>(63);
|
||||
do {
|
||||
x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
|
||||
y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
|
||||
x ^= w.second;
|
||||
y += v.first + Fetch64(s + 40);
|
||||
z = Rotate(z + w.first, 33) * k1;
|
||||
v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
|
||||
w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
|
||||
std::swap(z, x);
|
||||
s += 64;
|
||||
len -= 64;
|
||||
} while (len != 0);
|
||||
return HashLen16(HashLen16(v.first, w.first) + ShiftMix(y) * k1 + z,
|
||||
HashLen16(v.second, w.second) + x);
|
||||
}
|
||||
|
||||
uint64 CityHash64WithSeed(const char* s, size_t len, uint64 seed) {
|
||||
return CityHash64WithSeeds(s, len, k2, seed);
|
||||
}
|
||||
|
||||
uint64 CityHash64WithSeeds(const char* s, size_t len, uint64 seed0, uint64 seed1) {
|
||||
return HashLen16(CityHash64(s, len) - seed0, seed1);
|
||||
}
|
||||
|
||||
// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings
|
||||
// of any length representable in signed long. Based on City and Murmur.
|
||||
static uint128 CityMurmur(const char* s, size_t len, uint128 seed) {
|
||||
uint64 a = Uint128Low64(seed);
|
||||
uint64 b = Uint128High64(seed);
|
||||
uint64 c = 0;
|
||||
uint64 d = 0;
|
||||
signed long l = static_cast<long>(len) - 16;
|
||||
if (l <= 0) { // len <= 16
|
||||
a = ShiftMix(a * k1) * k1;
|
||||
c = b * k1 + HashLen0to16(s, len);
|
||||
d = ShiftMix(a + (len >= 8 ? Fetch64(s) : c));
|
||||
} else { // len > 16
|
||||
c = HashLen16(Fetch64(s + len - 8) + k1, a);
|
||||
d = HashLen16(b + len, c + Fetch64(s + len - 16));
|
||||
a += d;
|
||||
do {
|
||||
a ^= ShiftMix(Fetch64(s) * k1) * k1;
|
||||
a *= k1;
|
||||
b ^= a;
|
||||
c ^= ShiftMix(Fetch64(s + 8) * k1) * k1;
|
||||
c *= k1;
|
||||
d ^= c;
|
||||
s += 16;
|
||||
l -= 16;
|
||||
} while (l > 0);
|
||||
}
|
||||
a = HashLen16(a, c);
|
||||
b = HashLen16(d, b);
|
||||
return uint128(a ^ b, HashLen16(b, a));
|
||||
}
|
||||
|
||||
uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed) {
|
||||
if (len < 128) {
|
||||
return CityMurmur(s, len, seed);
|
||||
}
|
||||
|
||||
// We expect len >= 128 to be the common case. Keep 56 bytes of state:
|
||||
// v, w, x, y, and z.
|
||||
pair<uint64, uint64> v, w;
|
||||
uint64 x = Uint128Low64(seed);
|
||||
uint64 y = Uint128High64(seed);
|
||||
uint64 z = len * k1;
|
||||
v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s);
|
||||
v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8);
|
||||
w.first = Rotate(y + z, 35) * k1 + x;
|
||||
w.second = Rotate(x + Fetch64(s + 88), 53) * k1;
|
||||
|
||||
// This is the same inner loop as CityHash64(), manually unrolled.
|
||||
do {
|
||||
x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
|
||||
y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
|
||||
x ^= w.second;
|
||||
y += v.first + Fetch64(s + 40);
|
||||
z = Rotate(z + w.first, 33) * k1;
|
||||
v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
|
||||
w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
|
||||
std::swap(z, x);
|
||||
s += 64;
|
||||
x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
|
||||
y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
|
||||
x ^= w.second;
|
||||
y += v.first + Fetch64(s + 40);
|
||||
z = Rotate(z + w.first, 33) * k1;
|
||||
v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
|
||||
w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
|
||||
std::swap(z, x);
|
||||
s += 64;
|
||||
len -= 128;
|
||||
} while (LIKELY(len >= 128));
|
||||
x += Rotate(v.first + z, 49) * k0;
|
||||
y = y * k0 + Rotate(w.second, 37);
|
||||
z = z * k0 + Rotate(w.first, 27);
|
||||
w.first *= 9;
|
||||
v.first *= k0;
|
||||
// If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
|
||||
for (size_t tail_done = 0; tail_done < len;) {
|
||||
tail_done += 32;
|
||||
y = Rotate(x + y, 42) * k0 + v.second;
|
||||
w.first += Fetch64(s + len - tail_done + 16);
|
||||
x = x * k0 + w.first;
|
||||
z += w.second + Fetch64(s + len - tail_done);
|
||||
w.second += v.first;
|
||||
v = WeakHashLen32WithSeeds(s + len - tail_done, v.first + z, v.second);
|
||||
v.first *= k0;
|
||||
}
|
||||
// At this point our 56 bytes of state should contain more than
|
||||
// enough information for a strong 128-bit hash. We use two
|
||||
// different 56-byte-to-8-byte hashes to get a 16-byte final result.
|
||||
x = HashLen16(x, v.first);
|
||||
y = HashLen16(y + z, w.first);
|
||||
return uint128(HashLen16(x + v.second, w.second) + y, HashLen16(x + w.second, y + v.second));
|
||||
}
|
||||
|
||||
uint128 CityHash128(const char* s, size_t len) {
|
||||
return len >= 16
|
||||
? CityHash128WithSeed(s + 16, len - 16, uint128(Fetch64(s), Fetch64(s + 8) + k0))
|
||||
: CityHash128WithSeed(s, len, uint128(k0, k1));
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
110
src/common/cityhash.h
Normal file
@@ -0,0 +1,110 @@
|
||||
// Copyright (c) 2011 Google, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// CityHash, by Geoff Pike and Jyrki Alakuijala
|
||||
//
|
||||
// http://code.google.com/p/cityhash/
|
||||
//
|
||||
// This file provides a few functions for hashing strings. All of them are
|
||||
// high-quality functions in the sense that they pass standard tests such
|
||||
// as Austin Appleby's SMHasher. They are also fast.
|
||||
//
|
||||
// For 64-bit x86 code, on short strings, we don't know of anything faster than
|
||||
// CityHash64 that is of comparable quality. We believe our nearest competitor
|
||||
// is Murmur3. For 64-bit x86 code, CityHash64 is an excellent choice for hash
|
||||
// tables and most other hashing (excluding cryptography).
|
||||
//
|
||||
// For 64-bit x86 code, on long strings, the picture is more complicated.
|
||||
// On many recent Intel CPUs, such as Nehalem, Westmere, Sandy Bridge, etc.,
|
||||
// CityHashCrc128 appears to be faster than all competitors of comparable
|
||||
// quality. CityHash128 is also good but not quite as fast. We believe our
|
||||
// nearest competitor is Bob Jenkins' Spooky. We don't have great data for
|
||||
// other 64-bit CPUs, but for long strings we know that Spooky is slightly
|
||||
// faster than CityHash on some relatively recent AMD x86-64 CPUs, for example.
|
||||
// Note that CityHashCrc128 is declared in citycrc.h.
|
||||
//
|
||||
// For 32-bit x86 code, we don't know of anything faster than CityHash32 that
|
||||
// is of comparable quality. We believe our nearest competitor is Murmur3A.
|
||||
// (On 64-bit CPUs, it is typically faster to use the other CityHash variants.)
|
||||
//
|
||||
// Functions in the CityHash family are not suitable for cryptography.
|
||||
//
|
||||
// Please see CityHash's README file for more details on our performance
|
||||
// measurements and so on.
|
||||
//
|
||||
// WARNING: This code has been only lightly tested on big-endian platforms!
|
||||
// It is known to work well on little-endian platforms that have a small penalty
|
||||
// for unaligned reads, such as current Intel and AMD moderate-to-high-end CPUs.
|
||||
// It should work on all 32-bit and 64-bit platforms that allow unaligned reads;
|
||||
// bug reports are welcome.
|
||||
//
|
||||
// By the way, for some hash functions, given strings a and b, the hash
|
||||
// of a+b is easily derived from the hashes of a and b. This property
|
||||
// doesn't hold for any hash functions in this file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h> // for size_t.
|
||||
|
||||
namespace Common {
|
||||
|
||||
typedef std::pair<uint64_t, uint64_t> uint128;
|
||||
|
||||
inline uint64_t Uint128Low64(const uint128& x) {
|
||||
return x.first;
|
||||
}
|
||||
inline uint64_t Uint128High64(const uint128& x) {
|
||||
return x.second;
|
||||
}
|
||||
|
||||
// Hash function for a byte array.
|
||||
uint64_t CityHash64(const char* buf, size_t len);
|
||||
|
||||
// Hash function for a byte array. For convenience, a 64-bit seed is also
|
||||
// hashed into the result.
|
||||
uint64_t CityHash64WithSeed(const char* buf, size_t len, uint64_t seed);
|
||||
|
||||
// Hash function for a byte array. For convenience, two seeds are also
|
||||
// hashed into the result.
|
||||
uint64_t CityHash64WithSeeds(const char* buf, size_t len, uint64_t seed0, uint64_t seed1);
|
||||
|
||||
// Hash function for a byte array.
|
||||
uint128 CityHash128(const char* s, size_t len);
|
||||
|
||||
// Hash function for a byte array. For convenience, a 128-bit seed is also
|
||||
// hashed into the result.
|
||||
uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed);
|
||||
|
||||
// Hash 128 input bits down to 64 bits of output.
|
||||
// This is intended to be a reasonably good hash function.
|
||||
inline uint64_t Hash128to64(const uint128& x) {
|
||||
// Murmur-inspired hashing.
|
||||
const uint64_t kMul = 0x9ddfea08eb382d69ULL;
|
||||
uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;
|
||||
a ^= (a >> 47);
|
||||
uint64_t b = (Uint128High64(x) ^ a) * kMul;
|
||||
b ^= (b >> 47);
|
||||
b *= kMul;
|
||||
return b;
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
@@ -1,85 +0,0 @@
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include "common/common_types.h"
|
||||
#include "common/memory_util.h"
|
||||
|
||||
// Everything that needs to generate code should inherit from this.
|
||||
// You get memory management for free, plus, you can use all emitter functions without
|
||||
// having to prefix them with gen-> or something similar.
|
||||
// Example implementation:
|
||||
// class JIT : public CodeBlock<ARMXEmitter> {}
|
||||
template <class T>
|
||||
class CodeBlock : public T, NonCopyable {
|
||||
private:
|
||||
// A privately used function to set the executable RAM space to something invalid.
|
||||
// For debugging usefulness it should be used to set the RAM to a host specific breakpoint
|
||||
// instruction
|
||||
virtual void PoisonMemory() = 0;
|
||||
|
||||
protected:
|
||||
u8* region;
|
||||
size_t region_size;
|
||||
|
||||
public:
|
||||
CodeBlock() : region(nullptr), region_size(0) {}
|
||||
virtual ~CodeBlock() {
|
||||
if (region)
|
||||
FreeCodeSpace();
|
||||
}
|
||||
|
||||
// Call this before you generate any code.
|
||||
void AllocCodeSpace(int size) {
|
||||
region_size = size;
|
||||
region = (u8*)AllocateExecutableMemory(region_size);
|
||||
T::SetCodePtr(region);
|
||||
}
|
||||
|
||||
// Always clear code space with breakpoints, so that if someone accidentally executes
|
||||
// uninitialized, it just breaks into the debugger.
|
||||
void ClearCodeSpace() {
|
||||
PoisonMemory();
|
||||
ResetCodePtr();
|
||||
}
|
||||
|
||||
// Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
|
||||
void FreeCodeSpace() {
|
||||
#ifdef __SYMBIAN32__
|
||||
ResetExecutableMemory(region);
|
||||
#else
|
||||
FreeMemoryPages(region, region_size);
|
||||
#endif
|
||||
region = nullptr;
|
||||
region_size = 0;
|
||||
}
|
||||
|
||||
bool IsInSpace(const u8* ptr) {
|
||||
return (ptr >= region) && (ptr < (region + region_size));
|
||||
}
|
||||
|
||||
// Cannot currently be undone. Will write protect the entire code region.
|
||||
// Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()).
|
||||
void WriteProtect() {
|
||||
WriteProtectMemory(region, region_size, true);
|
||||
}
|
||||
|
||||
void ResetCodePtr() {
|
||||
T::SetCodePtr(region);
|
||||
}
|
||||
|
||||
size_t GetSpaceLeft() const {
|
||||
return region_size - (T::GetCodePtr() - region);
|
||||
}
|
||||
|
||||
u8* GetBasePtr() {
|
||||
return region;
|
||||
}
|
||||
|
||||
size_t GetOffset(const u8* ptr) const {
|
||||
return ptr - region;
|
||||
}
|
||||
};
|
||||
@@ -9,8 +9,6 @@
|
||||
#endif
|
||||
#include "common/common_types.h"
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
/// Textually concatenates two tokens. The double-expansion is required by the C preprocessor.
|
||||
#define CONCAT2(x, y) DO_CONCAT2(x, y)
|
||||
#define DO_CONCAT2(x, y) x##y
|
||||
@@ -74,11 +72,6 @@ inline u64 _rotr64(u64 x, unsigned int shift) {
|
||||
|
||||
#else // _MSC_VER
|
||||
|
||||
#if (_MSC_VER < 1900)
|
||||
// Function Cross-Compatibility
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
// Locale Cross-Compatibility
|
||||
#define locale_t _locale_t
|
||||
|
||||
|
||||
@@ -27,29 +27,23 @@
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifndef __func__
|
||||
#define __func__ __FUNCTION__
|
||||
#endif
|
||||
#endif
|
||||
using u8 = std::uint8_t; ///< 8-bit unsigned byte
|
||||
using u16 = std::uint16_t; ///< 16-bit unsigned short
|
||||
using u32 = std::uint32_t; ///< 32-bit unsigned word
|
||||
using u64 = std::uint64_t; ///< 64-bit unsigned int
|
||||
|
||||
typedef std::uint8_t u8; ///< 8-bit unsigned byte
|
||||
typedef std::uint16_t u16; ///< 16-bit unsigned short
|
||||
typedef std::uint32_t u32; ///< 32-bit unsigned word
|
||||
typedef std::uint64_t u64; ///< 64-bit unsigned int
|
||||
using s8 = std::int8_t; ///< 8-bit signed byte
|
||||
using s16 = std::int16_t; ///< 16-bit signed short
|
||||
using s32 = std::int32_t; ///< 32-bit signed word
|
||||
using s64 = std::int64_t; ///< 64-bit signed int
|
||||
|
||||
typedef std::int8_t s8; ///< 8-bit signed byte
|
||||
typedef std::int16_t s16; ///< 16-bit signed short
|
||||
typedef std::int32_t s32; ///< 32-bit signed word
|
||||
typedef std::int64_t s64; ///< 64-bit signed int
|
||||
|
||||
typedef float f32; ///< 32-bit floating point
|
||||
typedef double f64; ///< 64-bit floating point
|
||||
using f32 = float; ///< 32-bit floating point
|
||||
using f64 = double; ///< 64-bit floating point
|
||||
|
||||
// TODO: It would be nice to eventually replace these with strong types that prevent accidental
|
||||
// conversion between each other.
|
||||
typedef u64 VAddr; ///< Represents a pointer in the userspace virtual address space.
|
||||
typedef u64 PAddr; ///< Represents a pointer in the ARM11 physical address space.
|
||||
using VAddr = u64; ///< Represents a pointer in the userspace virtual address space.
|
||||
using PAddr = u64; ///< Represents a pointer in the ARM11 physical address space.
|
||||
|
||||
using u128 = std::array<std::uint64_t, 2>;
|
||||
static_assert(sizeof(u128) == 16, "u128 must be 128 bits wide");
|
||||
|
||||
@@ -118,7 +118,7 @@ bool IsDirectory(const std::string& filename) {
|
||||
#endif
|
||||
|
||||
if (result < 0) {
|
||||
LOG_DEBUG(Common_Filesystem, "stat failed on %s: %s", filename.c_str(), GetLastErrorMsg());
|
||||
NGLOG_DEBUG(Common_Filesystem, "stat failed on {}: {}", filename, GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -128,31 +128,29 @@ bool IsDirectory(const std::string& filename) {
|
||||
// Deletes a given filename, return true on success
|
||||
// Doesn't supports deleting a directory
|
||||
bool Delete(const std::string& filename) {
|
||||
LOG_TRACE(Common_Filesystem, "file %s", filename.c_str());
|
||||
NGLOG_TRACE(Common_Filesystem, "file {}", filename);
|
||||
|
||||
// Return true because we care about the file no
|
||||
// being there, not the actual delete.
|
||||
if (!Exists(filename)) {
|
||||
LOG_DEBUG(Common_Filesystem, "%s does not exist", filename.c_str());
|
||||
NGLOG_DEBUG(Common_Filesystem, "{} does not exist", filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
// We can't delete a directory
|
||||
if (IsDirectory(filename)) {
|
||||
LOG_ERROR(Common_Filesystem, "Failed: %s is a directory", filename.c_str());
|
||||
NGLOG_ERROR(Common_Filesystem, "Failed: {} is a directory", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!DeleteFileW(Common::UTF8ToUTF16W(filename).c_str())) {
|
||||
LOG_ERROR(Common_Filesystem, "DeleteFile failed on %s: %s", filename.c_str(),
|
||||
GetLastErrorMsg());
|
||||
NGLOG_ERROR(Common_Filesystem, "DeleteFile failed on {}: {}", filename, GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (unlink(filename.c_str()) == -1) {
|
||||
LOG_ERROR(Common_Filesystem, "unlink failed on %s: %s", filename.c_str(),
|
||||
GetLastErrorMsg());
|
||||
NGLOG_ERROR(Common_Filesystem, "unlink failed on {}: {}", filename, GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
@@ -162,16 +160,16 @@ bool Delete(const std::string& filename) {
|
||||
|
||||
// Returns true if successful, or path already exists.
|
||||
bool CreateDir(const std::string& path) {
|
||||
LOG_TRACE(Common_Filesystem, "directory %s", path.c_str());
|
||||
NGLOG_TRACE(Common_Filesystem, "directory {}", path);
|
||||
#ifdef _WIN32
|
||||
if (::CreateDirectoryW(Common::UTF8ToUTF16W(path).c_str(), nullptr))
|
||||
return true;
|
||||
DWORD error = GetLastError();
|
||||
if (error == ERROR_ALREADY_EXISTS) {
|
||||
LOG_DEBUG(Common_Filesystem, "CreateDirectory failed on %s: already exists", path.c_str());
|
||||
NGLOG_DEBUG(Common_Filesystem, "CreateDirectory failed on {}: already exists", path);
|
||||
return true;
|
||||
}
|
||||
LOG_ERROR(Common_Filesystem, "CreateDirectory failed on %s: %i", path.c_str(), error);
|
||||
NGLOG_ERROR(Common_Filesystem, "CreateDirectory failed on {}: {}", path, error);
|
||||
return false;
|
||||
#else
|
||||
if (mkdir(path.c_str(), 0755) == 0)
|
||||
@@ -180,11 +178,11 @@ bool CreateDir(const std::string& path) {
|
||||
int err = errno;
|
||||
|
||||
if (err == EEXIST) {
|
||||
LOG_DEBUG(Common_Filesystem, "mkdir failed on %s: already exists", path.c_str());
|
||||
NGLOG_DEBUG(Common_Filesystem, "mkdir failed on {}: already exists", path);
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG_ERROR(Common_Filesystem, "mkdir failed on %s: %s", path.c_str(), strerror(err));
|
||||
NGLOG_ERROR(Common_Filesystem, "mkdir failed on {}: {}", path, strerror(err));
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
@@ -192,10 +190,10 @@ bool CreateDir(const std::string& path) {
|
||||
// Creates the full path of fullPath returns true on success
|
||||
bool CreateFullPath(const std::string& fullPath) {
|
||||
int panicCounter = 100;
|
||||
LOG_TRACE(Common_Filesystem, "path %s", fullPath.c_str());
|
||||
NGLOG_TRACE(Common_Filesystem, "path {}", fullPath);
|
||||
|
||||
if (FileUtil::Exists(fullPath)) {
|
||||
LOG_DEBUG(Common_Filesystem, "path exists %s", fullPath.c_str());
|
||||
NGLOG_DEBUG(Common_Filesystem, "path exists {}", fullPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -211,14 +209,14 @@ bool CreateFullPath(const std::string& fullPath) {
|
||||
// Include the '/' so the first call is CreateDir("/") rather than CreateDir("")
|
||||
std::string const subPath(fullPath.substr(0, position + 1));
|
||||
if (!FileUtil::IsDirectory(subPath) && !FileUtil::CreateDir(subPath)) {
|
||||
LOG_ERROR(Common, "CreateFullPath: directory creation failed");
|
||||
NGLOG_ERROR(Common, "CreateFullPath: directory creation failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// A safety check
|
||||
panicCounter--;
|
||||
if (panicCounter <= 0) {
|
||||
LOG_ERROR(Common, "CreateFullPath: directory structure is too deep");
|
||||
NGLOG_ERROR(Common, "CreateFullPath: directory structure is too deep");
|
||||
return false;
|
||||
}
|
||||
position++;
|
||||
@@ -227,11 +225,11 @@ bool CreateFullPath(const std::string& fullPath) {
|
||||
|
||||
// Deletes a directory filename, returns true on success
|
||||
bool DeleteDir(const std::string& filename) {
|
||||
LOG_TRACE(Common_Filesystem, "directory %s", filename.c_str());
|
||||
NGLOG_TRACE(Common_Filesystem, "directory {}", filename);
|
||||
|
||||
// check if a directory
|
||||
if (!FileUtil::IsDirectory(filename)) {
|
||||
LOG_ERROR(Common_Filesystem, "Not a directory %s", filename.c_str());
|
||||
NGLOG_ERROR(Common_Filesystem, "Not a directory {}", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -242,14 +240,14 @@ bool DeleteDir(const std::string& filename) {
|
||||
if (rmdir(filename.c_str()) == 0)
|
||||
return true;
|
||||
#endif
|
||||
LOG_ERROR(Common_Filesystem, "failed %s: %s", filename.c_str(), GetLastErrorMsg());
|
||||
NGLOG_ERROR(Common_Filesystem, "failed {}: {}", filename, GetLastErrorMsg());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// renames file srcFilename to destFilename, returns true on success
|
||||
bool Rename(const std::string& srcFilename, const std::string& destFilename) {
|
||||
LOG_TRACE(Common_Filesystem, "%s --> %s", srcFilename.c_str(), destFilename.c_str());
|
||||
NGLOG_TRACE(Common_Filesystem, "{} --> {}", srcFilename, destFilename);
|
||||
#ifdef _WIN32
|
||||
if (_wrename(Common::UTF8ToUTF16W(srcFilename).c_str(),
|
||||
Common::UTF8ToUTF16W(destFilename).c_str()) == 0)
|
||||
@@ -258,21 +256,21 @@ bool Rename(const std::string& srcFilename, const std::string& destFilename) {
|
||||
if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)
|
||||
return true;
|
||||
#endif
|
||||
LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(),
|
||||
GetLastErrorMsg());
|
||||
NGLOG_ERROR(Common_Filesystem, "failed {} --> {}: {}", srcFilename, destFilename,
|
||||
GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
|
||||
// copies file srcFilename to destFilename, returns true on success
|
||||
bool Copy(const std::string& srcFilename, const std::string& destFilename) {
|
||||
LOG_TRACE(Common_Filesystem, "%s --> %s", srcFilename.c_str(), destFilename.c_str());
|
||||
NGLOG_TRACE(Common_Filesystem, "{} --> {}", srcFilename, destFilename);
|
||||
#ifdef _WIN32
|
||||
if (CopyFileW(Common::UTF8ToUTF16W(srcFilename).c_str(),
|
||||
Common::UTF8ToUTF16W(destFilename).c_str(), FALSE))
|
||||
return true;
|
||||
|
||||
LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(),
|
||||
GetLastErrorMsg());
|
||||
NGLOG_ERROR(Common_Filesystem, "failed {} --> {}: {}", srcFilename, destFilename,
|
||||
GetLastErrorMsg());
|
||||
return false;
|
||||
#else
|
||||
|
||||
@@ -284,8 +282,8 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
|
||||
// Open input file
|
||||
FILE* input = fopen(srcFilename.c_str(), "rb");
|
||||
if (!input) {
|
||||
LOG_ERROR(Common_Filesystem, "opening input failed %s --> %s: %s", srcFilename.c_str(),
|
||||
destFilename.c_str(), GetLastErrorMsg());
|
||||
NGLOG_ERROR(Common_Filesystem, "opening input failed {} --> {}: {}", srcFilename,
|
||||
destFilename, GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -293,8 +291,8 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
|
||||
FILE* output = fopen(destFilename.c_str(), "wb");
|
||||
if (!output) {
|
||||
fclose(input);
|
||||
LOG_ERROR(Common_Filesystem, "opening output failed %s --> %s: %s", srcFilename.c_str(),
|
||||
destFilename.c_str(), GetLastErrorMsg());
|
||||
NGLOG_ERROR(Common_Filesystem, "opening output failed {} --> {}: {}", srcFilename,
|
||||
destFilename, GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -304,8 +302,8 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
|
||||
size_t rnum = fread(buffer, sizeof(char), BSIZE, input);
|
||||
if (rnum != BSIZE) {
|
||||
if (ferror(input) != 0) {
|
||||
LOG_ERROR(Common_Filesystem, "failed reading from source, %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||
NGLOG_ERROR(Common_Filesystem, "failed reading from source, {} --> {}: {}",
|
||||
srcFilename, destFilename, GetLastErrorMsg());
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
@@ -313,8 +311,8 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
|
||||
// write output
|
||||
size_t wnum = fwrite(buffer, sizeof(char), rnum, output);
|
||||
if (wnum != rnum) {
|
||||
LOG_ERROR(Common_Filesystem, "failed writing to output, %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||
NGLOG_ERROR(Common_Filesystem, "failed writing to output, {} --> {}: {}", srcFilename,
|
||||
destFilename, GetLastErrorMsg());
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
@@ -334,12 +332,12 @@ bail:
|
||||
// Returns the size of filename (64bit)
|
||||
u64 GetSize(const std::string& filename) {
|
||||
if (!Exists(filename)) {
|
||||
LOG_ERROR(Common_Filesystem, "failed %s: No such file", filename.c_str());
|
||||
NGLOG_ERROR(Common_Filesystem, "failed {}: No such file", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (IsDirectory(filename)) {
|
||||
LOG_ERROR(Common_Filesystem, "failed %s: is a directory", filename.c_str());
|
||||
NGLOG_ERROR(Common_Filesystem, "failed {}: is a directory", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -350,11 +348,11 @@ u64 GetSize(const std::string& filename) {
|
||||
if (stat(filename.c_str(), &buf) == 0)
|
||||
#endif
|
||||
{
|
||||
LOG_TRACE(Common_Filesystem, "%s: %lld", filename.c_str(), (long long)buf.st_size);
|
||||
NGLOG_TRACE(Common_Filesystem, "{}: {}", filename, buf.st_size);
|
||||
return buf.st_size;
|
||||
}
|
||||
|
||||
LOG_ERROR(Common_Filesystem, "Stat failed %s: %s", filename.c_str(), GetLastErrorMsg());
|
||||
NGLOG_ERROR(Common_Filesystem, "Stat failed {}: {}", filename, GetLastErrorMsg());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -362,7 +360,7 @@ u64 GetSize(const std::string& filename) {
|
||||
u64 GetSize(const int fd) {
|
||||
struct stat buf;
|
||||
if (fstat(fd, &buf) != 0) {
|
||||
LOG_ERROR(Common_Filesystem, "GetSize: stat failed %i: %s", fd, GetLastErrorMsg());
|
||||
NGLOG_ERROR(Common_Filesystem, "GetSize: stat failed {}: {}", fd, GetLastErrorMsg());
|
||||
return 0;
|
||||
}
|
||||
return buf.st_size;
|
||||
@@ -373,12 +371,14 @@ u64 GetSize(FILE* f) {
|
||||
// can't use off_t here because it can be 32-bit
|
||||
u64 pos = ftello(f);
|
||||
if (fseeko(f, 0, SEEK_END) != 0) {
|
||||
LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s", f, GetLastErrorMsg());
|
||||
NGLOG_ERROR(Common_Filesystem, "GetSize: seek failed {}: {}", fmt::ptr(f),
|
||||
GetLastErrorMsg());
|
||||
return 0;
|
||||
}
|
||||
u64 size = ftello(f);
|
||||
if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) {
|
||||
LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s", f, GetLastErrorMsg());
|
||||
NGLOG_ERROR(Common_Filesystem, "GetSize: seek failed {}: {}", fmt::ptr(f),
|
||||
GetLastErrorMsg());
|
||||
return 0;
|
||||
}
|
||||
return size;
|
||||
@@ -386,10 +386,10 @@ u64 GetSize(FILE* f) {
|
||||
|
||||
// creates an empty file filename, returns true on success
|
||||
bool CreateEmptyFile(const std::string& filename) {
|
||||
LOG_TRACE(Common_Filesystem, "%s", filename.c_str());
|
||||
NGLOG_TRACE(Common_Filesystem, "{}", filename);
|
||||
|
||||
if (!FileUtil::IOFile(filename, "wb")) {
|
||||
LOG_ERROR(Common_Filesystem, "failed %s: %s", filename.c_str(), GetLastErrorMsg());
|
||||
NGLOG_ERROR(Common_Filesystem, "failed {}: {}", filename, GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -398,7 +398,7 @@ bool CreateEmptyFile(const std::string& filename) {
|
||||
|
||||
bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string& directory,
|
||||
DirectoryEntryCallable callback) {
|
||||
LOG_TRACE(Common_Filesystem, "directory %s", directory.c_str());
|
||||
NGLOG_TRACE(Common_Filesystem, "directory {}", directory);
|
||||
|
||||
// How many files + directories we found
|
||||
unsigned found_entries = 0;
|
||||
@@ -556,7 +556,7 @@ std::string GetCurrentDir() {
|
||||
char* dir;
|
||||
if (!(dir = getcwd(nullptr, 0))) {
|
||||
#endif
|
||||
LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: %s", GetLastErrorMsg());
|
||||
NGLOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: {}", GetLastErrorMsg());
|
||||
return nullptr;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
@@ -653,12 +653,12 @@ static const std::string GetUserDirectory(const std::string& envvar) {
|
||||
else if (envvar == "XDG_CACHE_HOME")
|
||||
subdirectory = DIR_SEP ".cache";
|
||||
else
|
||||
ASSERT_MSG(false, "Unknown XDG variable %s.", envvar.c_str());
|
||||
ASSERT_MSG(false, "Unknown XDG variable {}.", envvar);
|
||||
user_dir = GetHomeDirectory() + subdirectory;
|
||||
}
|
||||
|
||||
ASSERT_MSG(!user_dir.empty(), "User directory %s musn’t be empty.", envvar.c_str());
|
||||
ASSERT_MSG(user_dir[0] == '/', "User directory %s must be absolute.", envvar.c_str());
|
||||
ASSERT_MSG(!user_dir.empty(), "User directory {} mustn’t be empty.", envvar);
|
||||
ASSERT_MSG(user_dir[0] == '/', "User directory {} must be absolute.", envvar);
|
||||
|
||||
return user_dir;
|
||||
}
|
||||
@@ -676,7 +676,7 @@ std::string GetSysDirectory() {
|
||||
#endif
|
||||
sysDir += DIR_SEP;
|
||||
|
||||
LOG_DEBUG(Common_Filesystem, "Setting to %s:", sysDir.c_str());
|
||||
NGLOG_DEBUG(Common_Filesystem, "Setting to {}:", sysDir);
|
||||
return sysDir;
|
||||
}
|
||||
|
||||
@@ -692,7 +692,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string& new
|
||||
if (!FileUtil::IsDirectory(paths[D_USER_IDX])) {
|
||||
paths[D_USER_IDX] = AppDataRoamingDirectory() + DIR_SEP EMU_DATA_DIR DIR_SEP;
|
||||
} else {
|
||||
LOG_INFO(Common_Filesystem, "Using the local user directory");
|
||||
NGLOG_INFO(Common_Filesystem, "Using the local user directory");
|
||||
}
|
||||
|
||||
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
|
||||
@@ -719,7 +719,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string& new
|
||||
|
||||
if (!newPath.empty()) {
|
||||
if (!FileUtil::IsDirectory(newPath)) {
|
||||
LOG_ERROR(Common_Filesystem, "Invalid path specified %s", newPath.c_str());
|
||||
NGLOG_ERROR(Common_Filesystem, "Invalid path specified {}", newPath);
|
||||
return paths[DirIDX];
|
||||
} else {
|
||||
paths[DirIDX] = newPath;
|
||||
|
||||
@@ -121,7 +121,7 @@ void CopyDir(const std::string& source_path, const std::string& dest_path);
|
||||
// Set the current directory to given directory
|
||||
bool SetCurrentDir(const std::string& directory);
|
||||
|
||||
// Returns a pointer to a string with a Citra data dir in the user's home
|
||||
// Returns a pointer to a string with a yuzu data dir in the user's home
|
||||
// directory. To be used in "multi-user" mode (that is, installed).
|
||||
const std::string& GetUserPath(const unsigned int DirIDX, const std::string& newPath = "");
|
||||
|
||||
@@ -170,12 +170,8 @@ public:
|
||||
|
||||
template <typename T>
|
||||
size_t ReadArray(T* data, size_t length) {
|
||||
static_assert(std::is_standard_layout<T>(),
|
||||
"Given array does not consist of standard layout objects");
|
||||
#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
|
||||
static_assert(std::is_trivially_copyable<T>(),
|
||||
"Given array does not consist of trivially copyable objects");
|
||||
#endif
|
||||
|
||||
if (!IsOpen()) {
|
||||
m_good = false;
|
||||
@@ -191,12 +187,8 @@ public:
|
||||
|
||||
template <typename T>
|
||||
size_t WriteArray(const T* data, size_t length) {
|
||||
static_assert(std::is_standard_layout<T>(),
|
||||
"Given array does not consist of standard layout objects");
|
||||
#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
|
||||
static_assert(std::is_trivially_copyable<T>(),
|
||||
"Given array does not consist of trivially copyable objects");
|
||||
#endif
|
||||
|
||||
if (!IsOpen()) {
|
||||
m_good = false;
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
// Copyright 2015 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/hash.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
// MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||
// domain. The author hereby disclaims copyright to this source code.
|
||||
|
||||
// Block read - if your platform needs to do endian-swapping or can only handle aligned reads, do
|
||||
// the conversion here
|
||||
static FORCE_INLINE u64 getblock64(const u64* p, size_t i) {
|
||||
return p[i];
|
||||
}
|
||||
|
||||
// Finalization mix - force all bits of a hash block to avalanche
|
||||
static FORCE_INLINE u64 fmix64(u64 k) {
|
||||
k ^= k >> 33;
|
||||
k *= 0xff51afd7ed558ccdllu;
|
||||
k ^= k >> 33;
|
||||
k *= 0xc4ceb9fe1a85ec53llu;
|
||||
k ^= k >> 33;
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
// This is the 128-bit variant of the MurmurHash3 hash function that is targeted for 64-bit
|
||||
// platforms (MurmurHash3_x64_128). It was taken from:
|
||||
// https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
|
||||
void MurmurHash3_128(const void* key, size_t len, u32 seed, void* out) {
|
||||
const u8* data = (const u8*)key;
|
||||
const size_t nblocks = len / 16;
|
||||
|
||||
u64 h1 = seed;
|
||||
u64 h2 = seed;
|
||||
|
||||
const u64 c1 = 0x87c37b91114253d5llu;
|
||||
const u64 c2 = 0x4cf5ad432745937fllu;
|
||||
|
||||
// Body
|
||||
|
||||
const u64* blocks = (const u64*)(data);
|
||||
|
||||
for (size_t i = 0; i < nblocks; i++) {
|
||||
u64 k1 = getblock64(blocks, i * 2 + 0);
|
||||
u64 k2 = getblock64(blocks, i * 2 + 1);
|
||||
|
||||
k1 *= c1;
|
||||
k1 = _rotl64(k1, 31);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
|
||||
h1 = _rotl64(h1, 27);
|
||||
h1 += h2;
|
||||
h1 = h1 * 5 + 0x52dce729;
|
||||
|
||||
k2 *= c2;
|
||||
k2 = _rotl64(k2, 33);
|
||||
k2 *= c1;
|
||||
h2 ^= k2;
|
||||
|
||||
h2 = _rotl64(h2, 31);
|
||||
h2 += h1;
|
||||
h2 = h2 * 5 + 0x38495ab5;
|
||||
}
|
||||
|
||||
// Tail
|
||||
|
||||
const u8* tail = (const u8*)(data + nblocks * 16);
|
||||
|
||||
u64 k1 = 0;
|
||||
u64 k2 = 0;
|
||||
|
||||
switch (len & 15) {
|
||||
case 15:
|
||||
k2 ^= ((u64)tail[14]) << 48;
|
||||
case 14:
|
||||
k2 ^= ((u64)tail[13]) << 40;
|
||||
case 13:
|
||||
k2 ^= ((u64)tail[12]) << 32;
|
||||
case 12:
|
||||
k2 ^= ((u64)tail[11]) << 24;
|
||||
case 11:
|
||||
k2 ^= ((u64)tail[10]) << 16;
|
||||
case 10:
|
||||
k2 ^= ((u64)tail[9]) << 8;
|
||||
case 9:
|
||||
k2 ^= ((u64)tail[8]) << 0;
|
||||
k2 *= c2;
|
||||
k2 = _rotl64(k2, 33);
|
||||
k2 *= c1;
|
||||
h2 ^= k2;
|
||||
|
||||
case 8:
|
||||
k1 ^= ((u64)tail[7]) << 56;
|
||||
case 7:
|
||||
k1 ^= ((u64)tail[6]) << 48;
|
||||
case 6:
|
||||
k1 ^= ((u64)tail[5]) << 40;
|
||||
case 5:
|
||||
k1 ^= ((u64)tail[4]) << 32;
|
||||
case 4:
|
||||
k1 ^= ((u64)tail[3]) << 24;
|
||||
case 3:
|
||||
k1 ^= ((u64)tail[2]) << 16;
|
||||
case 2:
|
||||
k1 ^= ((u64)tail[1]) << 8;
|
||||
case 1:
|
||||
k1 ^= ((u64)tail[0]) << 0;
|
||||
k1 *= c1;
|
||||
k1 = _rotl64(k1, 31);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
};
|
||||
|
||||
// Finalization
|
||||
|
||||
h1 ^= len;
|
||||
h2 ^= len;
|
||||
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
||||
h1 = fmix64(h1);
|
||||
h2 = fmix64(h2);
|
||||
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
||||
((u64*)out)[0] = h1;
|
||||
((u64*)out)[1] = h2;
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
@@ -5,12 +5,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include "common/cityhash.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
void MurmurHash3_128(const void* key, size_t len, u32 seed, void* out);
|
||||
|
||||
/**
|
||||
* Computes a 64-bit hash over the specified block of data
|
||||
* @param data Block of data to compute hash over
|
||||
@@ -18,9 +18,54 @@ void MurmurHash3_128(const void* key, size_t len, u32 seed, void* out);
|
||||
* @returns 64-bit hash value that was computed over the data block
|
||||
*/
|
||||
static inline u64 ComputeHash64(const void* data, size_t len) {
|
||||
u64 res[2];
|
||||
MurmurHash3_128(data, len, 0, res);
|
||||
return res[0];
|
||||
return CityHash64(static_cast<const char*>(data), len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a 64-bit hash of a struct. In addition to being trivially copyable, it is also critical
|
||||
* that either the struct includes no padding, or that any padding is initialized to a known value
|
||||
* by memsetting the struct to 0 before filling it in.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline u64 ComputeStructHash64(const T& data) {
|
||||
static_assert(std::is_trivially_copyable<T>(),
|
||||
"Type passed to ComputeStructHash64 must be trivially copyable");
|
||||
return ComputeHash64(&data, sizeof(data));
|
||||
}
|
||||
|
||||
/// A helper template that ensures the padding in a struct is initialized by memsetting to 0.
|
||||
template <typename T>
|
||||
struct HashableStruct {
|
||||
// In addition to being trivially copyable, T must also have a trivial default constructor,
|
||||
// because any member initialization would be overridden by memset
|
||||
static_assert(std::is_trivial<T>(), "Type passed to HashableStruct must be trivial");
|
||||
/*
|
||||
* We use a union because "implicitly-defined copy/move constructor for a union X copies the
|
||||
* object representation of X." and "implicitly-defined copy assignment operator for a union X
|
||||
* copies the object representation (3.9) of X." = Bytewise copy instead of memberwise copy.
|
||||
* This is important because the padding bytes are included in the hash and comparison between
|
||||
* objects.
|
||||
*/
|
||||
union {
|
||||
T state;
|
||||
};
|
||||
|
||||
HashableStruct() {
|
||||
// Memset structure to zero padding bits, so that they will be deterministic when hashing
|
||||
std::memset(&state, 0, sizeof(T));
|
||||
}
|
||||
|
||||
bool operator==(const HashableStruct<T>& o) const {
|
||||
return std::memcmp(&state, &o.state, sizeof(T)) == 0;
|
||||
};
|
||||
|
||||
bool operator!=(const HashableStruct<T>& o) const {
|
||||
return !(*this == o);
|
||||
};
|
||||
|
||||
size_t Hash() const {
|
||||
return Common::ComputeStructHash64(state);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include "common/common_types.h"
|
||||
|
||||
// defined in Version.cpp
|
||||
extern const char* scm_rev_git_str;
|
||||
|
||||
// On disk format:
|
||||
// header{
|
||||
// u32 'DCAC';
|
||||
// u32 version; // svn_rev
|
||||
// u16 sizeof(key_type);
|
||||
// u16 sizeof(value_type);
|
||||
//}
|
||||
|
||||
// key_value_pair{
|
||||
// u32 value_size;
|
||||
// key_type key;
|
||||
// value_type[value_size] value;
|
||||
//}
|
||||
|
||||
template <typename K, typename V>
|
||||
class LinearDiskCacheReader {
|
||||
public:
|
||||
virtual void Read(const K& key, const V* value, u32 value_size) = 0;
|
||||
};
|
||||
|
||||
// Dead simple unsorted key-value store with append functionality.
|
||||
// No random read functionality, all reading is done in OpenAndRead.
|
||||
// Keys and values can contain any characters, including \0.
|
||||
//
|
||||
// Suitable for caching generated shader bytecode between executions.
|
||||
// Not tuned for extreme performance but should be reasonably fast.
|
||||
// Does not support keys or values larger than 2GB, which should be reasonable.
|
||||
// Keys must have non-zero length; values can have zero length.
|
||||
|
||||
// K and V are some POD type
|
||||
// K : the key type
|
||||
// V : value array type
|
||||
template <typename K, typename V>
|
||||
class LinearDiskCache {
|
||||
public:
|
||||
// return number of read entries
|
||||
u32 OpenAndRead(const char* filename, LinearDiskCacheReader<K, V>& reader) {
|
||||
using std::ios_base;
|
||||
|
||||
// close any currently opened file
|
||||
Close();
|
||||
m_num_entries = 0;
|
||||
|
||||
// try opening for reading/writing
|
||||
OpenFStream(m_file, filename, ios_base::in | ios_base::out | ios_base::binary);
|
||||
|
||||
m_file.seekg(0, std::ios::end);
|
||||
std::fstream::pos_type end_pos = m_file.tellg();
|
||||
m_file.seekg(0, std::ios::beg);
|
||||
std::fstream::pos_type start_pos = m_file.tellg();
|
||||
std::streamoff file_size = end_pos - start_pos;
|
||||
|
||||
if (m_file.is_open() && ValidateHeader()) {
|
||||
// good header, read some key/value pairs
|
||||
K key;
|
||||
|
||||
V* value = nullptr;
|
||||
u32 value_size;
|
||||
u32 entry_number;
|
||||
|
||||
std::fstream::pos_type last_pos = m_file.tellg();
|
||||
|
||||
while (Read(&value_size)) {
|
||||
std::streamoff next_extent =
|
||||
(last_pos - start_pos) + sizeof(value_size) + value_size;
|
||||
if (next_extent > file_size)
|
||||
break;
|
||||
|
||||
delete[] value;
|
||||
value = new V[value_size];
|
||||
|
||||
// read key/value and pass to reader
|
||||
if (Read(&key) && Read(value, value_size) && Read(&entry_number) &&
|
||||
entry_number == m_num_entries + 1) {
|
||||
reader.Read(key, value, value_size);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
m_num_entries++;
|
||||
last_pos = m_file.tellg();
|
||||
}
|
||||
m_file.seekp(last_pos);
|
||||
m_file.clear();
|
||||
|
||||
delete[] value;
|
||||
return m_num_entries;
|
||||
}
|
||||
|
||||
// failed to open file for reading or bad header
|
||||
// close and recreate file
|
||||
Close();
|
||||
m_file.open(filename, ios_base::out | ios_base::trunc | ios_base::binary);
|
||||
WriteHeader();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Sync() {
|
||||
m_file.flush();
|
||||
}
|
||||
|
||||
void Close() {
|
||||
if (m_file.is_open())
|
||||
m_file.close();
|
||||
// clear any error flags
|
||||
m_file.clear();
|
||||
}
|
||||
|
||||
// Appends a key-value pair to the store.
|
||||
void Append(const K& key, const V* value, u32 value_size) {
|
||||
// TODO: Should do a check that we don't already have "key"? (I think each caller does that
|
||||
// already.)
|
||||
Write(&value_size);
|
||||
Write(&key);
|
||||
Write(value, value_size);
|
||||
m_num_entries++;
|
||||
Write(&m_num_entries);
|
||||
}
|
||||
|
||||
private:
|
||||
void WriteHeader() {
|
||||
Write(&m_header);
|
||||
}
|
||||
|
||||
bool ValidateHeader() {
|
||||
char file_header[sizeof(Header)];
|
||||
|
||||
return (Read(file_header, sizeof(Header)) &&
|
||||
!memcmp((const char*)&m_header, file_header, sizeof(Header)));
|
||||
}
|
||||
|
||||
template <typename D>
|
||||
bool Write(const D* data, u32 count = 1) {
|
||||
return m_file.write((const char*)data, count * sizeof(D)).good();
|
||||
}
|
||||
|
||||
template <typename D>
|
||||
bool Read(const D* data, u32 count = 1) {
|
||||
return m_file.read((char*)data, count * sizeof(D)).good();
|
||||
}
|
||||
|
||||
struct Header {
|
||||
Header() : id(*(u32*)"DCAC"), key_t_size(sizeof(K)), value_t_size(sizeof(V)) {
|
||||
memcpy(ver, scm_rev_git_str, 40);
|
||||
}
|
||||
|
||||
const u32 id;
|
||||
const u16 key_t_size, value_t_size;
|
||||
char ver[40];
|
||||
|
||||
} m_header;
|
||||
|
||||
std::fstream m_file;
|
||||
u32 m_num_entries;
|
||||
};
|
||||
@@ -2,15 +2,13 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <utility>
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h" // snprintf compatibility define
|
||||
#include "common/logging/backend.h"
|
||||
#include "common/logging/filter.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/logging/text_formatter.h"
|
||||
#include "common/string_util.h"
|
||||
|
||||
namespace Log {
|
||||
|
||||
@@ -42,12 +40,16 @@ namespace Log {
|
||||
SUB(Service, FS) \
|
||||
SUB(Service, HID) \
|
||||
SUB(Service, LM) \
|
||||
SUB(Service, NFP) \
|
||||
SUB(Service, NIFM) \
|
||||
SUB(Service, NS) \
|
||||
SUB(Service, NVDRV) \
|
||||
SUB(Service, PCTL) \
|
||||
SUB(Service, PREPO) \
|
||||
SUB(Service, SET) \
|
||||
SUB(Service, SM) \
|
||||
SUB(Service, SPL) \
|
||||
SUB(Service, SSL) \
|
||||
SUB(Service, Time) \
|
||||
SUB(Service, VI) \
|
||||
CLS(HW) \
|
||||
@@ -103,25 +105,20 @@ const char* GetLevelName(Level log_level) {
|
||||
}
|
||||
|
||||
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
|
||||
const char* function, const char* format, va_list args) {
|
||||
const char* function, std::string message) {
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::steady_clock;
|
||||
|
||||
static steady_clock::time_point time_origin = steady_clock::now();
|
||||
|
||||
std::array<char, 4 * 1024> formatting_buffer;
|
||||
|
||||
Entry entry;
|
||||
entry.timestamp = duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin);
|
||||
entry.log_class = log_class;
|
||||
entry.log_level = log_level;
|
||||
|
||||
snprintf(formatting_buffer.data(), formatting_buffer.size(), "%s:%s:%u", filename, function,
|
||||
line_nr);
|
||||
entry.location = std::string(formatting_buffer.data());
|
||||
|
||||
vsnprintf(formatting_buffer.data(), formatting_buffer.size(), format, args);
|
||||
entry.message = std::string(formatting_buffer.data());
|
||||
entry.filename = Common::TrimSourcePath(filename);
|
||||
entry.line_num = line_nr;
|
||||
entry.function = function;
|
||||
entry.message = std::move(message);
|
||||
|
||||
return entry;
|
||||
}
|
||||
@@ -132,15 +129,13 @@ void SetFilter(Filter* new_filter) {
|
||||
filter = new_filter;
|
||||
}
|
||||
|
||||
void LogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
|
||||
const char* function, const char* format, ...) {
|
||||
if (filter != nullptr && !filter->CheckMessage(log_class, log_level))
|
||||
void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
|
||||
unsigned int line_num, const char* function, const char* format,
|
||||
const fmt::format_args& args) {
|
||||
if (filter && !filter->CheckMessage(log_class, log_level))
|
||||
return;
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
Entry entry = CreateEntry(log_class, log_level, filename, line_nr, function, format, args);
|
||||
va_end(args);
|
||||
Entry entry =
|
||||
CreateEntry(log_class, log_level, filename, line_num, function, fmt::vformat(format, args));
|
||||
|
||||
PrintColoredMessage(entry);
|
||||
}
|
||||
|
||||
@@ -22,13 +22,16 @@ struct Entry {
|
||||
std::chrono::microseconds timestamp;
|
||||
Class log_class;
|
||||
Level log_level;
|
||||
std::string location;
|
||||
std::string filename;
|
||||
unsigned int line_num;
|
||||
std::string function;
|
||||
std::string message;
|
||||
|
||||
Entry() = default;
|
||||
Entry(Entry&& o) = default;
|
||||
|
||||
Entry& operator=(Entry&& o) = default;
|
||||
Entry& operator=(const Entry& o) = default;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -44,7 +47,7 @@ const char* GetLevelName(Level log_level);
|
||||
|
||||
/// Creates a log entry by formatting the given source location, and message.
|
||||
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
|
||||
const char* function, const char* format, va_list args);
|
||||
const char* function, std::string message);
|
||||
|
||||
void SetFilter(Filter* filter);
|
||||
} // namespace Log
|
||||
|
||||
@@ -65,14 +65,14 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin,
|
||||
const std::string::const_iterator end) {
|
||||
auto level_separator = std::find(begin, end, ':');
|
||||
if (level_separator == end) {
|
||||
LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: %s",
|
||||
std::string(begin, end).c_str());
|
||||
NGLOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: %s",
|
||||
std::string(begin, end).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
const Level level = GetLevelByName(level_separator + 1, end);
|
||||
if (level == Level::Count) {
|
||||
LOG_ERROR(Log, "Unknown log level in filter: %s", std::string(begin, end).c_str());
|
||||
NGLOG_ERROR(Log, "Unknown log level in filter: %s", std::string(begin, end).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin,
|
||||
|
||||
const Class log_class = GetClassByName(begin, level_separator);
|
||||
if (log_class == Class::Count) {
|
||||
LOG_ERROR(Log, "Unknown log class in filter: %s", std::string(begin, end).c_str());
|
||||
NGLOG_ERROR(Log, "Unknown log class in filter: %s", std::string(begin, end).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Log {
|
||||
class Filter {
|
||||
public:
|
||||
/// Initializes the filter with all classes having `default_level` as the minimum level.
|
||||
Filter(Level default_level);
|
||||
Filter(Level default_level = Level::Info);
|
||||
|
||||
/// Resets the filter so that all classes have `level` as the minimum displayed level.
|
||||
void ResetAll(Level level);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Log {
|
||||
@@ -59,12 +60,16 @@ enum class Class : ClassType {
|
||||
Service_FS, ///< The FS (Filesystem) service
|
||||
Service_HID, ///< The HID (Human interface device) service
|
||||
Service_LM, ///< The LM (Logger) service
|
||||
Service_NFP, ///< The NFP service
|
||||
Service_NIFM, ///< The NIFM (Network interface) service
|
||||
Service_NS, ///< The NS services
|
||||
Service_NVDRV, ///< The NVDRV (Nvidia driver) service
|
||||
Service_PCTL, ///< The PCTL (Parental control) service
|
||||
Service_PREPO, ///< The PREPO (Play report) service
|
||||
Service_SET, ///< The SET (Settings) service
|
||||
Service_SM, ///< The SM (Service manager) service
|
||||
Service_SPL, ///< The SPL service
|
||||
Service_SSL, ///< The SSL service
|
||||
Service_Time, ///< The time service
|
||||
Service_VI, ///< The VI (Video interface) service
|
||||
HW, ///< Low-level hardware emulation
|
||||
@@ -83,42 +88,44 @@ enum class Class : ClassType {
|
||||
Loader, ///< ROM loader
|
||||
Input, ///< Input emulation
|
||||
Network, ///< Network emulation
|
||||
WebService, ///< Interface to Citra Web Services
|
||||
WebService, ///< Interface to yuzu Web Services
|
||||
Count ///< Total number of logging classes
|
||||
};
|
||||
|
||||
/// Logs a message to the global logger.
|
||||
void LogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
|
||||
const char* function,
|
||||
#ifdef _MSC_VER
|
||||
_Printf_format_string_
|
||||
#endif
|
||||
const char* format,
|
||||
...)
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 6, 7)))
|
||||
#endif
|
||||
;
|
||||
/// Logs a message to the global logger, using fmt
|
||||
void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
|
||||
unsigned int line_num, const char* function, const char* format,
|
||||
const fmt::format_args& args);
|
||||
|
||||
template <typename... Args>
|
||||
void FmtLogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_num,
|
||||
const char* function, const char* format, const Args&... args) {
|
||||
FmtLogMessageImpl(log_class, log_level, filename, line_num, function, format,
|
||||
fmt::make_args(args...));
|
||||
}
|
||||
|
||||
} // namespace Log
|
||||
|
||||
#define LOG_GENERIC(log_class, log_level, ...) \
|
||||
::Log::LogMessage(log_class, log_level, __FILE__, __LINE__, __func__, __VA_ARGS__)
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define LOG_TRACE(log_class, ...) \
|
||||
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Trace, __VA_ARGS__)
|
||||
#define NGLOG_TRACE(log_class, ...) \
|
||||
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Trace, __FILE__, __LINE__, \
|
||||
__func__, __VA_ARGS__)
|
||||
#else
|
||||
#define LOG_TRACE(log_class, ...) (void(0))
|
||||
#define NGLOG_TRACE(log_class, fmt, ...) (void(0))
|
||||
#endif
|
||||
|
||||
#define LOG_DEBUG(log_class, ...) \
|
||||
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Debug, __VA_ARGS__)
|
||||
#define LOG_INFO(log_class, ...) \
|
||||
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Info, __VA_ARGS__)
|
||||
#define LOG_WARNING(log_class, ...) \
|
||||
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Warning, __VA_ARGS__)
|
||||
#define LOG_ERROR(log_class, ...) \
|
||||
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Error, __VA_ARGS__)
|
||||
#define LOG_CRITICAL(log_class, ...) \
|
||||
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Critical, __VA_ARGS__)
|
||||
#define NGLOG_DEBUG(log_class, ...) \
|
||||
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Debug, __FILE__, __LINE__, \
|
||||
__func__, __VA_ARGS__)
|
||||
#define NGLOG_INFO(log_class, ...) \
|
||||
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Info, __FILE__, __LINE__, \
|
||||
__func__, __VA_ARGS__)
|
||||
#define NGLOG_WARNING(log_class, ...) \
|
||||
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Warning, __FILE__, __LINE__, \
|
||||
__func__, __VA_ARGS__)
|
||||
#define NGLOG_ERROR(log_class, ...) \
|
||||
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Error, __FILE__, __LINE__, \
|
||||
__func__, __VA_ARGS__)
|
||||
#define NGLOG_CRITICAL(log_class, ...) \
|
||||
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Critical, __FILE__, __LINE__, \
|
||||
__func__, __VA_ARGS__)
|
||||
|
||||
@@ -18,50 +18,29 @@
|
||||
|
||||
namespace Log {
|
||||
|
||||
// TODO(bunnei): This should be moved to a generic path manipulation library
|
||||
const char* TrimSourcePath(const char* path, const char* root) {
|
||||
const char* p = path;
|
||||
|
||||
while (*p != '\0') {
|
||||
const char* next_slash = p;
|
||||
while (*next_slash != '\0' && *next_slash != '/' && *next_slash != '\\') {
|
||||
++next_slash;
|
||||
}
|
||||
|
||||
bool is_src = Common::ComparePartialString(p, next_slash, root);
|
||||
p = next_slash;
|
||||
|
||||
if (*p != '\0') {
|
||||
++p;
|
||||
}
|
||||
if (is_src) {
|
||||
path = p;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len) {
|
||||
std::string FormatLogMessage(const Entry& entry) {
|
||||
unsigned int time_seconds = static_cast<unsigned int>(entry.timestamp.count() / 1000000);
|
||||
unsigned int time_fractional = static_cast<unsigned int>(entry.timestamp.count() % 1000000);
|
||||
|
||||
const char* class_name = GetLogClassName(entry.log_class);
|
||||
const char* level_name = GetLevelName(entry.log_level);
|
||||
|
||||
snprintf(out_text, text_len, "[%4u.%06u] %s <%s> %s: %s", time_seconds, time_fractional,
|
||||
class_name, level_name, TrimSourcePath(entry.location.c_str()), entry.message.c_str());
|
||||
return fmt::format("[{:4d}.{:06d}] {} <{}> {}:{}:{}: {}", time_seconds, time_fractional,
|
||||
class_name, level_name, entry.filename, entry.function, entry.line_num,
|
||||
entry.message);
|
||||
}
|
||||
|
||||
void PrintMessage(const Entry& entry) {
|
||||
std::array<char, 4 * 1024> format_buffer;
|
||||
FormatLogMessage(entry, format_buffer.data(), format_buffer.size());
|
||||
fputs(format_buffer.data(), stderr);
|
||||
fputc('\n', stderr);
|
||||
auto str = FormatLogMessage(entry) + '\n';
|
||||
fputs(str.c_str(), stderr);
|
||||
}
|
||||
|
||||
void PrintColoredMessage(const Entry& entry) {
|
||||
#ifdef _WIN32
|
||||
static HANDLE console_handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||
HANDLE console_handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||
if (console_handle == INVALID_HANDLE_VALUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO original_info = {0};
|
||||
GetConsoleScreenBufferInfo(console_handle, &original_info);
|
||||
|
||||
@@ -10,20 +10,8 @@ namespace Log {
|
||||
|
||||
struct Entry;
|
||||
|
||||
/**
|
||||
* Attempts to trim an arbitrary prefix from `path`, leaving only the part starting at `root`. It's
|
||||
* intended to be used to strip a system-specific build directory from the `__FILE__` macro,
|
||||
* leaving only the path relative to the sources root.
|
||||
*
|
||||
* @param path The input file path as a null-terminated string
|
||||
* @param root The name of the root source directory as a null-terminated string. Path up to and
|
||||
* including the last occurrence of this name will be stripped
|
||||
* @return A pointer to the same string passed as `path`, but starting at the trimmed portion
|
||||
*/
|
||||
const char* TrimSourcePath(const char* path, const char* root = "src");
|
||||
|
||||
/// Formats a log entry into the provided text buffer.
|
||||
void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len);
|
||||
std::string FormatLogMessage(const Entry& entry);
|
||||
/// Formats and prints a log entry to stderr.
|
||||
void PrintMessage(const Entry& entry);
|
||||
/// Prints the same message as `PrintMessage`, but colored acoording to the severity level.
|
||||
|
||||
@@ -17,11 +17,6 @@ inline bool IntervalsIntersect(unsigned start0, unsigned length0, unsigned start
|
||||
return (std::max(start0, start1) < std::min(start0 + length0, start1 + length1));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T Clamp(const T val, const T& min, const T& max) {
|
||||
return std::max(min, std::min(max, val));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct Rectangle {
|
||||
T left;
|
||||
|
||||
@@ -55,7 +55,7 @@ void* AllocateExecutableMemory(size_t size, bool low) {
|
||||
if (ptr == MAP_FAILED) {
|
||||
ptr = nullptr;
|
||||
#endif
|
||||
LOG_ERROR(Common_Memory, "Failed to allocate executable memory");
|
||||
NGLOG_ERROR(Common_Memory, "Failed to allocate executable memory");
|
||||
}
|
||||
#if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT)
|
||||
else {
|
||||
@@ -68,7 +68,7 @@ void* AllocateExecutableMemory(size_t size, bool low) {
|
||||
|
||||
#if EMU_ARCH_BITS == 64
|
||||
if ((u64)ptr >= 0x80000000 && low == true)
|
||||
LOG_ERROR(Common_Memory, "Executable memory ended up above 2GB!");
|
||||
NGLOG_ERROR(Common_Memory, "Executable memory ended up above 2GB!");
|
||||
#endif
|
||||
|
||||
return ptr;
|
||||
@@ -85,7 +85,7 @@ void* AllocateMemoryPages(size_t size) {
|
||||
#endif
|
||||
|
||||
if (ptr == nullptr)
|
||||
LOG_ERROR(Common_Memory, "Failed to allocate raw memory");
|
||||
NGLOG_ERROR(Common_Memory, "Failed to allocate raw memory");
|
||||
|
||||
return ptr;
|
||||
}
|
||||
@@ -99,12 +99,12 @@ void* AllocateAlignedMemory(size_t size, size_t alignment) {
|
||||
ptr = memalign(alignment, size);
|
||||
#else
|
||||
if (posix_memalign(&ptr, alignment, size) != 0)
|
||||
LOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
|
||||
NGLOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (ptr == nullptr)
|
||||
LOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
|
||||
NGLOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
|
||||
|
||||
return ptr;
|
||||
}
|
||||
@@ -113,7 +113,7 @@ void FreeMemoryPages(void* ptr, size_t size) {
|
||||
if (ptr) {
|
||||
#ifdef _WIN32
|
||||
if (!VirtualFree(ptr, 0, MEM_RELEASE))
|
||||
LOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n%s", GetLastErrorMsg());
|
||||
NGLOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n{}", GetLastErrorMsg());
|
||||
#else
|
||||
munmap(ptr, size);
|
||||
#endif
|
||||
@@ -134,7 +134,7 @@ void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) {
|
||||
#ifdef _WIN32
|
||||
DWORD oldValue;
|
||||
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
|
||||
LOG_ERROR(Common_Memory, "WriteProtectMemory failed!\n%s", GetLastErrorMsg());
|
||||
NGLOG_ERROR(Common_Memory, "WriteProtectMemory failed!\n{}", GetLastErrorMsg());
|
||||
#else
|
||||
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ);
|
||||
#endif
|
||||
@@ -145,7 +145,7 @@ void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) {
|
||||
DWORD oldValue;
|
||||
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE,
|
||||
&oldValue))
|
||||
LOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n%s", GetLastErrorMsg());
|
||||
NGLOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n{}", GetLastErrorMsg());
|
||||
#else
|
||||
mprotect(ptr, size,
|
||||
allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
|
||||
|
||||
@@ -25,7 +25,7 @@ ParamPackage::ParamPackage(const std::string& serialized) {
|
||||
std::vector<std::string> key_value;
|
||||
Common::SplitString(pair, KEY_VALUE_SEPARATOR, key_value);
|
||||
if (key_value.size() != 2) {
|
||||
LOG_ERROR(Common, "invalid key pair %s", pair.c_str());
|
||||
NGLOG_ERROR(Common, "invalid key pair {}", pair);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ std::string ParamPackage::Serialize() const {
|
||||
std::string ParamPackage::Get(const std::string& key, const std::string& default_value) const {
|
||||
auto pair = data.find(key);
|
||||
if (pair == data.end()) {
|
||||
LOG_DEBUG(Common, "key %s not found", key.c_str());
|
||||
NGLOG_DEBUG(Common, "key '{}' not found", key);
|
||||
return default_value;
|
||||
}
|
||||
|
||||
@@ -74,14 +74,14 @@ std::string ParamPackage::Get(const std::string& key, const std::string& default
|
||||
int ParamPackage::Get(const std::string& key, int default_value) const {
|
||||
auto pair = data.find(key);
|
||||
if (pair == data.end()) {
|
||||
LOG_DEBUG(Common, "key %s not found", key.c_str());
|
||||
NGLOG_DEBUG(Common, "key '{}' not found", key);
|
||||
return default_value;
|
||||
}
|
||||
|
||||
try {
|
||||
return std::stoi(pair->second);
|
||||
} catch (const std::logic_error&) {
|
||||
LOG_ERROR(Common, "failed to convert %s to int", pair->second.c_str());
|
||||
NGLOG_ERROR(Common, "failed to convert {} to int", pair->second);
|
||||
return default_value;
|
||||
}
|
||||
}
|
||||
@@ -89,14 +89,14 @@ int ParamPackage::Get(const std::string& key, int default_value) const {
|
||||
float ParamPackage::Get(const std::string& key, float default_value) const {
|
||||
auto pair = data.find(key);
|
||||
if (pair == data.end()) {
|
||||
LOG_DEBUG(Common, "key %s not found", key.c_str());
|
||||
NGLOG_DEBUG(Common, "key {} not found", key);
|
||||
return default_value;
|
||||
}
|
||||
|
||||
try {
|
||||
return std::stof(pair->second);
|
||||
} catch (const std::logic_error&) {
|
||||
LOG_ERROR(Common, "failed to convert %s to float", pair->second.c_str());
|
||||
NGLOG_ERROR(Common, "failed to convert {} to float", pair->second);
|
||||
return default_value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2005-2012 Gekko Emulator
|
||||
*
|
||||
* @file platform.h
|
||||
* @author ShizZy <shizzy247@gmail.com>
|
||||
* @date 2012-02-11
|
||||
* @brief Platform detection macros for portable compilation
|
||||
*
|
||||
* @section LICENSE
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details at
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*
|
||||
* Official project repository can be found at:
|
||||
* http://code.google.com/p/gekko-gc-emu/
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Platform detection
|
||||
|
||||
#if defined(ARCHITECTURE_x86_64) || defined(__aarch64__)
|
||||
#define EMU_ARCH_BITS 64
|
||||
#elif defined(__i386) || defined(_M_IX86) || defined(__arm__) || defined(_M_ARM)
|
||||
#define EMU_ARCH_BITS 32
|
||||
#endif
|
||||
@@ -107,7 +107,7 @@ std::string StringFromFormat(const char* format, ...) {
|
||||
#else
|
||||
va_start(args, format);
|
||||
if (vasprintf(&buf, format, args) < 0)
|
||||
LOG_ERROR(Common, "Unable to allocate memory for string");
|
||||
NGLOG_ERROR(Common, "Unable to allocate memory for string");
|
||||
va_end(args);
|
||||
|
||||
std::string temp = buf;
|
||||
@@ -347,7 +347,7 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>&
|
||||
|
||||
iconv_t const conv_desc = iconv_open("UTF-8", fromcode);
|
||||
if ((iconv_t)(-1) == conv_desc) {
|
||||
LOG_ERROR(Common, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno));
|
||||
NGLOG_ERROR(Common, "Iconv initialization failure [{}]: {}", fromcode, strerror(errno));
|
||||
iconv_close(conv_desc);
|
||||
return {};
|
||||
}
|
||||
@@ -376,7 +376,7 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>&
|
||||
++src_buffer;
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR(Common, "iconv failure [%s]: %s", fromcode, strerror(errno));
|
||||
NGLOG_ERROR(Common, "iconv failure [{}]: {}", fromcode, strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -395,7 +395,7 @@ std::u16string UTF8ToUTF16(const std::string& input) {
|
||||
|
||||
iconv_t const conv_desc = iconv_open("UTF-16LE", "UTF-8");
|
||||
if ((iconv_t)(-1) == conv_desc) {
|
||||
LOG_ERROR(Common, "Iconv initialization failure [UTF-8]: %s", strerror(errno));
|
||||
NGLOG_ERROR(Common, "Iconv initialization failure [UTF-8]: {}", strerror(errno));
|
||||
iconv_close(conv_desc);
|
||||
return {};
|
||||
}
|
||||
@@ -424,7 +424,7 @@ std::u16string UTF8ToUTF16(const std::string& input) {
|
||||
++src_buffer;
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR(Common, "iconv failure [UTF-8]: %s", strerror(errno));
|
||||
NGLOG_ERROR(Common, "iconv failure [UTF-8]: {}", strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -462,4 +462,27 @@ std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_l
|
||||
|
||||
return std::string(buffer, len);
|
||||
}
|
||||
|
||||
const char* TrimSourcePath(const char* path, const char* root) {
|
||||
const char* p = path;
|
||||
|
||||
while (*p != '\0') {
|
||||
const char* next_slash = p;
|
||||
while (*next_slash != '\0' && *next_slash != '/' && *next_slash != '\\') {
|
||||
++next_slash;
|
||||
}
|
||||
|
||||
bool is_src = Common::ComparePartialString(p, next_slash, root);
|
||||
p = next_slash;
|
||||
|
||||
if (*p != '\0') {
|
||||
++p;
|
||||
}
|
||||
if (is_src) {
|
||||
path = p;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -134,4 +134,17 @@ bool ComparePartialString(InIt begin, InIt end, const char* other) {
|
||||
* NUL-terminated then the string ends at max_len characters.
|
||||
*/
|
||||
std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len);
|
||||
|
||||
/**
|
||||
* Attempts to trim an arbitrary prefix from `path`, leaving only the part starting at `root`. It's
|
||||
* intended to be used to strip a system-specific build directory from the `__FILE__` macro,
|
||||
* leaving only the path relative to the sources root.
|
||||
*
|
||||
* @param path The input file path as a null-terminated string
|
||||
* @param root The name of the root source directory as a null-terminated string. Path up to and
|
||||
* including the last occurrence of this name will be stripped
|
||||
* @return A pointer to the same string passed as `path`, but starting at the trimmed portion
|
||||
*/
|
||||
const char* TrimSourcePath(const char* path, const char* root = "src");
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -103,7 +103,19 @@ inline __attribute__((always_inline)) u64 swap64(u64 _data) {
|
||||
return __builtin_bswap64(_data);
|
||||
}
|
||||
#elif defined(__Bitrig__) || defined(__OpenBSD__)
|
||||
// swap16, swap32, swap64 are left as is
|
||||
// redefine swap16, swap32, swap64 as inline functions
|
||||
#undef swap16
|
||||
#undef swap32
|
||||
#undef swap64
|
||||
inline u16 swap16(u16 _data) {
|
||||
return __swap16(_data);
|
||||
}
|
||||
inline u32 swap32(u32 _data) {
|
||||
return __swap32(_data);
|
||||
}
|
||||
inline u64 swap64(u64 _data) {
|
||||
return __swap64(_data);
|
||||
}
|
||||
#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
inline u16 swap16(u16 _data) {
|
||||
return bswap16(_data);
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Telemetry {
|
||||
/// Field type, used for grouping fields together in the final submitted telemetry log
|
||||
enum class FieldType : u8 {
|
||||
None = 0, ///< No specified field group
|
||||
App, ///< Citra application fields (e.g. version, branch, etc.)
|
||||
App, ///< yuzu application fields (e.g. version, branch, etc.)
|
||||
Session, ///< Emulated session fields (e.g. title ID, log, etc.)
|
||||
Performance, ///< Emulated performance (e.g. fps, emulated CPU speed, etc.)
|
||||
UserFeedback, ///< User submitted feedback (e.g. star rating, user notes, etc.)
|
||||
|
||||
@@ -11,25 +11,6 @@
|
||||
#include <thread>
|
||||
#include "common/common_types.h"
|
||||
|
||||
// Support for C++11's thread_local keyword was surprisingly spotty in compilers until very
|
||||
// recently. Fortunately, thread local variables have been well supported for compilers for a while,
|
||||
// but with semantics supporting only POD types, so we can use a few defines to get some amount of
|
||||
// backwards compat support.
|
||||
// WARNING: This only works correctly with POD types.
|
||||
#if defined(__clang__)
|
||||
#if !__has_feature(cxx_thread_local)
|
||||
#define thread_local __thread
|
||||
#endif
|
||||
#elif defined(__GNUC__)
|
||||
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)
|
||||
#define thread_local __thread
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#if _MSC_VER < 1900
|
||||
#define thread_local __declspec(thread)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace Common {
|
||||
|
||||
int CurrentThreadId();
|
||||
|
||||
@@ -55,10 +55,6 @@ public:
|
||||
T x;
|
||||
T y;
|
||||
|
||||
T* AsArray() {
|
||||
return &x;
|
||||
}
|
||||
|
||||
Vec2() = default;
|
||||
Vec2(const T& _x, const T& _y) : x(_x), y(_y) {}
|
||||
|
||||
@@ -71,11 +67,6 @@ public:
|
||||
return Vec2<T>(f, f);
|
||||
}
|
||||
|
||||
void Write(T a[2]) {
|
||||
a[0] = x;
|
||||
a[1] = y;
|
||||
}
|
||||
|
||||
Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
|
||||
return MakeVec(x + other.x, y + other.y);
|
||||
}
|
||||
@@ -205,10 +196,6 @@ public:
|
||||
T y;
|
||||
T z;
|
||||
|
||||
T* AsArray() {
|
||||
return &x;
|
||||
}
|
||||
|
||||
Vec3() = default;
|
||||
Vec3(const T& _x, const T& _y, const T& _z) : x(_x), y(_y), z(_z) {}
|
||||
|
||||
@@ -225,12 +212,6 @@ public:
|
||||
return MakeVec(f, f, f);
|
||||
}
|
||||
|
||||
void Write(T a[3]) {
|
||||
a[0] = x;
|
||||
a[1] = y;
|
||||
a[2] = z;
|
||||
}
|
||||
|
||||
Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
|
||||
return MakeVec(x + other.x, y + other.y, z + other.z);
|
||||
}
|
||||
@@ -416,10 +397,6 @@ public:
|
||||
T z;
|
||||
T w;
|
||||
|
||||
T* AsArray() {
|
||||
return &x;
|
||||
}
|
||||
|
||||
Vec4() = default;
|
||||
Vec4(const T& _x, const T& _y, const T& _z, const T& _w) : x(_x), y(_y), z(_z), w(_w) {}
|
||||
|
||||
@@ -436,13 +413,6 @@ public:
|
||||
return Vec4<T>(f, f, f, f);
|
||||
}
|
||||
|
||||
void Write(T a[4]) {
|
||||
a[0] = x;
|
||||
a[1] = y;
|
||||
a[2] = z;
|
||||
a[3] = w;
|
||||
}
|
||||
|
||||
Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
|
||||
return MakeVec(x + other.x, y + other.y, z + other.z, w + other.w);
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ static CPUCaps Detect() {
|
||||
caps.num_cores = std::thread::hardware_concurrency();
|
||||
|
||||
// Assumes the CPU supports the CPUID instruction. Those that don't would likely not support
|
||||
// Citra at all anyway
|
||||
// yuzu at all anyway
|
||||
|
||||
int cpu_id[4];
|
||||
memset(caps.brand_string, 0, sizeof(caps.brand_string));
|
||||
|
||||
@@ -12,6 +12,8 @@ add_library(core STATIC
|
||||
file_sys/errors.h
|
||||
file_sys/filesystem.cpp
|
||||
file_sys/filesystem.h
|
||||
file_sys/partition_filesystem.cpp
|
||||
file_sys/partition_filesystem.h
|
||||
file_sys/path_parser.cpp
|
||||
file_sys/path_parser.h
|
||||
file_sys/program_metadata.cpp
|
||||
@@ -22,6 +24,8 @@ add_library(core STATIC
|
||||
file_sys/romfs_filesystem.h
|
||||
file_sys/savedata_factory.cpp
|
||||
file_sys/savedata_factory.h
|
||||
file_sys/sdmc_factory.cpp
|
||||
file_sys/sdmc_factory.h
|
||||
file_sys/storage.h
|
||||
frontend/emu_window.cpp
|
||||
frontend/emu_window.h
|
||||
@@ -38,8 +42,6 @@ add_library(core STATIC
|
||||
hle/kernel/client_port.h
|
||||
hle/kernel/client_session.cpp
|
||||
hle/kernel/client_session.h
|
||||
hle/kernel/condition_variable.cpp
|
||||
hle/kernel/condition_variable.h
|
||||
hle/kernel/errors.h
|
||||
hle/kernel/event.cpp
|
||||
hle/kernel/event.h
|
||||
@@ -86,8 +88,14 @@ add_library(core STATIC
|
||||
hle/romfs.h
|
||||
hle/service/acc/acc.cpp
|
||||
hle/service/acc/acc.h
|
||||
hle/service/acc/acc_aa.cpp
|
||||
hle/service/acc/acc_aa.h
|
||||
hle/service/acc/acc_su.cpp
|
||||
hle/service/acc/acc_su.h
|
||||
hle/service/acc/acc_u0.cpp
|
||||
hle/service/acc/acc_u0.h
|
||||
hle/service/acc/acc_u1.cpp
|
||||
hle/service/acc/acc_u1.h
|
||||
hle/service/am/am.cpp
|
||||
hle/service/am/am.h
|
||||
hle/service/am/applet_ae.cpp
|
||||
@@ -128,6 +136,8 @@ add_library(core STATIC
|
||||
hle/service/friend/friend.h
|
||||
hle/service/friend/friend_a.cpp
|
||||
hle/service/friend/friend_a.h
|
||||
hle/service/friend/friend_u.cpp
|
||||
hle/service/friend/friend_u.h
|
||||
hle/service/hid/hid.cpp
|
||||
hle/service/hid/hid.h
|
||||
hle/service/lm/lm.cpp
|
||||
@@ -140,6 +150,10 @@ add_library(core STATIC
|
||||
hle/service/nifm/nifm_s.h
|
||||
hle/service/nifm/nifm_u.cpp
|
||||
hle/service/nifm/nifm_u.h
|
||||
hle/service/nfp/nfp.cpp
|
||||
hle/service/nfp/nfp.h
|
||||
hle/service/nfp/nfp_user.cpp
|
||||
hle/service/nfp/nfp_user.h
|
||||
hle/service/ns/ns.cpp
|
||||
hle/service/ns/ns.h
|
||||
hle/service/ns/pl_u.cpp
|
||||
@@ -167,10 +181,12 @@ add_library(core STATIC
|
||||
hle/service/nvflinger/buffer_queue.h
|
||||
hle/service/nvflinger/nvflinger.cpp
|
||||
hle/service/nvflinger/nvflinger.h
|
||||
hle/service/pctl/module.cpp
|
||||
hle/service/pctl/module.h
|
||||
hle/service/pctl/pctl.cpp
|
||||
hle/service/pctl/pctl.h
|
||||
hle/service/pctl/pctl_a.cpp
|
||||
hle/service/pctl/pctl_a.h
|
||||
hle/service/prepo/prepo.cpp
|
||||
hle/service/prepo/prepo.h
|
||||
hle/service/service.cpp
|
||||
hle/service/service.h
|
||||
hle/service/set/set.cpp
|
||||
@@ -187,12 +203,22 @@ add_library(core STATIC
|
||||
hle/service/sm/controller.h
|
||||
hle/service/sm/sm.cpp
|
||||
hle/service/sm/sm.h
|
||||
hle/service/sockets/bsd_u.cpp
|
||||
hle/service/sockets/bsd_u.h
|
||||
hle/service/sockets/bsd.cpp
|
||||
hle/service/sockets/bsd.h
|
||||
hle/service/sockets/nsd.cpp
|
||||
hle/service/sockets/nsd.h
|
||||
hle/service/sockets/sfdnsres.cpp
|
||||
hle/service/sockets/sfdnsres.h
|
||||
hle/service/sockets/sockets.cpp
|
||||
hle/service/sockets/sockets.h
|
||||
hle/service/spl/csrng.cpp
|
||||
hle/service/spl/csrng.h
|
||||
hle/service/spl/module.cpp
|
||||
hle/service/spl/module.h
|
||||
hle/service/spl/spl.cpp
|
||||
hle/service/spl/spl.h
|
||||
hle/service/ssl/ssl.cpp
|
||||
hle/service/ssl/ssl.h
|
||||
hle/service/time/time.cpp
|
||||
hle/service/time/time.h
|
||||
hle/service/time/time_s.cpp
|
||||
|
||||
@@ -55,8 +55,8 @@ public:
|
||||
}
|
||||
|
||||
void InterpreterFallback(u64 pc, size_t num_instructions) override {
|
||||
LOG_INFO(Core_ARM, "Unicorn fallback @ 0x%" PRIx64 " for %zu instructions (instr = %08x)",
|
||||
pc, num_instructions, MemoryReadCode(pc));
|
||||
NGLOG_INFO(Core_ARM, "Unicorn fallback @ {:#X} for {} instructions (instr = {:08X})", pc,
|
||||
num_instructions, MemoryReadCode(pc));
|
||||
|
||||
ARM_Interface::ThreadContext ctx;
|
||||
parent.SaveContext(ctx);
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
case Dynarmic::A64::Exception::Yield:
|
||||
return;
|
||||
default:
|
||||
ASSERT_MSG(false, "ExceptionRaised(exception = %zu, pc = %" PRIx64 ")",
|
||||
ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:X})",
|
||||
static_cast<size_t>(exception), pc);
|
||||
}
|
||||
}
|
||||
@@ -86,21 +86,17 @@ public:
|
||||
}
|
||||
|
||||
void AddTicks(u64 ticks) override {
|
||||
if (ticks > ticks_remaining) {
|
||||
ticks_remaining = 0;
|
||||
return;
|
||||
}
|
||||
ticks -= ticks_remaining;
|
||||
CoreTiming::AddTicks(ticks - num_interpreted_instructions);
|
||||
num_interpreted_instructions = 0;
|
||||
}
|
||||
u64 GetTicksRemaining() override {
|
||||
return ticks_remaining;
|
||||
return std::max(CoreTiming::GetDowncount(), 0);
|
||||
}
|
||||
u64 GetCNTPCT() override {
|
||||
return CoreTiming::GetTicks();
|
||||
}
|
||||
|
||||
ARM_Dynarmic& parent;
|
||||
size_t ticks_remaining = 0;
|
||||
size_t num_interpreted_instructions = 0;
|
||||
u64 tpidrro_el0 = 0;
|
||||
u64 tpidr_el0 = 0;
|
||||
|
||||
@@ -30,7 +30,7 @@ LoadDll LoadDll::g_load_dll;
|
||||
#define CHECKED(expr) \
|
||||
do { \
|
||||
if (auto _cerr = (expr)) { \
|
||||
ASSERT_MSG(false, "Call " #expr " failed with error: %u (%s)\n", _cerr, \
|
||||
ASSERT_MSG(false, "Call " #expr " failed with error: {} ({})\n", _cerr, \
|
||||
uc_strerror(_cerr)); \
|
||||
} \
|
||||
} while (0)
|
||||
@@ -53,7 +53,7 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si
|
||||
void* user_data) {
|
||||
ARM_Interface::ThreadContext ctx{};
|
||||
Core::CPU().SaveContext(ctx);
|
||||
ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x%lx, pc=0x%lx, lr=0x%lx", addr,
|
||||
ASSERT_MSG(false, "Attempted to read from unmapped memory: {:#X}, pc={:#X}, lr={:#X}", addr,
|
||||
ctx.pc, ctx.cpu_registers[30]);
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -12,10 +12,13 @@
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sm/controller.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/hw/hw.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/memory_setup.h"
|
||||
@@ -26,6 +29,8 @@ namespace Core {
|
||||
|
||||
/*static*/ System System::s_instance;
|
||||
|
||||
System::~System() = default;
|
||||
|
||||
System::ResultStatus System::RunLoop(bool tight_loop) {
|
||||
status = ResultStatus::Success;
|
||||
if (!cpu_core) {
|
||||
@@ -50,7 +55,7 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
|
||||
// If we don't have a currently active thread then don't execute instructions,
|
||||
// instead advance to the next event and try to yield to the next thread
|
||||
if (Kernel::GetCurrentThread() == nullptr) {
|
||||
LOG_TRACE(Core_ARM, "Idling");
|
||||
NGLOG_TRACE(Core_ARM, "Idling");
|
||||
CoreTiming::Idle();
|
||||
CoreTiming::Advance();
|
||||
PrepareReschedule();
|
||||
@@ -77,21 +82,23 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
|
||||
app_loader = Loader::GetLoader(filepath);
|
||||
|
||||
if (!app_loader) {
|
||||
LOG_CRITICAL(Core, "Failed to obtain loader for %s!", filepath.c_str());
|
||||
NGLOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
|
||||
return ResultStatus::ErrorGetLoader;
|
||||
}
|
||||
std::pair<boost::optional<u32>, Loader::ResultStatus> system_mode =
|
||||
app_loader->LoadKernelSystemMode();
|
||||
|
||||
if (system_mode.second != Loader::ResultStatus::Success) {
|
||||
LOG_CRITICAL(Core, "Failed to determine system mode (Error %i)!",
|
||||
static_cast<int>(system_mode.second));
|
||||
NGLOG_CRITICAL(Core, "Failed to determine system mode (Error {})!",
|
||||
static_cast<int>(system_mode.second));
|
||||
|
||||
switch (system_mode.second) {
|
||||
case Loader::ResultStatus::ErrorEncrypted:
|
||||
return ResultStatus::ErrorLoader_ErrorEncrypted;
|
||||
case Loader::ResultStatus::ErrorInvalidFormat:
|
||||
return ResultStatus::ErrorLoader_ErrorInvalidFormat;
|
||||
case Loader::ResultStatus::ErrorUnsupportedArch:
|
||||
return ResultStatus::ErrorUnsupportedArch;
|
||||
default:
|
||||
return ResultStatus::ErrorSystemMode;
|
||||
}
|
||||
@@ -99,15 +106,15 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
|
||||
|
||||
ResultStatus init_result{Init(emu_window, system_mode.first.get())};
|
||||
if (init_result != ResultStatus::Success) {
|
||||
LOG_CRITICAL(Core, "Failed to initialize system (Error %i)!",
|
||||
static_cast<int>(init_result));
|
||||
NGLOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
|
||||
static_cast<int>(init_result));
|
||||
System::Shutdown();
|
||||
return init_result;
|
||||
}
|
||||
|
||||
const Loader::ResultStatus load_result{app_loader->Load(current_process)};
|
||||
if (Loader::ResultStatus::Success != load_result) {
|
||||
LOG_CRITICAL(Core, "Failed to load ROM (Error %i)!", static_cast<int>(load_result));
|
||||
NGLOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result));
|
||||
System::Shutdown();
|
||||
|
||||
switch (load_result) {
|
||||
@@ -115,6 +122,8 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
|
||||
return ResultStatus::ErrorLoader_ErrorEncrypted;
|
||||
case Loader::ResultStatus::ErrorInvalidFormat:
|
||||
return ResultStatus::ErrorLoader_ErrorInvalidFormat;
|
||||
case Loader::ResultStatus::ErrorUnsupportedArch:
|
||||
return ResultStatus::ErrorUnsupportedArch;
|
||||
default:
|
||||
return ResultStatus::ErrorLoader;
|
||||
}
|
||||
@@ -142,42 +151,40 @@ void System::Reschedule() {
|
||||
}
|
||||
|
||||
System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
|
||||
LOG_DEBUG(HW_Memory, "initialized OK");
|
||||
NGLOG_DEBUG(HW_Memory, "initialized OK");
|
||||
|
||||
CoreTiming::Init();
|
||||
|
||||
current_process = Kernel::Process::Create("main");
|
||||
|
||||
switch (Settings::values.cpu_core) {
|
||||
case Settings::CpuCore::Unicorn:
|
||||
cpu_core = std::make_shared<ARM_Unicorn>();
|
||||
break;
|
||||
case Settings::CpuCore::Dynarmic:
|
||||
default:
|
||||
if (Settings::values.use_cpu_jit) {
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
cpu_core = std::make_shared<ARM_Dynarmic>();
|
||||
#else
|
||||
cpu_core = std::make_shared<ARM_Unicorn>();
|
||||
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
|
||||
NGLOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
|
||||
#endif
|
||||
break;
|
||||
} else {
|
||||
cpu_core = std::make_shared<ARM_Unicorn>();
|
||||
}
|
||||
|
||||
gpu_core = std::make_unique<Tegra::GPU>();
|
||||
|
||||
telemetry_session = std::make_unique<Core::TelemetrySession>();
|
||||
|
||||
service_manager = std::make_shared<Service::SM::ServiceManager>();
|
||||
|
||||
HW::Init();
|
||||
Kernel::Init(system_mode);
|
||||
scheduler = std::make_unique<Kernel::Scheduler>(cpu_core.get());
|
||||
Service::Init();
|
||||
Service::Init(service_manager);
|
||||
GDBStub::Init();
|
||||
|
||||
if (!VideoCore::Init(emu_window)) {
|
||||
return ResultStatus::ErrorVideoCore;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Core, "Initialized OK");
|
||||
NGLOG_DEBUG(Core, "Initialized OK");
|
||||
|
||||
// Reset counters and set time origin to current frame
|
||||
GetAndResetPerfStats();
|
||||
@@ -200,17 +207,26 @@ void System::Shutdown() {
|
||||
VideoCore::Shutdown();
|
||||
GDBStub::Shutdown();
|
||||
Service::Shutdown();
|
||||
scheduler = nullptr;
|
||||
scheduler.reset();
|
||||
Kernel::Shutdown();
|
||||
HW::Shutdown();
|
||||
telemetry_session = nullptr;
|
||||
gpu_core = nullptr;
|
||||
cpu_core = nullptr;
|
||||
service_manager.reset();
|
||||
telemetry_session.reset();
|
||||
gpu_core.reset();
|
||||
cpu_core.reset();
|
||||
CoreTiming::Shutdown();
|
||||
|
||||
app_loader = nullptr;
|
||||
app_loader.reset();
|
||||
|
||||
LOG_DEBUG(Core, "Shutdown OK");
|
||||
NGLOG_DEBUG(Core, "Shutdown OK");
|
||||
}
|
||||
|
||||
Service::SM::ServiceManager& System::ServiceManager() {
|
||||
return *service_manager;
|
||||
}
|
||||
|
||||
const Service::SM::ServiceManager& System::ServiceManager() const {
|
||||
return *service_manager;
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||