Compare commits
100 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d915a0b945 | ||
|
|
ac9c5eaae9 | ||
|
|
0891da303c | ||
|
|
55e9b51faa | ||
|
|
55dc0ade47 | ||
|
|
2cf7083718 | ||
|
|
15df532d68 | ||
|
|
884d2302a9 | ||
|
|
bacdfd6018 | ||
|
|
dc7a3bbbd3 | ||
|
|
ff0d791783 | ||
|
|
a3d8a0dde0 | ||
|
|
a8c908d113 | ||
|
|
01849d5305 | ||
|
|
23968d3e2b | ||
|
|
7246a64ae5 | ||
|
|
729e050adb | ||
|
|
003452fbbb | ||
|
|
419b6bd0a3 | ||
|
|
668c3d9a08 | ||
|
|
9a6f878051 | ||
|
|
50fc750154 | ||
|
|
9fe8235eda | ||
|
|
f7b9c48998 | ||
|
|
17bf27c018 | ||
|
|
80ca5ea5fd | ||
|
|
3afa9ca403 | ||
|
|
842190e15e | ||
|
|
717775d9ab | ||
|
|
a19bb91041 | ||
|
|
a545982a28 | ||
|
|
2109df04ca | ||
|
|
f485cf8ebc | ||
|
|
bb48110f95 | ||
|
|
718adda749 | ||
|
|
a170c7ccb1 | ||
|
|
fec3fe3b6b | ||
|
|
00f19c9777 | ||
|
|
93aae28593 | ||
|
|
8be2b907b3 | ||
|
|
fcca07765b | ||
|
|
559e4e75eb | ||
|
|
8ae84614d5 | ||
|
|
18a7e8b22c | ||
|
|
01120f6120 | ||
|
|
07be6bb5ae | ||
|
|
39b4905ef1 | ||
|
|
6c49a5aa9d | ||
|
|
aaeff2ea0f | ||
|
|
cd48e78667 | ||
|
|
f2ab4e840e | ||
|
|
9a476f8283 | ||
|
|
8e24ad724c | ||
|
|
c70aba2ca5 | ||
|
|
c6a20961b8 | ||
|
|
4741354883 | ||
|
|
a3051f5d58 | ||
|
|
730207e75b | ||
|
|
27e067889d | ||
|
|
22c9433c1c | ||
|
|
c6b558cb3d | ||
|
|
a6d5598c08 | ||
|
|
13ee2abeef | ||
|
|
ca9c841477 | ||
|
|
0dbae3c46c | ||
|
|
045bcbc7da | ||
|
|
9f98e28b08 | ||
|
|
59dfbae9b4 | ||
|
|
3f0250957b | ||
|
|
73595d93f3 | ||
|
|
19b8755c89 | ||
|
|
14aad730de | ||
|
|
6c7eec5778 | ||
|
|
2c5ce5763a | ||
|
|
b568e1387a | ||
|
|
85bd46e457 | ||
|
|
bd4a77992e | ||
|
|
a8750ce8ad | ||
|
|
4e8887c80b | ||
|
|
c38a0cdec9 | ||
|
|
6f961edcb1 | ||
|
|
bdd9f30404 | ||
|
|
f94d5faaf2 | ||
|
|
c1ffd93f28 | ||
|
|
05bf7af859 | ||
|
|
eae359a3b8 | ||
|
|
2156906341 | ||
|
|
e7bd669362 | ||
|
|
17ac5b5e06 | ||
|
|
671cc753b5 | ||
|
|
fd81b47413 | ||
|
|
710b07a857 | ||
|
|
5b93d2642b | ||
|
|
38d792fd97 | ||
|
|
fed266f5ac | ||
|
|
a547d10ab9 | ||
|
|
4cc6043737 | ||
|
|
0a42313b6f | ||
|
|
0b53f541d1 | ||
|
|
ddd17b18d7 |
4
.github/ISSUE_TEMPLATE/emu_bug_report.yaml
vendored
@@ -66,10 +66,6 @@ body:
|
||||
|
||||
Performance issues as a result of not meeting our hardware requirements are not valid.
|
||||
|
||||
Please read our known issues pages for AMD and Intel drivers.
|
||||
- [Intel Drivers](https://github.com/PCSX2/pcsx2/wiki/OpenGL-and-Intel-GPUs-All-you-need-to-know).
|
||||
- [AMD Drivers](https://github.com/PCSX2/pcsx2/wiki/OpenGL-and-AMD-GPUs---All-you-need-to-know).
|
||||
|
||||
We are **not** accepting issues related to the **libretro** core. The libretro core is being maintained separately at this time
|
||||
- type: input
|
||||
id: rev
|
||||
|
||||
8
.github/workflows/linux_build_flatpak.yml
vendored
@@ -96,7 +96,7 @@ jobs:
|
||||
|
||||
- name: Build Flatpak (beta)
|
||||
if: ${{ inputs.stableBuild == false || inputs.stableBuild == 'false' }}
|
||||
uses: flathub-infra/flatpak-github-actions/flatpak-builder@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
|
||||
uses: flatpak/flatpak-github-actions/flatpak-builder@10a3c29f0162516f0f68006be14c92f34bd4fa6c
|
||||
with:
|
||||
bundle: ${{ steps.artifact-metadata.outputs.artifact-name }}.flatpak
|
||||
upload-artifact: false
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
|
||||
- name: Build Flatpak (stable)
|
||||
if: ${{ inputs.stableBuild == true || inputs.stableBuild == 'true' }}
|
||||
uses: flathub-infra/flatpak-github-actions/flatpak-builder@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
|
||||
uses: flatpak/flatpak-github-actions/flatpak-builder@10a3c29f0162516f0f68006be14c92f34bd4fa6c
|
||||
with:
|
||||
bundle: ${{ steps.artifact-metadata.outputs.artifact-name }}.flatpak
|
||||
upload-artifact: false
|
||||
@@ -132,7 +132,7 @@ jobs:
|
||||
|
||||
- name: Push to Flathub (beta)
|
||||
if: ${{ inputs.publish == true && (inputs.stableBuild == false || inputs.stableBuild == 'false') }}
|
||||
uses: flathub-infra/flatpak-github-actions/flat-manager@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
|
||||
uses: flatpak/flatpak-github-actions/flatpak-builder@10a3c29f0162516f0f68006be14c92f34bd4fa6c
|
||||
with:
|
||||
flat-manager-url: https://hub.flathub.org/
|
||||
repository: beta
|
||||
@@ -141,7 +141,7 @@ jobs:
|
||||
|
||||
- name: Push to Flathub (stable)
|
||||
if: ${{ inputs.publish == true && (inputs.stableBuild == true || inputs.stableBuild == 'true') }}
|
||||
uses: flathub-infra/flatpak-github-actions/flat-manager@23796715b3dfa4c86ddf50cf29c3cc8b3c82dca8
|
||||
uses: flatpak/flatpak-github-actions/flatpak-builder@10a3c29f0162516f0f68006be14c92f34bd4fa6c
|
||||
with:
|
||||
flat-manager-url: https://hub.flathub.org/
|
||||
repository: stable
|
||||
|
||||
411
.github/workflows/scripts/releases/generate-release-notes/package-lock.json
generated
vendored
@@ -9,123 +9,11 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@octokit/plugin-retry": "^3.0.9",
|
||||
"@octokit/plugin-throttling": "^3.5.2",
|
||||
"@octokit/plugin-throttling": "^9.6.0",
|
||||
"@octokit/rest": "^21.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/auth-token": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
|
||||
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/core": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.5.1.tgz",
|
||||
"integrity": "sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^2.4.4",
|
||||
"@octokit/graphql": "^4.5.8",
|
||||
"@octokit/request": "^5.6.0",
|
||||
"@octokit/request-error": "^2.0.5",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"before-after-hook": "^2.2.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/endpoint": {
|
||||
"version": "6.0.12",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
|
||||
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/graphql": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
|
||||
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/request": "^5.6.0",
|
||||
"@octokit/types": "^6.0.3",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/openapi-types": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.1.0.tgz",
|
||||
"integrity": "sha512-dWZfYvCCdjZzDYA3lIAMF72Q0jld8xidqCq5Ryw09eBJXZdcM6he0vWBTvw/b5UnGYqexxOyHWgfrsTlUJL3Gw=="
|
||||
},
|
||||
"node_modules/@octokit/plugin-retry": {
|
||||
"version": "3.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-3.0.9.tgz",
|
||||
"integrity": "sha512-r+fArdP5+TG6l1Rv/C9hVoty6tldw6cE2pRHNGmFPdyfrc696R6JjrQ3d7HdVqGwuzfyrcaLAKD7K8TX8aehUQ==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"bottleneck": "^2.15.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-throttling": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-3.5.2.tgz",
|
||||
"integrity": "sha512-Eu7kfJxU8vmHqWGNszWpg+GVp2tnAfax3XQV5CkYPEE69C+KvInJXW9WajgSeW+cxYe0UVdouzCtcreGNuJo7A==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.1",
|
||||
"bottleneck": "^2.15.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": "^3.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request": {
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.2.tgz",
|
||||
"integrity": "sha512-je66CvSEVf0jCpRISxkUcCa0UkxmFs6eGDRSbfJtAVwbLH5ceqF+YEyC8lj8ystKyZTy8adWr0qmkY52EfOeLA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/endpoint": "^6.0.1",
|
||||
"@octokit/request-error": "^2.1.0",
|
||||
"@octokit/types": "^6.16.1",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"node-fetch": "^2.6.1",
|
||||
"universal-user-agent": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request-error": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
|
||||
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"deprecation": "^2.0.0",
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-21.1.1.tgz",
|
||||
"integrity": "sha512-sTQV7va0IUVZcntzy1q3QqPm/r8rWtDCqpRAmb8eXXnKkjoQEtFe3Nt5GTVsHft+R6jJoHeSiVLcgcvhtue/rg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/core": "^6.1.4",
|
||||
"@octokit/plugin-paginate-rest": "^11.4.2",
|
||||
"@octokit/plugin-request-log": "^5.3.1",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^13.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/auth-token": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.2.tgz",
|
||||
"integrity": "sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw==",
|
||||
@@ -134,7 +22,7 @@
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/core": {
|
||||
"node_modules/@octokit/core": {
|
||||
"version": "6.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.4.tgz",
|
||||
"integrity": "sha512-lAS9k7d6I0MPN+gb9bKDt7X8SdxknYqAMh44S5L+lNqIN2NuV8nvv3g8rPp7MuRxcOpxpUIATWprO0C34a8Qmg==",
|
||||
@@ -152,7 +40,22 @@
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/endpoint": {
|
||||
"node_modules/@octokit/core/node_modules/@octokit/openapi-types": {
|
||||
"version": "24.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
||||
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/core/node_modules/@octokit/types": {
|
||||
"version": "13.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
||||
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^24.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/endpoint": {
|
||||
"version": "10.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.3.tgz",
|
||||
"integrity": "sha512-nBRBMpKPhQUxCsQQeW+rCJ/OPSMcj3g0nfHn01zGYZXuNDvvXudF/TYY6APj5THlurerpFN4a/dQAIAaM6BYhA==",
|
||||
@@ -165,7 +68,22 @@
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/graphql": {
|
||||
"node_modules/@octokit/endpoint/node_modules/@octokit/openapi-types": {
|
||||
"version": "24.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
||||
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/endpoint/node_modules/@octokit/types": {
|
||||
"version": "13.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
||||
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^24.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/graphql": {
|
||||
"version": "8.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-8.2.1.tgz",
|
||||
"integrity": "sha512-n57hXtOoHrhwTWdvhVkdJHdhTv0JstjDbDRhJfwIRNfFqmSo1DaK/mD2syoNUoLCyqSjBpGAKOG0BuwF392slw==",
|
||||
@@ -179,6 +97,139 @@
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/graphql/node_modules/@octokit/openapi-types": {
|
||||
"version": "24.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
||||
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/graphql/node_modules/@octokit/types": {
|
||||
"version": "13.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
||||
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^24.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/openapi-types": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.1.0.tgz",
|
||||
"integrity": "sha512-dWZfYvCCdjZzDYA3lIAMF72Q0jld8xidqCq5Ryw09eBJXZdcM6he0vWBTvw/b5UnGYqexxOyHWgfrsTlUJL3Gw=="
|
||||
},
|
||||
"node_modules/@octokit/plugin-retry": {
|
||||
"version": "3.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-3.0.9.tgz",
|
||||
"integrity": "sha512-r+fArdP5+TG6l1Rv/C9hVoty6tldw6cE2pRHNGmFPdyfrc696R6JjrQ3d7HdVqGwuzfyrcaLAKD7K8TX8aehUQ==",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^6.0.3",
|
||||
"bottleneck": "^2.15.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-throttling": {
|
||||
"version": "9.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-9.6.0.tgz",
|
||||
"integrity": "sha512-zn7m1N3vpJDaVzLqjCRdJ0cRzNiekHEWPi8Ww9xyPNrDt5PStHvVE0eR8wy4RSU8Eg7YO8MHyvn6sv25EGVhhg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^13.7.0",
|
||||
"bottleneck": "^2.15.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@octokit/core": "^6.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/plugin-throttling/node_modules/@octokit/openapi-types": {
|
||||
"version": "24.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
||||
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/plugin-throttling/node_modules/@octokit/types": {
|
||||
"version": "13.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
||||
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^24.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request": {
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.2.2.tgz",
|
||||
"integrity": "sha512-dZl0ZHx6gOQGcffgm1/Sf6JfEpmh34v3Af2Uci02vzUYz6qEN6zepoRtmybWXIGXFIK8K9ylE3b+duCWqhArtg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/endpoint": "^10.1.3",
|
||||
"@octokit/request-error": "^6.1.7",
|
||||
"@octokit/types": "^13.6.2",
|
||||
"fast-content-type-parse": "^2.0.0",
|
||||
"universal-user-agent": "^7.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request-error": {
|
||||
"version": "6.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.7.tgz",
|
||||
"integrity": "sha512-69NIppAwaauwZv6aOzb+VVLwt+0havz9GT5YplkeJv7fG7a40qpLt/yZKyiDxAhgz0EtgNdNcb96Z0u+Zyuy2g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^13.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request-error/node_modules/@octokit/openapi-types": {
|
||||
"version": "24.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
||||
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/request-error/node_modules/@octokit/types": {
|
||||
"version": "13.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
||||
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^24.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/request/node_modules/@octokit/openapi-types": {
|
||||
"version": "24.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
|
||||
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@octokit/request/node_modules/@octokit/types": {
|
||||
"version": "13.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
|
||||
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/openapi-types": "^24.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-21.1.1.tgz",
|
||||
"integrity": "sha512-sTQV7va0IUVZcntzy1q3QqPm/r8rWtDCqpRAmb8eXXnKkjoQEtFe3Nt5GTVsHft+R6jJoHeSiVLcgcvhtue/rg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/core": "^6.1.4",
|
||||
"@octokit/plugin-paginate-rest": "^11.4.2",
|
||||
"@octokit/plugin-request-log": "^5.3.1",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^13.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/openapi-types": {
|
||||
"version": "23.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
|
||||
@@ -227,34 +278,6 @@
|
||||
"@octokit/core": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/request": {
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.2.2.tgz",
|
||||
"integrity": "sha512-dZl0ZHx6gOQGcffgm1/Sf6JfEpmh34v3Af2Uci02vzUYz6qEN6zepoRtmybWXIGXFIK8K9ylE3b+duCWqhArtg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/endpoint": "^10.1.3",
|
||||
"@octokit/request-error": "^6.1.7",
|
||||
"@octokit/types": "^13.6.2",
|
||||
"fast-content-type-parse": "^2.0.0",
|
||||
"universal-user-agent": "^7.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/request-error": {
|
||||
"version": "6.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.7.tgz",
|
||||
"integrity": "sha512-69NIppAwaauwZv6aOzb+VVLwt+0havz9GT5YplkeJv7fG7a40qpLt/yZKyiDxAhgz0EtgNdNcb96Z0u+Zyuy2g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@octokit/types": "^13.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/@octokit/types": {
|
||||
"version": "13.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
|
||||
@@ -264,18 +287,6 @@
|
||||
"@octokit/openapi-types": "^23.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/before-after-hook": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz",
|
||||
"integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@octokit/rest/node_modules/universal-user-agent": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz",
|
||||
"integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/@octokit/types": {
|
||||
"version": "6.33.0",
|
||||
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.33.0.tgz",
|
||||
@@ -285,22 +296,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/before-after-hook": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
|
||||
"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==",
|
||||
"peer": true
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz",
|
||||
"integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/bottleneck": {
|
||||
"version": "2.19.5",
|
||||
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
|
||||
"integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="
|
||||
},
|
||||
"node_modules/deprecation": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
|
||||
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/fast-content-type-parse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz",
|
||||
@@ -317,77 +322,11 @@
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/universal-user-agent": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
|
||||
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"peer": true
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz",
|
||||
"integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==",
|
||||
"license": "ISC"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@octokit/plugin-retry": "^3.0.9",
|
||||
"@octokit/plugin-throttling": "^3.5.2",
|
||||
"@octokit/plugin-throttling": "^9.6.0",
|
||||
"@octokit/rest": "^21.1.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1749,7 +1749,7 @@
|
||||
- hashes:
|
||||
- md5: f95ea9eb021181b888229df60ba8effd
|
||||
size: 2159050752
|
||||
name: Shadow the Hedgehog (Europe, Australia) (En,Fr,De,Es,It)
|
||||
name: Shadow the Hedgehog (Europe, Australia) (En,Ja,Fr,De,Es,It)
|
||||
serial: SLES-53542
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
@@ -8524,7 +8524,7 @@
|
||||
- hashes:
|
||||
- md5: ce030f48dcb588682902b5a569baa24e
|
||||
size: 4677795840
|
||||
name: 007 - Quantum of Solace (USA)
|
||||
name: 007 - Quantum of Solace (USA) (En,Fr)
|
||||
serial: SLUS-21813
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -8620,7 +8620,7 @@
|
||||
- hashes:
|
||||
- md5: c15a1707d1c89728e0c596b97ba91b27
|
||||
size: 4313153536
|
||||
name: Official PlayStation 2 Magazine Sonderausgabe 2004-3 (Germany) (En,Fr,De,Es,It)
|
||||
name: Official PlayStation 2 Magazine - Special Edition 2004-03 (Germany) (En,Fr,De,Es,It)
|
||||
serial: SCED-52997
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -8854,7 +8854,7 @@
|
||||
- hashes:
|
||||
- md5: fab56e6f617b0a64ad35221341bd167c
|
||||
size: 3529965568
|
||||
name: Rock Band - Metal Track Pack (USA)
|
||||
name: Rock Band - Metal Track Pack (USA, Canada)
|
||||
serial: SLUS-21889
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -9753,7 +9753,7 @@
|
||||
- hashes:
|
||||
- md5: 63d3e8e5da0305650160bc50f46df87b
|
||||
size: 4033478656
|
||||
name: Fight Night Round 3 (Europe) (En,Fr)
|
||||
name: Fight Night Round 3 (Europe, Australia) (En,Fr)
|
||||
serial: SLES-53982
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -13331,7 +13331,7 @@
|
||||
- hashes:
|
||||
- md5: aac303724ce688c8f242245ea0f4b9e4
|
||||
size: 877953024
|
||||
name: Tokyo Bus Guide - Kyou kara Kimi mo Untenshu (Japan)
|
||||
name: SuperLite 2000 Vol. 5 - Tokyo Bus Guide - Kyou kara Kimi mo Untenshu (Japan)
|
||||
serial: SLPM-65032
|
||||
version: '1.04'
|
||||
- hashes:
|
||||
@@ -15880,7 +15880,7 @@
|
||||
- hashes:
|
||||
- md5: 29e5cf458549ca5321dd0c12619a002b
|
||||
size: 3846504448
|
||||
name: Bakugan - Battle Brawlers (USA)
|
||||
name: Bakugan - Battle Brawlers (USA) (En,Fr)
|
||||
serial: SLUS-21902
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -20525,7 +20525,7 @@
|
||||
- hashes:
|
||||
- md5: 2e7fcee5a1333b72eef8a18c7a673e9f
|
||||
size: 8539766784
|
||||
name: Guitar Hero - Metallica (USA)
|
||||
name: Guitar Hero - Metallica (USA) (En,Fr)
|
||||
serial: SLUS-21843
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -20868,7 +20868,7 @@
|
||||
- hashes:
|
||||
- md5: 35d939b30458790cf58ddd16ef11e159
|
||||
size: 697149264
|
||||
name: Online Start-Up Disc 4.0 - Broadband Only (USA)
|
||||
name: Online Start-Up Disc 4.0 - Broadband Only (USA) (v1.02)
|
||||
serial: PBPX-95248
|
||||
version: '1.02'
|
||||
- hashes:
|
||||
@@ -21320,8 +21320,7 @@
|
||||
- hashes:
|
||||
- md5: 4f18266ee64804fc1ba858c5d5bee759
|
||||
size: 3782836224
|
||||
name: Official PlayStation 2 Magazine Germany Special Edition 01-2004 (Germany)
|
||||
(En,Fr,De,Es,It)
|
||||
name: Official PlayStation 2 Magazine - Special Edition 2004-01 (Germany) (En,Fr,De,Es,It)
|
||||
serial: SCED-52119
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
@@ -21764,7 +21763,7 @@
|
||||
- hashes:
|
||||
- md5: e6159c29d23cd03252e94823045b4ff8
|
||||
size: 4071424000
|
||||
name: DJ Hero (USA)
|
||||
name: DJ Hero (USA) (En,Fr)
|
||||
serial: SLUS-21909
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -22190,7 +22189,7 @@
|
||||
- hashes:
|
||||
- md5: 007f0ccc933f59b65f28c72ad227843d
|
||||
size: 4580573184
|
||||
name: Score International Baja 1000 - World Championship Off Road Racing (Europe)
|
||||
name: SCORE International Baja 1000 - World Championship Off Road Racing (Europe)
|
||||
serial: SLES-55295
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -22862,7 +22861,7 @@
|
||||
- hashes:
|
||||
- md5: cadce0add00903396577b5d53cff1929
|
||||
size: 4679565312
|
||||
name: Marvel Super Hero Squad (USA)
|
||||
name: Marvel Super Hero Squad (USA) (En,Fr,Es)
|
||||
serial: SLUS-21910
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -22946,7 +22945,7 @@
|
||||
- hashes:
|
||||
- md5: 77ae418d710142291b5d6eb5d5d904d1
|
||||
size: 3007021056
|
||||
name: Buzz! The Schools Quiz (Europe)
|
||||
name: Buzz! The Schools Quiz (UK) (v2.00)
|
||||
serial: SCES-54941
|
||||
version: '2.00'
|
||||
- hashes:
|
||||
@@ -30411,7 +30410,7 @@
|
||||
- hashes:
|
||||
- md5: 01abdbe56de95af5b5379cf7fea1bec0
|
||||
size: 3683680256
|
||||
name: Ratchet & Clank 2 - Gagaga! Ginga no Commando-ssu (Japan, Asia)
|
||||
name: Ratchet & Clank 2 - Gagaga! Ginga no Commando ssu (Japan, Asia)
|
||||
serial: SCAJ-20052
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -32035,7 +32034,7 @@
|
||||
- hashes:
|
||||
- md5: 47e03c7b246239330d5e41efb5160fda
|
||||
size: 1328939008
|
||||
name: Nickelodeon Bob L'eponge - Silence on Tourne! (France)
|
||||
name: Nickelodeon Bob L'eponge - Silence on Tourne ! (France)
|
||||
serial: SLES-53495
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -33603,19 +33602,19 @@
|
||||
- hashes:
|
||||
- md5: ac71dddc4a60475a689fcb6f1836e607
|
||||
size: 4307582976
|
||||
name: Buzz! The Big Quiz (Europe) (En,Fr,Nl)
|
||||
name: Buzz! The Big Quiz (Belgium, Netherlands) (En,Fr,Nl)
|
||||
serial: SCES-53925
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 0f457023f2a436d38a0cd53599115846
|
||||
size: 4611080192
|
||||
name: Buzz! The Mega Quiz (Europe) (En,Fr,Nl)
|
||||
name: Buzz! The Mega Quiz (Belgium, Netherlands) (En,Fr,Nl)
|
||||
serial: SCES-54505
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 409302dffc2512d1ccd2227d17ff6bf2
|
||||
size: 4688314368
|
||||
name: Buzz! The Pop Quiz (Europe) (En,Fr,Nl)
|
||||
name: Buzz! The Pop Quiz (Belgium, Netherlands) (En,Fr,Nl)
|
||||
serial: SCES-55098
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -34577,7 +34576,7 @@
|
||||
- hashes:
|
||||
- md5: 4703eb006c9921927145c878acd7324c
|
||||
size: 3536748544
|
||||
name: Buzz! The Sports Quiz (Europe) (En,Fr,Nl)
|
||||
name: Buzz! The Sports Quiz (Belgium, Netherlands) (En,Fr,Nl)
|
||||
serial: SCES-54265
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -36547,7 +36546,7 @@
|
||||
- hashes:
|
||||
- md5: fa7523e49dc9825589504430857c5c25
|
||||
size: 564202464
|
||||
name: LEGO Island Xtreme Stunts (USA)
|
||||
name: Island Xtreme Stunts (USA)
|
||||
serial: SLUS-20575
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
@@ -38437,7 +38436,7 @@
|
||||
- hashes:
|
||||
- md5: 06553f511a16b8cc0396bab31cc910a6
|
||||
size: 2924576768
|
||||
name: DreamWorks Madagascar - Escape 2 Africa (USA)
|
||||
name: DreamWorks Madagascar - Escape 2 Africa (USA) (En,Fr)
|
||||
serial: SLUS-21840
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
@@ -39061,7 +39060,7 @@
|
||||
- hashes:
|
||||
- md5: cc5e862a633532654176096888dfacba
|
||||
size: 2679865344
|
||||
name: PES 2011 - Pro Evolution Soccer (USA)
|
||||
name: PES 2011 - Pro Evolution Soccer (USA) (En,Fr,Es,Pt)
|
||||
serial: SLUS-21942
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -39355,7 +39354,7 @@
|
||||
- hashes:
|
||||
- md5: 298ad8520c82f4edbaacb3194bc46d5c
|
||||
size: 3530391552
|
||||
name: PES 2010 - Pro Evolution Soccer (USA)
|
||||
name: PES 2010 - Pro Evolution Soccer (USA) (En,Fr,Es,Pt)
|
||||
serial: SLUS-21918
|
||||
version: '1.02'
|
||||
- hashes:
|
||||
@@ -39421,7 +39420,7 @@
|
||||
- hashes:
|
||||
- md5: 491a3f6a39ce290de2f6dbb9ba98575f
|
||||
size: 2129297408
|
||||
name: PES 2013 - Pro Evolution Soccer (USA)
|
||||
name: PES 2013 - Pro Evolution Soccer (USA) (En,Fr,Es,Pt)
|
||||
serial: SLUS-21955
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -39433,7 +39432,7 @@
|
||||
- hashes:
|
||||
- md5: b2d139590f169442a46d21ed2f8558ab
|
||||
size: 2437316608
|
||||
name: PES 2012 - Pro Evolution Soccer (USA)
|
||||
name: PES 2012 - Pro Evolution Soccer (USA) (En,Fr,Es,Pt)
|
||||
serial: SLUS-21948
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -39511,7 +39510,7 @@
|
||||
- hashes:
|
||||
- md5: 6821bded97877694e8cf4ccf9ca64ad4
|
||||
size: 4659347456
|
||||
name: Vitamin Z - Welcome Our New Supplement Boys (Japan) (Genteiban)
|
||||
name: VitaminZ - Welcome Our New Supplement Boys (Japan) (Genteiban)
|
||||
serial: SLPS-25922
|
||||
version: '1.02'
|
||||
- hashes:
|
||||
@@ -39770,7 +39769,7 @@
|
||||
- hashes:
|
||||
- md5: 6f2533c2ae433f1beac4f1aa3a88f4c6
|
||||
size: 4588797952
|
||||
name: AND 1 Streetball (USA) (v1.03)
|
||||
name: AND 1 Streetball (USA) (En,Fr,Es) (v1.03)
|
||||
serial: SLUS-21237
|
||||
version: '1.03'
|
||||
- hashes:
|
||||
@@ -39902,7 +39901,7 @@
|
||||
- hashes:
|
||||
- md5: 2d3dd4cd0d8c16e97a1a887b70349658
|
||||
size: 4636672000
|
||||
name: Score International Baja 1000 - The Official Game (USA)
|
||||
name: SCORE International Baja 1000 - The Official Game (USA)
|
||||
serial: SLUS-21850
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -40463,7 +40462,7 @@
|
||||
- md5: 08a63db4f248acdc24cdaa0b9507b854
|
||||
size: 2205908992
|
||||
name: Umishou (Japan)
|
||||
serial: SLPM-66864
|
||||
serial: FVGK-0001
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
- md5: d3b19450aea4a9688e876fa71830aa77
|
||||
@@ -40745,7 +40744,7 @@
|
||||
- hashes:
|
||||
- md5: 9be1477e6c0bd67bb6aff3a02601b4a6
|
||||
size: 1534427136
|
||||
name: Freaky Flyers (USA) (Demo)
|
||||
name: Freaky Flyers (USA) (Demo) (Rev 1)
|
||||
serial: SLUS-29061
|
||||
version: '0.30'
|
||||
- hashes:
|
||||
@@ -41497,7 +41496,7 @@
|
||||
- hashes:
|
||||
- md5: 6dc613680039ba59d20f8baa61e56fc5
|
||||
size: 739706352
|
||||
name: Momotarou Dentetsu 11 - Black Bombee Shutsugen! no Maki (Japan)
|
||||
name: Momotarou Dentetsu 11 - Black Bonby Shutsugen! no Maki (Japan)
|
||||
serial: SLPM-62475
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
@@ -44241,7 +44240,7 @@
|
||||
- md5: 34d981b3883eaeb95c82fbed14dcad26
|
||||
size: 3115188224
|
||||
name: Harukanaru Toki no Naka de 3 (Japan) (History Box)
|
||||
serial: SLPM-66005
|
||||
serial: SLPM-65849
|
||||
version: '1.02'
|
||||
- hashes:
|
||||
- md5: d8ecac6d03a601d4a81f1389bfe25962
|
||||
@@ -45207,13 +45206,13 @@
|
||||
- hashes:
|
||||
- md5: 29a454ebd230549939654022af5db917
|
||||
size: 4107206656
|
||||
name: Vitamin X - We are Super Supriment Boys (Japan)
|
||||
name: VitaminX - We are Super Supriment Boys (Japan)
|
||||
serial: SLPS-25761
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
- md5: 19cc959d502b7eebae156ee760731454
|
||||
size: 4659347456
|
||||
name: Vitamin Z - Welcome Our New Supplement Boys (Japan)
|
||||
name: VitaminZ - Welcome Our New Supplement Boys (Japan)
|
||||
serial: SLPS-25923
|
||||
version: '1.02'
|
||||
- hashes:
|
||||
@@ -46244,7 +46243,7 @@
|
||||
- hashes:
|
||||
- md5: ecb21ce06339ab6b628e077f3c03690b
|
||||
size: 3962535936
|
||||
name: Suigetsu - Mayoi Gokoro (Japan)
|
||||
name: Suigetsu - Mayoigokoro (Japan)
|
||||
serial: SLPM-65751
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
@@ -47270,7 +47269,7 @@
|
||||
- hashes:
|
||||
- md5: 68634f9b74fe47e4a039ada615970ca1
|
||||
size: 541969008
|
||||
name: Momotarou Dentetsu 15 - Godai Bombee Toujou! no Maki (Japan) (v2.00)
|
||||
name: Momotarou Dentetsu 15 - Godai Bonby Toujou! no Maki (Japan) (v2.00)
|
||||
serial: SLPM-74104
|
||||
version: '2.00'
|
||||
- hashes:
|
||||
@@ -49343,8 +49342,7 @@
|
||||
- hashes:
|
||||
- md5: 72e49d4201496dea3e0851abf58098cf
|
||||
size: 4677992448
|
||||
name: Official PlayStation 2 Magazine Germany Special Edition 2003-01 (Germany)
|
||||
(En,De)
|
||||
name: Official PlayStation 2 Magazine - Special Edition 2003-01 (Germany) (En,De)
|
||||
serial: SCED-51512
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -49422,7 +49420,7 @@
|
||||
- hashes:
|
||||
- md5: aa26f473fc9ecf2df7fad3a9acc30351
|
||||
size: 3115188224
|
||||
name: Harukanaru Toki no Naka de 3 (Japan) (Triple Pack)
|
||||
name: Harukanaru Toki no Naka de 3 (Japan) (Premium Box)
|
||||
serial: SLPM-65850
|
||||
version: '1.02'
|
||||
- hashes:
|
||||
@@ -51309,12 +51307,6 @@
|
||||
name: Magazine Ufficiale PlayStation 2 Demo Italia 05-2006 (Italy) (En,Fr,De,Es,It)
|
||||
serial: SCED-54180
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 0b14951eb38e4f5f4730bcf48bf64898
|
||||
size: 4569923584
|
||||
name: Magazine Ufficiale PlayStation 2 Italia 05-04 (Italy) (En,Fr,De,Es,It)
|
||||
serial: SCED-52443
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 771bfe48ce1a10c8a638da8bedc9acf6
|
||||
size: 4175429632
|
||||
@@ -51698,13 +51690,13 @@
|
||||
- hashes:
|
||||
- md5: cf45002cd37168e4a2b3a8f96c560941
|
||||
size: 3983638528
|
||||
name: Official PlayStation 2 Magazine Germany Special 2-2005 (Germany)
|
||||
name: Official PlayStation 2 Magazine - Special Edition 2005-02 (Germany)
|
||||
serial: SCED-53662
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 8191fa8441cd8c947ab80b9db6de0ce3
|
||||
size: 4583129088
|
||||
name: Official PlayStation 2 Magazine Germany Special 3-2005 (Germany)
|
||||
name: Official PlayStation 2 Magazine - Special Edition 2005-03 (Germany)
|
||||
serial: SCED-53938
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -51818,7 +51810,7 @@
|
||||
- hashes:
|
||||
- md5: 8e18b5399008416a7d012f2ea1bf9353
|
||||
size: 663976656
|
||||
name: Pro Evolution Soccer 3 (Europe) (Demo 1)
|
||||
name: Pro Evolution Soccer 3 (UK) (Demo)
|
||||
serial: SLED-51992
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -51950,7 +51942,7 @@
|
||||
- hashes:
|
||||
- md5: 209c4247ffb84795b23ce2cec0f090a4
|
||||
size: 3793453056
|
||||
name: Official PlayStation 2 Magazine Germany Special Edition 2003-03 (Germany)
|
||||
name: Official PlayStation 2 Magazine - Special Edition 2003-03 (Germany)
|
||||
serial: SCED-51551
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -52038,7 +52030,7 @@
|
||||
- hashes:
|
||||
- md5: e8e5b428c642c78d510cbd854c17b9cc
|
||||
size: 1616740352
|
||||
name: Primal + The Mark of Kri + War of the Monsters (Europe) (En,Fr,De,Es,It)
|
||||
name: Primal & The Mark of Kri & War of the Monsters (Europe) (En,Fr,De,Es,It)
|
||||
serial: SCED-51506
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -52350,7 +52342,7 @@
|
||||
- hashes:
|
||||
- md5: d42eed1d14cdaf8add8295116776a447
|
||||
size: 3765108736
|
||||
name: Best PS2 Games Ever 10 (Europe)
|
||||
name: Official PlayStation 2 Magazine-UK Special Edition - Yearbook 2002 (Europe)
|
||||
serial: SCED-51389
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -52637,7 +52629,7 @@
|
||||
- hashes:
|
||||
- md5: cded45ee044b5a7614644fa444a59989
|
||||
size: 4334157824
|
||||
name: Official PlayStation 2 Magazine Germany Special Edition 2003-02 (Germany)
|
||||
name: Official PlayStation 2 Magazine - Special Edition 2003-02 (Germany)
|
||||
serial: SCED-51549
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
@@ -53111,7 +53103,7 @@
|
||||
- hashes:
|
||||
- md5: f309b4b48dc775dbbde635a1ef3b662b
|
||||
size: 4522639360
|
||||
name: Germany Special Issue 3 (Germany)
|
||||
name: Official PlayStation 2 Magazine - Special Edition 3 (Germany)
|
||||
serial: SCED-51375
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -54054,7 +54046,7 @@
|
||||
- hashes:
|
||||
- md5: ac5b76bd39b0cabd1acfe4dcb08df502
|
||||
size: 1649803264
|
||||
name: Primal + The Mark of Kri (Europe)
|
||||
name: Primal & The Mark of Kri (Europe)
|
||||
serial: SCED-51491
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -54085,7 +54077,7 @@
|
||||
- hashes:
|
||||
- md5: 2475b61666f06dc2aa9ca032f15a4cde
|
||||
size: 4241293312
|
||||
name: Official PlayStation 2 Magazine Germany Special Edition 2007-1 (Germany)
|
||||
name: Official PlayStation 2 Magazine - Special Edition 2007-01 (Germany)
|
||||
serial: SCED-54693
|
||||
version: '1.02'
|
||||
- hashes:
|
||||
@@ -54462,7 +54454,7 @@
|
||||
- hashes:
|
||||
- md5: 97a9156abd199f588d4f46e9af7ab5a7
|
||||
size: 4107206656
|
||||
name: Vitamin X - We are Super Supriment Boys (Japan) (Genteiban)
|
||||
name: VitaminX - We are Super Supriment Boys (Japan) (Genteiban)
|
||||
serial: SLPS-25760
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
@@ -54767,7 +54759,7 @@
|
||||
- hashes:
|
||||
- md5: a4b5b1d6c13c15bc1bac6fc63622c9ee
|
||||
size: 2925920256
|
||||
name: Ever 17 - The Out of Infinity Premium Edition (Japan)
|
||||
name: Ever 17 - The Out of Infinity - Premium Edition (Japan)
|
||||
serial: SLPM-65421
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
@@ -55910,7 +55902,7 @@
|
||||
- hashes:
|
||||
- md5: 05b210d50d92a418ac1e37a1fff0df8a
|
||||
size: 243996480
|
||||
name: Giant Robo - The Animation - Chikyuu ga Seishi suru Hi (Japan)
|
||||
name: Giant Robo - The Animation - Chikyuu ga Seishi Suru Hi (Japan)
|
||||
serial: SLPM-62526
|
||||
version: '1.02'
|
||||
- hashes:
|
||||
@@ -56111,7 +56103,7 @@
|
||||
- hashes:
|
||||
- md5: 45d62f1cf862b8e6c47d373a5c55d2f2
|
||||
size: 708511776
|
||||
name: Pro Evolution Soccer 4 (Europe) (Demo)
|
||||
name: Pro Evolution Soccer 4 (UK) (Demo)
|
||||
serial: SLED-52873
|
||||
version: '1.02'
|
||||
- hashes:
|
||||
@@ -56171,7 +56163,7 @@
|
||||
- hashes:
|
||||
- md5: 139585af1bf276d5f2e17a32def4f66d
|
||||
size: 4528504832
|
||||
name: Official PlayStation 2 Magazine Germany Special Edition 1 (Germany)
|
||||
name: Official PlayStation 2 Magazine - Special Edition 1 (Germany)
|
||||
serial: SCED-50780
|
||||
version: '1.10'
|
||||
- hashes:
|
||||
@@ -57668,7 +57660,7 @@
|
||||
- hashes:
|
||||
- md5: 1ce4a9368f7c6c73dcd983ad5f86f3eb
|
||||
size: 718702992
|
||||
name: MaxPlay (Europe) (Unl)
|
||||
name: Max Play (Europe) (Unl)
|
||||
version: 1.00 (European)
|
||||
- hashes:
|
||||
- md5: 8182f27cc5a0cac14da217e45861e49e
|
||||
@@ -57841,8 +57833,7 @@
|
||||
- hashes:
|
||||
- md5: 4fb718d2059a1843882a70b17922b483
|
||||
size: 4613996544
|
||||
name: Official PlayStation 2 Magazine Germany Special Edition 2005-01 (Germany)
|
||||
(En,De)
|
||||
name: Official PlayStation 2 Magazine - Special Edition 2005-01 (Germany) (En,De)
|
||||
serial: SCED-53298
|
||||
version: '1.02'
|
||||
- hashes:
|
||||
@@ -57854,7 +57845,7 @@
|
||||
- hashes:
|
||||
- md5: 739a2f519751c64f7291d036105c2c0d
|
||||
size: 1670316032
|
||||
name: Buzz! Junior - Robojam (Europe) (Beta) (2007-01-12)
|
||||
name: Buzz! Junior - RoboJam (Europe) (Beta) (2007-01-12)
|
||||
serial: SCES-54676
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -58392,7 +58383,7 @@
|
||||
- hashes:
|
||||
- md5: 6969a8f3623387131e2e1d49fff4c3f5
|
||||
size: 4492853248
|
||||
name: Magical Tale - Chiicha na Mahoutsukai (Japan)
|
||||
name: Magical Tale - Chitcha na Mahoutsukai (Japan)
|
||||
serial: SLPM-65965
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
@@ -59340,7 +59331,7 @@
|
||||
- hashes:
|
||||
- md5: 8d61b97a6dd45165b012b338d42e53a8
|
||||
size: 2358018048
|
||||
name: Harry Potter and the Prisoner of Azkaban (Korea)
|
||||
name: Harry Potter-wa Azkaban-ui Joesu (Korea)
|
||||
serial: SLKA-25172
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
@@ -59646,7 +59637,7 @@
|
||||
- hashes:
|
||||
- md5: 1162e6411d9e16fbefc9fd8a9e886d70
|
||||
size: 4412145664
|
||||
name: Official PlayStation 2 Magazine Germany Winter 2006 (Germany) (En,De)
|
||||
name: Official PlayStation 2 Magazine - Winter 2006 (Germany) (En,De)
|
||||
serial: SCED-54558
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -60504,7 +60495,7 @@
|
||||
- hashes:
|
||||
- md5: 78f327cd6c0f2bd6f99a299e982b9a93
|
||||
size: 1253867520
|
||||
name: TOCA Race Driver 3 + V8 Supercars Australia 3 (Australia) (Demo)
|
||||
name: TOCA Race Driver 3 (Australia) (Demo)
|
||||
serial: SLED-53888
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -60764,7 +60755,7 @@
|
||||
- hashes:
|
||||
- md5: 7e964b27119adc590228452d42c634b0
|
||||
size: 4614062080
|
||||
name: Buzz! Hollywood Quiz (Europe) (En,Fr,Nl)
|
||||
name: Buzz! Hollywood Quiz (Belgium, Netherlands) (En,Fr,Nl)
|
||||
serial: SCES-54854
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -62041,7 +62032,7 @@
|
||||
- hashes:
|
||||
- md5: dd5ccdc3e325716d7f7ed08a9836f3f0
|
||||
size: 3938189312
|
||||
name: PlayStation 2 Revista Oficial - Portugal 9 (Portugal)
|
||||
name: Official PlayStation 2 Magazine Demo 32 (Portugal)
|
||||
serial: SCED-51657
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -62487,7 +62478,7 @@
|
||||
- hashes:
|
||||
- md5: fe79ea717184a278802679ef78f6df7b
|
||||
size: 7774928896
|
||||
name: Zhen San Guo Wu Shuang 5 Special (Taiwan)
|
||||
name: Zhen Sanguo Wushuang 5 Special (Taiwan)
|
||||
serial: SLAJ-35007
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -63024,7 +63015,7 @@
|
||||
- hashes:
|
||||
- md5: 18e6281d238ccb19e8975d45e8c157f0
|
||||
size: 3816554496
|
||||
name: Offizielle PlayStation 2 Magazin 02-2004, Das - Uncut Edition (Germany)
|
||||
name: Official PlayStation 2 Magazine 02-2004 - Uncut Edition (Germany)
|
||||
serial: SCED-52082
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
@@ -63141,7 +63132,7 @@
|
||||
- hashes:
|
||||
- md5: d38ab694e14843f16af11a15d1883023
|
||||
size: 4677795840
|
||||
name: Koi suru Otome to Shugo no Tate - The Shield of AIGIS (Japan)
|
||||
name: Koi Suru Otome to Shugo no Tate - The Shield of AIGIS (Japan)
|
||||
serial: SLPM-55098
|
||||
version: '1.02'
|
||||
- hashes:
|
||||
@@ -63554,7 +63545,7 @@
|
||||
- hashes:
|
||||
- md5: 3acdf0ae8cc67fe9e0db9f4707cb3905
|
||||
size: 2638381056
|
||||
name: I Love Baseball - Pro Yakyuu o Koyonaku Ai suru Hitotachi e (Japan)
|
||||
name: I Love Baseball - Pro Yakyuu o Koyonaku Ai Suru Hitotachi e (Japan)
|
||||
serial: SLPM-65633
|
||||
version: '1.04'
|
||||
- hashes:
|
||||
@@ -63941,13 +63932,13 @@
|
||||
- hashes:
|
||||
- md5: 7ea2da0f39ae55794fd9fd5006b417cc
|
||||
size: 4446388224
|
||||
name: Offizielle PlayStation 2 Magazin 09-2004, Das (Germany)
|
||||
name: Official PlayStation 2 Magazine 09-2004 (Germany)
|
||||
serial: SCED-52089
|
||||
version: '1.02'
|
||||
- hashes:
|
||||
- md5: 11b80bd02a0a874212b014c56e44a4c5
|
||||
size: 4033347584
|
||||
name: Offizielle PlayStation 2 Magazin 12-2003, Das (Germany)
|
||||
name: Official PlayStation Magazine 12-2003 (Germany)
|
||||
serial: SCED-51936
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -64181,7 +64172,7 @@
|
||||
- hashes:
|
||||
- md5: 8990d1c3b88b04b1bbc7a78ee3e9df2f
|
||||
size: 33821760
|
||||
name: Karat PS2-you Pro Action Replay 2 Taikenban (Japan) (Unl)
|
||||
name: Karat PS2-you Pro Action Replay 2 Taikenban (Japan) (Unl) (Rev 1)
|
||||
version: '1.7'
|
||||
- hashes:
|
||||
- md5: 4a2754811946ef9badbbd872f541a03f
|
||||
@@ -64254,7 +64245,7 @@
|
||||
- hashes:
|
||||
- md5: 0e35e8fd22fe57f8727b9764685bbc29
|
||||
size: 3871703040
|
||||
name: Offizielle PlayStation 2 Magazin, Das - Special Edition 2 (Germany)
|
||||
name: Official PlayStation 2 Magazine - Special Edition 2 (Germany)
|
||||
serial: SCED-51161
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -64563,7 +64554,7 @@
|
||||
- hashes:
|
||||
- md5: 477eb508b08f59386478908e481eb8a1
|
||||
size: 4519690240
|
||||
name: Official PlayStation 2 Magazine - German Kids Special (Germany) (En,De)
|
||||
name: Official PlayStation 2 Magazine - Kids Special (Germany) (En,De)
|
||||
serial: SCED-53611
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -64580,7 +64571,7 @@
|
||||
- hashes:
|
||||
- md5: ac9cb481855792415314e06e5c12b291
|
||||
size: 664183632
|
||||
name: Pro Evolution Soccer 3 (Europe) (Demo 2)
|
||||
name: Pro Evolution Soccer 3 (Europe) (Demo)
|
||||
serial: SLED-51994
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -65185,7 +65176,7 @@
|
||||
- hashes:
|
||||
- md5: 86af0c99c8a8566e5f9307110f339e20
|
||||
size: 364475328
|
||||
name: Monopoly - Mezase!! Daifugou Jinsei!! (Japan)
|
||||
name: Monopoly - Mezase!! Daifugou Jinsei!! (Japan) (v2.00)
|
||||
serial: SLPS-20281
|
||||
version: '2.00'
|
||||
- hashes:
|
||||
@@ -66352,7 +66343,7 @@
|
||||
- hashes:
|
||||
- md5: ff59d561b843dbbb940c631d53294d63
|
||||
size: 1552318464
|
||||
name: Monsterspass (Austria, Switzerland) (En,Fr,De,Es,It,Nl,Pt)
|
||||
name: Monsterspass (Austria) (En,Fr,De,Es,It,Nl,Pt)
|
||||
serial: SCES-54704
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -66436,7 +66427,7 @@
|
||||
- hashes:
|
||||
- md5: 79fc6bc53ff748088a36d2f6778d0a0b
|
||||
size: 1943797760
|
||||
name: Big! Sports Quiz, The (Austria, Switzerland)
|
||||
name: Big! Sports Quiz, The (Austria)
|
||||
serial: SCES-54526
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -66803,7 +66794,7 @@
|
||||
- hashes:
|
||||
- md5: 91450691bed8af904b291c4d86c0c338
|
||||
size: 1645182976
|
||||
name: Jungle Party (Austria, Switzerland)
|
||||
name: Jungle Party (Austria)
|
||||
serial: SCES-54524
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
@@ -66934,7 +66925,7 @@
|
||||
- hashes:
|
||||
- md5: 777cd430a73b95945cee679a27446eed
|
||||
size: 2297200640
|
||||
name: Disney-Pixar Finding Nemo (Korea)
|
||||
name: Disney-Pixar Nemo-reul Chajaseo (Korea)
|
||||
serial: SLKA-25056
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -68550,7 +68541,7 @@
|
||||
- hashes:
|
||||
- md5: 5b315096f6bfc1897e52fec9c877b81d
|
||||
size: 4250206208
|
||||
name: Offizielle PlayStation 2 Magazin 13-2003, Das - Uncut Edition (Germany)
|
||||
name: Official PlayStation 2 Magazine 13-2003 - Uncut Edition (Germany)
|
||||
serial: SCED-51937
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
@@ -69278,7 +69269,7 @@
|
||||
- hashes:
|
||||
- md5: 6905874bbb6167417bac324464d70d28
|
||||
size: 541969008
|
||||
name: Momotarou Dentetsu 15 - Godai Bombee Toujou! no Maki (Japan) (v1.01)
|
||||
name: Momotarou Dentetsu 15 - Godai Bonby Toujou! no Maki (Japan) (v1.01)
|
||||
serial: SLPM-62702
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
@@ -69326,7 +69317,7 @@
|
||||
- hashes:
|
||||
- md5: 950783ce0723d41ff7aa46659a6eafbc
|
||||
size: 4492853248
|
||||
name: Magical Tale - Chiicha na Mahoutsukai (Japan) (Shokai Genteiban)
|
||||
name: Magical Tale - Chitcha na Mahoutsukai (Japan) (Shokai Genteiban)
|
||||
serial: SLPM-65964
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
@@ -69341,3 +69332,240 @@
|
||||
name: Quilt - Anata to Tsumugu Yume to Koi no Dress (Japan)
|
||||
serial: SLPM-66735
|
||||
version: '1.02'
|
||||
- hashes:
|
||||
- md5: ad64473c57824cf607cf40a7d85cf36c
|
||||
size: 2300313600
|
||||
name: Guitar Hero (USA) (Demo)
|
||||
serial: SLUS-29177
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 667607deb941380aa4d13db387b93077
|
||||
size: 93254448
|
||||
name: Codes Exclusifs (France) (Unl)
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 589e37362d073b8ad52670cdd5664415
|
||||
size: 1822326784
|
||||
name: DearS (Japan) (Genteiban)
|
||||
serial: SLPS-25371
|
||||
version: '1.04'
|
||||
- hashes:
|
||||
- md5: 4afb874dc19e35051e79f7a881a584b4
|
||||
size: 1524793344
|
||||
name: Winning Post 6 - 2005-nendoban (Japan) (Premium Pack)
|
||||
serial: SLPM-65893
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
- md5: 132ce8a9e16ca7ef5a356aa111bce318
|
||||
size: 4354473984
|
||||
name: Jak 3 (Europe) (En,Fr,De,Es,It,Pt,Ko,Ru) (Beta) (2004-09-14)
|
||||
serial: SCES-52460
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 6432d610b89d00eb1eea2ee71cf27147
|
||||
size: 3007119360
|
||||
name: Buzz! The Schools Quiz (UK) (v1.00)
|
||||
serial: SCES-54941
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 3c47093b42a1e1a39692b220e7659ad9
|
||||
size: 4601774080
|
||||
name: Big! Pop Quiz, The (Austria)
|
||||
serial: SCES-55099
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 859073451dbb344df7cee32703245ed5
|
||||
size: 306380800
|
||||
name: Freaky Flyers (USA) (Demo)
|
||||
serial: SLUS-29051
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 8d987ddccb1e2ec4c068896a4182bc4c
|
||||
size: 1542029312
|
||||
name: Tennis no Oujisama - Smash Hit! 2 (Japan) (Shokai SP Genteiban C-Type)
|
||||
serial: SLPM-65453
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
- md5: b0a2a871249538d80b92e7ef837f20dd
|
||||
size: 761692848
|
||||
name: CD avec les Codes Action Replay Exclusivement pour le Jeu Enter the Matrix
|
||||
(France)
|
||||
version: 1.01 (European)
|
||||
- hashes:
|
||||
- md5: db0c13bd5bddb659d563b4e2c0fcd5e8
|
||||
size: 226549344
|
||||
name: Action Replay Ultimate Cheats for Use with Grand Theft Auto - Vice City (UK)
|
||||
(Unl)
|
||||
version: '1.30'
|
||||
- hashes:
|
||||
- md5: 7866eaffddb52bbf7375ab4deca20dd6
|
||||
size: 33821760
|
||||
name: Karat PS2-you Pro Action Replay 2 Taikenban (Japan) (Unl)
|
||||
version: '1.7'
|
||||
- hashes:
|
||||
- md5: 76b15475cac6977f2510ea07d9b87043
|
||||
size: 4348444672
|
||||
name: Official PlayStation 2 Magazine - Special Edition 2006-01 (Germany)
|
||||
serial: SCED-54034
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: c9f8be1699b50935c1e1989cd76bdbe1
|
||||
size: 697118688
|
||||
name: Online Start-Up Disc 4.0 - Broadband Only (USA) (v1.01)
|
||||
serial: PBPX-95248
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
- md5: d7cfe2da9a3598cb10bc61abd2657acd
|
||||
size: 3497885696
|
||||
name: Big! Movie Quiz, The (Austria)
|
||||
serial: SCES-54857
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 875894a624cc3d7bc81311985b5eeff7
|
||||
size: 549201408
|
||||
name: Argus-ui Jeonsa (Korea) (Cheheompan)
|
||||
serial: SCKA-90005
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 7f3b5e111ca4c77039a1641fe2785423
|
||||
size: 3271229440
|
||||
name: Mai-Otome HiME - Otome Butoushi!! (Japan) (Limited Edition)
|
||||
serial: SLPS-25680
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
- md5: 5626f8c491117a0924380c786ab7e458
|
||||
size: 3049783296
|
||||
name: Fire It Up Kids (Europe)
|
||||
serial: SCED-53678
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 7d6503407ba1ea104753be2bfe1283e3
|
||||
size: 2560065536
|
||||
name: Nickelodeon SpongeBob SquarePants - Movin' with Friends (Europe) (En,Fr,De,Es)
|
||||
(Beta) (2004-10-29)
|
||||
- hashes:
|
||||
- md5: baf280135d74603e097a813d52e25afa
|
||||
size: 707949648
|
||||
name: Pro Evolution Soccer 4 (Europe) (Demo)
|
||||
serial: SLED-52878
|
||||
version: '1.03'
|
||||
- hashes:
|
||||
- md5: 1fa77218061839d6ac9b39159fa46680
|
||||
size: 1249804288
|
||||
name: SingStar Rocks! (Europe) (Demo)
|
||||
serial: SCED-54086
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 2d91ab06f6fc0f918c9389990df71a63
|
||||
size: 1378156544
|
||||
name: This Is Football 2004 (Belgium) (Demo)
|
||||
serial: SCED-52321
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
- md5: 6917a832cf75177a18c4ef4499966ba4
|
||||
size: 3448471552
|
||||
name: Official PlayStation 2 Magazine Demo 10 (Spain)
|
||||
serial: SCED-50406
|
||||
- hashes:
|
||||
- md5: e1615a414d9b561e70b395155edb7e39
|
||||
size: 4697686016
|
||||
name: Chaos Legion (Europe) (Demo)
|
||||
serial: SLED-51808
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 670fabe932a7ad8b81f6356d162cdac6
|
||||
size: 4569923584
|
||||
name: Magazine Ufficiale PlayStation 2 Italia 05-04 (Italy) (En,Fr,De,Es,It)
|
||||
serial: SCED-52443
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: dd4dd82c735f0189b5cd91c0c5e4b327
|
||||
size: 364472976
|
||||
name: Monopoly - Mezase!! Daifugou Jinsei!! (Japan) (v1.04)
|
||||
serial: SLPS-20281
|
||||
version: '1.04'
|
||||
- hashes:
|
||||
- md5: 2be7a399436665d532383e9e6d21f7fb
|
||||
size: 1632665600
|
||||
name: Musashiden II - Blademaster (Japan) (Taikenban)
|
||||
serial: SLPM-61117
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 85f8dd4c84ac2fd97f4b154280c01910
|
||||
size: 1239580672
|
||||
name: Bratz - Rock Angelz (Denmark)
|
||||
serial: SLES-53578
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 36c27c981bfdd9f311ecc36da4ad7071
|
||||
size: 598507520
|
||||
name: Metal Gear Solid 2 - Sons of Liberty (Europe) (En,Fr,De) (Demo)
|
||||
serial: SLED-50782
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 626b946f71116a9ec455b41c0fb8aa3a
|
||||
size: 2710274048
|
||||
name: Bonus Demo 7 (15-16) (Europe)
|
||||
serial: SCED-52437
|
||||
version: '1.02'
|
||||
- hashes:
|
||||
- md5: 2696c838c64d0f7f0c86adc5bbc1f54a
|
||||
size: 4292870144
|
||||
name: Buzz! The Big Quiz (Switzerland) (Fr,De,It)
|
||||
serial: SCES-54071
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 865cb20ccc3b938879eb3cae955ab70c
|
||||
size: 4598398976
|
||||
name: Buzz! The Mega Quiz (Switzerland) (Fr,De,It)
|
||||
serial: SCES-54506
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: f543c17d10aa576cc4ea74622a7050ee
|
||||
size: 750130416
|
||||
name: Code Breaker (USA) (Unl) (v4.0)
|
||||
version: '4.0'
|
||||
- hashes:
|
||||
- md5: bae22925feb7587573b663cc83bc1eb3
|
||||
size: 2719285248
|
||||
name: Kaido Battle 2 - Chain Reaction (Korea)
|
||||
serial: SLKA-25146
|
||||
version: '1.02'
|
||||
- hashes:
|
||||
- md5: 92c7a59eb4650bbc8a429970640b871b
|
||||
size: 748700400
|
||||
name: Time Crisis II (Europe) (Demo)
|
||||
serial: SCED-50473
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
- md5: fd46dd639a28f9f8ec7475f999d8b653
|
||||
size: 2786852864
|
||||
name: Call of Duty - World at War - Final Fronts (Korea)
|
||||
serial: SLKA-25449
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 41ccada9d75b88b20adf6db41349df52
|
||||
size: 4511367168
|
||||
name: Shijag-ui Ilbo All Stars (Korea)
|
||||
serial: SLKA-25152
|
||||
version: '1.01'
|
||||
- hashes:
|
||||
- md5: d46987283a22024d4b8e3e36c597035f
|
||||
size: 4116643840
|
||||
name: Fight Night Round 2 (Europe, Australia) (Demo)
|
||||
serial: SLED-53126
|
||||
version: '1.00'
|
||||
- hashes:
|
||||
- md5: 22a1b12df6fae4ecd8da5bed8cd91dd6
|
||||
size: 4192600064
|
||||
name: SOCOM 3 - U.S. Navy SEALs (USA) (Beta) (2005-09-08)
|
||||
- hashes:
|
||||
- md5: 3a04c1e3548d8169271336a73ae67e93
|
||||
size: 566942544
|
||||
name: Taz - Wanted (Europe) (2002-01-29)
|
||||
version: Beta
|
||||
- hashes:
|
||||
- md5: ecb58db2de607ed68a215d052381a83b
|
||||
size: 245814576
|
||||
name: Taz - Wanted (Europe) (2001-05-31)
|
||||
version: Beta
|
||||
|
||||
BIN
bin/resources/fullscreenui/flags/NTSC-B.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
bin/resources/fullscreenui/flags/NTSC-C.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
bin/resources/fullscreenui/flags/NTSC-HK.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
bin/resources/fullscreenui/flags/NTSC-J.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
bin/resources/fullscreenui/flags/NTSC-K.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
bin/resources/fullscreenui/flags/NTSC-T.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
bin/resources/fullscreenui/flags/NTSC-U.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
bin/resources/fullscreenui/flags/Other.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
bin/resources/fullscreenui/flags/PAL-A.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
bin/resources/fullscreenui/flags/PAL-AF.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
bin/resources/fullscreenui/flags/PAL-AU.png
Normal file
|
After Width: | Height: | Size: 144 B |
BIN
bin/resources/fullscreenui/flags/PAL-BE.png
Normal file
|
After Width: | Height: | Size: 322 B |
BIN
bin/resources/fullscreenui/flags/PAL-E.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
bin/resources/fullscreenui/flags/PAL-F.png
Normal file
|
After Width: | Height: | Size: 261 B |
BIN
bin/resources/fullscreenui/flags/PAL-FI.png
Normal file
|
After Width: | Height: | Size: 334 B |
BIN
bin/resources/fullscreenui/flags/PAL-G.png
Normal file
|
After Width: | Height: | Size: 361 B |
BIN
bin/resources/fullscreenui/flags/PAL-GR.png
Normal file
|
After Width: | Height: | Size: 655 B |
BIN
bin/resources/fullscreenui/flags/PAL-I.png
Normal file
|
After Width: | Height: | Size: 247 B |
BIN
bin/resources/fullscreenui/flags/PAL-IN.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
bin/resources/fullscreenui/flags/PAL-M.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
bin/resources/fullscreenui/flags/PAL-NL.png
Normal file
|
After Width: | Height: | Size: 265 B |
BIN
bin/resources/fullscreenui/flags/PAL-NO.png
Normal file
|
After Width: | Height: | Size: 675 B |
BIN
bin/resources/fullscreenui/flags/PAL-P.png
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
bin/resources/fullscreenui/flags/PAL-PL.png
Normal file
|
After Width: | Height: | Size: 140 B |
BIN
bin/resources/fullscreenui/flags/PAL-R.png
Normal file
|
After Width: | Height: | Size: 265 B |
BIN
bin/resources/fullscreenui/flags/PAL-S.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
bin/resources/fullscreenui/flags/PAL-SC.png
Normal file
|
After Width: | Height: | Size: 587 B |
BIN
bin/resources/fullscreenui/flags/PAL-SW.png
Normal file
|
After Width: | Height: | Size: 331 B |
BIN
bin/resources/fullscreenui/flags/PAL-SWI.png
Normal file
|
After Width: | Height: | Size: 751 B |
BIN
bin/resources/fullscreenui/flags/PAL-UK.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
bin/resources/fullscreenui/star-0.png
Normal file
|
After Width: | Height: | Size: 296 B |
BIN
bin/resources/fullscreenui/star-1.png
Normal file
|
After Width: | Height: | Size: 442 B |
BIN
bin/resources/fullscreenui/star-2.png
Normal file
|
After Width: | Height: | Size: 534 B |
BIN
bin/resources/fullscreenui/star-3.png
Normal file
|
After Width: | Height: | Size: 505 B |
BIN
bin/resources/fullscreenui/star-4.png
Normal file
|
After Width: | Height: | Size: 442 B |
BIN
bin/resources/fullscreenui/star-5.png
Normal file
|
After Width: | Height: | Size: 297 B |
@@ -1478,13 +1478,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,platform:Linux,
|
||||
05000000010000000100000003000000,Nintendo Wii Remote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
050000007e0500003003000001000000,Nintendo Wii U Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
|
||||
050000005a1d00000218000003000000,Nokia GC 5000,a:b9,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
030000000d0500000308000010010000,Nostromo n45 Dual Analog,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,
|
||||
030000007e0500001920000011810000,NSO N64 Controller,+rightx:b10,+righty:b8,-rightx:b9,-righty:b7,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b3,lefttrigger:b2,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b4,righttrigger:b5,start:b6,platform:Linux,
|
||||
030000007e0500001920000011810000,NSO N64 Controller,+rightx:b2,+righty:b3,-rightx:b4,-righty:b10,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b7,righttrigger:b9,start:b11,platform:Linux,
|
||||
050000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Linux,
|
||||
050000007e0500001920000001800000,NSO N64 Controller,+rightx:b10,+righty:b8,-rightx:b9,-righty:b7,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b3,lefttrigger:b2,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b4,righttrigger:b5,start:b6,platform:Linux,
|
||||
030000007e0500001720000011810000,NSO SNES Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,
|
||||
050000007e0500001920000001800000,NSO N64 Controller,+rightx:b2,+righty:b3,-rightx:b4,-righty:b10,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b7,righttrigger:b9,start:b11,platform:Linux,
|
||||
030000007e0500001720000011810000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,
|
||||
050000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b8,start:b10,x:b3,y:b2,platform:Linux,
|
||||
050000007e0500001720000001800000,NSO SNES Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,
|
||||
050000007e0500001720000001800000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,
|
||||
03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000550900001472000011010000,NVIDIA Controller,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
|
||||
05000000550900001472000001000000,NVIDIA Controller,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
|
||||
|
||||
@@ -160,10 +160,7 @@ float FxaaLuma(float4 rgba)
|
||||
|
||||
float4 FxaaPixelShader(float2 pos, FxaaTex tex, float2 fxaaRcpFrame, float fxaaSubpix, float fxaaEdgeThreshold, float fxaaEdgeThresholdMin)
|
||||
{
|
||||
float2 posM;
|
||||
posM.x = pos.x;
|
||||
posM.y = pos.y;
|
||||
|
||||
float2 posM = pos;
|
||||
float4 rgbyM = FxaaTexTop(tex, posM);
|
||||
rgbyM.w = RGBLuminance(rgbyM.xyz);
|
||||
#define lumaM rgbyM.w
|
||||
@@ -186,9 +183,10 @@ float4 FxaaPixelShader(float2 pos, FxaaTex tex, float2 fxaaRcpFrame, float fxaaS
|
||||
float rangeMaxScaled = rangeMax * fxaaEdgeThreshold;
|
||||
float rangeMaxClamped = max(fxaaEdgeThresholdMin, rangeMaxScaled);
|
||||
|
||||
bool earlyExit = range < rangeMaxClamped;
|
||||
#if (FxaaEarlyExit == 1)
|
||||
if(earlyExit) { return rgbyM; }
|
||||
// Potential optimization, early exit.
|
||||
if (range < rangeMaxClamped)
|
||||
return rgbyM;
|
||||
#endif
|
||||
|
||||
float lumaNW = FxaaLuma(FxaaTexOff(tex, posM, int2(-1,-1), fxaaRcpFrame.xy));
|
||||
|
||||
@@ -170,7 +170,7 @@ PS_OUTPUT ps_rta_decorrection(PS_INPUT input)
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_hdr_init(PS_INPUT input)
|
||||
PS_OUTPUT ps_colclip_init(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
float4 value = sample_c(input.t);
|
||||
@@ -178,7 +178,7 @@ PS_OUTPUT ps_hdr_init(PS_INPUT input)
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_hdr_resolve(PS_INPUT input)
|
||||
PS_OUTPUT ps_colclip_resolve(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
float4 value = sample_c(input.t);
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
#define PS_CHANNEL_FETCH 0
|
||||
#define PS_TALES_OF_ABYSS_HLE 0
|
||||
#define PS_URBAN_CHAOS_HLE 0
|
||||
#define PS_HDR 0
|
||||
#define PS_COLCLIP_HW 0
|
||||
#define PS_RTA_CORRECTION 0
|
||||
#define PS_RTA_SRC_CORRECTION 0
|
||||
#define PS_COLCLIP 0
|
||||
@@ -767,7 +767,7 @@ float4 ps_color(PS_INPUT input)
|
||||
float4 T = sample_color(st, input.t.w);
|
||||
#endif
|
||||
|
||||
if (PS_SHUFFLE && !PS_SHUFFLE_SAME && !PS_READ16_SRC)
|
||||
if (PS_SHUFFLE && !PS_SHUFFLE_SAME && !PS_READ16_SRC && !(PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE))
|
||||
{
|
||||
uint4 denorm_c_before = uint4(T);
|
||||
if (PS_PROCESS_BA & SHUFFLE_READ)
|
||||
@@ -799,7 +799,7 @@ void ps_fbmask(inout float4 C, float2 pos_xy)
|
||||
{
|
||||
if (PS_FBMASK)
|
||||
{
|
||||
float multi = PS_HDR ? 65535.0f : 255.0f;
|
||||
float multi = PS_COLCLIP_HW ? 65535.0f : 255.0f;
|
||||
float4 RT = trunc(RtTexture.Load(int3(pos_xy, 0)) * multi + 0.1f);
|
||||
C = (float4)(((uint4)C & ~FbMask) | ((uint4)RT & FbMask));
|
||||
}
|
||||
@@ -843,13 +843,13 @@ void ps_color_clamp_wrap(inout float3 C)
|
||||
C += 7.0f; // Need to round up, not down since the shader will invert
|
||||
|
||||
// Standard Clamp
|
||||
if (PS_COLCLIP == 0 && PS_HDR == 0)
|
||||
if (PS_COLCLIP == 0 && PS_COLCLIP_HW == 0)
|
||||
C = clamp(C, (float3)0.0f, (float3)255.0f);
|
||||
|
||||
// In 16 bits format, only 5 bits of color are used. It impacts shadows computation of Castlevania
|
||||
if (PS_DST_FMT == FMT_16 && PS_DITHER != 3 && (PS_BLEND_MIX == 0 || PS_DITHER))
|
||||
C = (float3)((int3)C & (int3)0xF8);
|
||||
else if (PS_COLCLIP == 1 || PS_HDR == 1)
|
||||
else if (PS_COLCLIP == 1 || PS_COLCLIP_HW == 1)
|
||||
C = (float3)((int3)C & (int3)0xFF);
|
||||
}
|
||||
else if (PS_DST_FMT == FMT_16 && PS_DITHER != 3 && PS_BLEND_MIX == 0 && PS_BLEND_HW == 0)
|
||||
@@ -898,7 +898,7 @@ void ps_blend(inout float4 Color, inout float4 As_rgba, float2 pos_xy)
|
||||
}
|
||||
|
||||
float Ad = PS_RTA_CORRECTION ? trunc(RT.a * 128.0f + 0.1f) / 128.0f : trunc(RT.a * 255.0f + 0.1f) / 128.0f;
|
||||
float color_multi = PS_HDR ? 65535.0f : 255.0f;
|
||||
float color_multi = PS_COLCLIP_HW ? 65535.0f : 255.0f;
|
||||
float3 Cd = trunc(RT.rgb * color_multi + 0.1f);
|
||||
float3 Cs = Color.rgb;
|
||||
|
||||
@@ -1086,7 +1086,7 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||
|
||||
if (PS_SHUFFLE)
|
||||
{
|
||||
if (!PS_SHUFFLE_SAME && !PS_READ16_SRC)
|
||||
if (!PS_SHUFFLE_SAME && !PS_READ16_SRC && !(PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE))
|
||||
{
|
||||
uint4 denorm_c_after = uint4(C);
|
||||
if (PS_PROCESS_BA & SHUFFLE_READ)
|
||||
@@ -1127,11 +1127,8 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||
{
|
||||
if (PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE)
|
||||
{
|
||||
C.rb = C.br;
|
||||
float g_temp = C.g;
|
||||
|
||||
C.g = C.a;
|
||||
C.a = g_temp;
|
||||
C.br = C.rb;
|
||||
C.ag = C.ga;
|
||||
}
|
||||
else if(PS_PROCESS_BA & SHUFFLE_READ)
|
||||
{
|
||||
@@ -1160,7 +1157,7 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||
|
||||
#if !PS_NO_COLOR
|
||||
output.c0.a = PS_RTA_CORRECTION ? C.a / 128.0f : C.a / 255.0f;
|
||||
output.c0.rgb = PS_HDR ? float3(C.rgb / 65535.0f) : C.rgb / 255.0f;
|
||||
output.c0.rgb = PS_COLCLIP_HW ? float3(C.rgb / 65535.0f) : C.rgb / 255.0f;
|
||||
#if !PS_NO_COLOR1
|
||||
output.c1 = alpha_blend;
|
||||
#endif
|
||||
|
||||
@@ -348,16 +348,16 @@ void ps_rta_decorrection()
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_hdr_init
|
||||
void ps_hdr_init()
|
||||
#ifdef ps_colclip_init
|
||||
void ps_colclip_init()
|
||||
{
|
||||
vec4 value = sample_c();
|
||||
SV_Target0 = vec4(round(value.rgb * 255.0f) / 65535.0f, value.a);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_hdr_resolve
|
||||
void ps_hdr_resolve()
|
||||
#ifdef ps_colclip_resolve
|
||||
void ps_colclip_resolve()
|
||||
{
|
||||
vec4 value = sample_c();
|
||||
SV_Target0 = vec4(vec3(uvec3(value.rgb * 65535.0f) & 255u) / 255.0f, value.a);
|
||||
|
||||
@@ -679,7 +679,7 @@ vec4 ps_color()
|
||||
vec4 T = sample_color(st);
|
||||
#endif
|
||||
|
||||
#if PS_SHUFFLE && !PS_READ16_SRC && !PS_SHUFFLE_SAME
|
||||
#if PS_SHUFFLE && !PS_READ16_SRC && !PS_SHUFFLE_SAME && !(PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE)
|
||||
uvec4 denorm_c_before = uvec4(T);
|
||||
#if (PS_PROCESS_BA & SHUFFLE_READ)
|
||||
T.r = float((denorm_c_before.b << 3) & 0xF8u);
|
||||
@@ -707,7 +707,7 @@ void ps_fbmask(inout vec4 C)
|
||||
{
|
||||
// FIXME do I need special case for 16 bits
|
||||
#if PS_FBMASK
|
||||
#if PS_HDR == 1
|
||||
#if PS_COLCLIP_HW == 1
|
||||
vec4 RT = trunc(sample_from_rt() * 65535.0f);
|
||||
#else
|
||||
vec4 RT = trunc(sample_from_rt() * 255.0f + 0.1f);
|
||||
@@ -757,7 +757,7 @@ void ps_color_clamp_wrap(inout vec3 C)
|
||||
#endif
|
||||
|
||||
// Correct the Color value based on the output format
|
||||
#if PS_COLCLIP == 0 && PS_HDR == 0
|
||||
#if PS_COLCLIP == 0 && PS_COLCLIP_HW == 0
|
||||
// Standard Clamp
|
||||
C = clamp(C, vec3(0.0f), vec3(255.0f));
|
||||
#endif
|
||||
@@ -771,7 +771,7 @@ void ps_color_clamp_wrap(inout vec3 C)
|
||||
#if PS_DST_FMT == FMT_16 && PS_DITHER < 3 && (PS_BLEND_MIX == 0 || PS_DITHER)
|
||||
// In 16 bits format, only 5 bits of colors are used. It impacts shadows computation of Castlevania
|
||||
C = vec3(ivec3(C) & ivec3(0xF8));
|
||||
#elif PS_COLCLIP == 1 || PS_HDR == 1
|
||||
#elif PS_COLCLIP == 1 || PS_COLCLIP_HW == 1
|
||||
C = vec3(ivec3(C) & ivec3(0xFF));
|
||||
#endif
|
||||
|
||||
@@ -828,7 +828,7 @@ float As = As_rgba.a;
|
||||
#endif
|
||||
|
||||
// Let the compiler do its jobs !
|
||||
#if PS_HDR == 1
|
||||
#if PS_COLCLIP_HW == 1
|
||||
vec3 Cd = trunc(RT.rgb * 65535.0f);
|
||||
#else
|
||||
vec3 Cd = trunc(RT.rgb * 255.0f + 0.1f);
|
||||
@@ -1064,7 +1064,7 @@ void ps_main()
|
||||
|
||||
|
||||
#if PS_SHUFFLE
|
||||
#if !PS_READ16_SRC && !PS_SHUFFLE_SAME
|
||||
#if !PS_READ16_SRC && !PS_SHUFFLE_SAME && !(PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE)
|
||||
uvec4 denorm_c_after = uvec4(C);
|
||||
#if (PS_PROCESS_BA & SHUFFLE_READ)
|
||||
C.b = float(((denorm_c_after.r >> 3) & 0x1Fu) | ((denorm_c_after.g << 2) & 0xE0u));
|
||||
@@ -1095,11 +1095,8 @@ void ps_main()
|
||||
C.ga = vec2(float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.x & 0x80u)));
|
||||
#elif PS_SHUFFLE_ACROSS
|
||||
#if(PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE)
|
||||
C.rb = C.br;
|
||||
float g_temp = C.g;
|
||||
|
||||
C.g = C.a;
|
||||
C.a = g_temp;
|
||||
C.br = C.rb;
|
||||
C.ag = C.ga;
|
||||
#elif(PS_PROCESS_BA & SHUFFLE_READ)
|
||||
C.rb = C.bb;
|
||||
C.ga = C.aa;
|
||||
@@ -1128,7 +1125,7 @@ void ps_main()
|
||||
#else
|
||||
SV_Target0.a = C.a / 255.0f;
|
||||
#endif
|
||||
#if PS_HDR == 1
|
||||
#if PS_COLCLIP_HW == 1
|
||||
SV_Target0.rgb = vec3(C.rgb / 65535.0f);
|
||||
#else
|
||||
SV_Target0.rgb = C.rgb / 255.0f;
|
||||
|
||||
@@ -148,16 +148,16 @@ void ps_rta_decorrection()
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_hdr_init
|
||||
void ps_hdr_init()
|
||||
#ifdef ps_colclip_init
|
||||
void ps_colclip_init()
|
||||
{
|
||||
vec4 value = sample_c(v_tex);
|
||||
o_col0 = vec4(roundEven(value.rgb * 255.0f) / 65535.0f, value.a);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_hdr_resolve
|
||||
void ps_hdr_resolve()
|
||||
#ifdef ps_colclip_resolve
|
||||
void ps_colclip_resolve()
|
||||
{
|
||||
vec4 value = sample_c(v_tex);
|
||||
o_col0 = vec4(vec3(uvec3(value.rgb * 65535.5f) & 255u) / 255.0f, value.a);
|
||||
|
||||
@@ -281,7 +281,7 @@ void main()
|
||||
#define PS_CHANNEL_FETCH 0
|
||||
#define PS_TALES_OF_ABYSS_HLE 0
|
||||
#define PS_URBAN_CHAOS_HLE 0
|
||||
#define PS_HDR 0
|
||||
#define PS_COLCLIP_HW 0
|
||||
#define PS_COLCLIP 0
|
||||
#define PS_BLEND_A 0
|
||||
#define PS_BLEND_B 0
|
||||
@@ -946,7 +946,7 @@ vec4 ps_color()
|
||||
vec4 T = sample_color(st);
|
||||
#endif
|
||||
|
||||
#if PS_SHUFFLE && !PS_READ16_SRC && !PS_SHUFFLE_SAME
|
||||
#if PS_SHUFFLE && !PS_READ16_SRC && !PS_SHUFFLE_SAME && !(PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE)
|
||||
uvec4 denorm_c_before = uvec4(T);
|
||||
#if (PS_PROCESS_BA & SHUFFLE_READ)
|
||||
T.r = float((denorm_c_before.b << 3) & 0xF8u);
|
||||
@@ -974,7 +974,7 @@ void ps_fbmask(inout vec4 C)
|
||||
{
|
||||
#if PS_FBMASK
|
||||
|
||||
#if PS_HDR == 1
|
||||
#if PS_COLCLIP_HW == 1
|
||||
vec4 RT = trunc(sample_from_rt() * 65535.0f);
|
||||
#else
|
||||
vec4 RT = trunc(sample_from_rt() * 255.0f + 0.1f);
|
||||
@@ -1027,7 +1027,7 @@ void ps_color_clamp_wrap(inout vec3 C)
|
||||
#endif
|
||||
|
||||
// Correct the Color value based on the output format
|
||||
#if PS_COLCLIP == 0 && PS_HDR == 0
|
||||
#if PS_COLCLIP == 0 && PS_COLCLIP_HW == 0
|
||||
// Standard Clamp
|
||||
C = clamp(C, vec3(0.0f), vec3(255.0f));
|
||||
#endif
|
||||
@@ -1041,7 +1041,7 @@ void ps_color_clamp_wrap(inout vec3 C)
|
||||
#if PS_DST_FMT == FMT_16 && PS_DITHER != 3 && (PS_BLEND_MIX == 0 || PS_DITHER > 0)
|
||||
// In 16 bits format, only 5 bits of colors are used. It impacts shadows computation of Castlevania
|
||||
C = vec3(ivec3(C) & ivec3(0xF8));
|
||||
#elif PS_COLCLIP == 1 || PS_HDR == 1
|
||||
#elif PS_COLCLIP == 1 || PS_COLCLIP_HW == 1
|
||||
C = vec3(ivec3(C) & ivec3(0xFF));
|
||||
#endif
|
||||
|
||||
@@ -1098,7 +1098,7 @@ void ps_blend(inout vec4 Color, inout vec4 As_rgba)
|
||||
#endif
|
||||
|
||||
// Let the compiler do its jobs !
|
||||
#if PS_HDR == 1
|
||||
#if PS_COLCLIP_HW == 1
|
||||
vec3 Cd = trunc(RT.rgb * 65535.0f);
|
||||
#else
|
||||
vec3 Cd = trunc(RT.rgb * 255.0f + 0.1f);
|
||||
@@ -1332,7 +1332,7 @@ void main()
|
||||
ps_blend(C, alpha_blend);
|
||||
|
||||
#if PS_SHUFFLE
|
||||
#if !PS_READ16_SRC && !PS_SHUFFLE_SAME
|
||||
#if !PS_READ16_SRC && !PS_SHUFFLE_SAME && !(PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE)
|
||||
uvec4 denorm_c_after = uvec4(C);
|
||||
#if (PS_PROCESS_BA & SHUFFLE_READ)
|
||||
C.b = float(((denorm_c_after.r >> 3) & 0x1Fu) | ((denorm_c_after.g << 2) & 0xE0u));
|
||||
@@ -1343,8 +1343,6 @@ void main()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Special case for 32bit input and 16bit output, shuffle used by The Godfather
|
||||
#if PS_SHUFFLE_SAME
|
||||
#if (PS_PROCESS_BA & SHUFFLE_READ)
|
||||
@@ -1362,11 +1360,8 @@ void main()
|
||||
// Write RB part. Mask will take care of the correct destination
|
||||
#elif PS_SHUFFLE_ACROSS
|
||||
#if(PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE)
|
||||
C.rb = C.br;
|
||||
float g_temp = C.g;
|
||||
|
||||
C.g = C.a;
|
||||
C.a = g_temp;
|
||||
C.br = C.rb;
|
||||
C.ag = C.ga;
|
||||
#elif(PS_PROCESS_BA & SHUFFLE_READ)
|
||||
C.rb = C.bb;
|
||||
C.ga = C.aa;
|
||||
@@ -1395,7 +1390,7 @@ void main()
|
||||
#else
|
||||
o_col0.a = C.a / 255.0f;
|
||||
#endif
|
||||
#if PS_HDR == 1
|
||||
#if PS_COLCLIP_HW == 1
|
||||
o_col0.rgb = vec3(C.rgb / 65535.0f);
|
||||
#else
|
||||
o_col0.rgb = C.rgb / 255.0f;
|
||||
|
||||
@@ -342,7 +342,7 @@ bool Log::SetFileOutputLevel(LOGLEVEL level, std::string path)
|
||||
if (!s_file_handle || s_file_path != path)
|
||||
{
|
||||
s_file_handle.reset();
|
||||
s_file_handle = FileSystem::OpenManagedCFile(path.c_str(), "wb");
|
||||
s_file_handle = FileSystem::OpenManagedSharedCFile(path.c_str(), "wb", FileSystem::FileShareMode::DenyWrite);
|
||||
if (s_file_handle)
|
||||
{
|
||||
s_file_path = std::move(path);
|
||||
|
||||
@@ -50,6 +50,32 @@ u64 GetPhysicalMemory()
|
||||
return getmem;
|
||||
}
|
||||
|
||||
u64 GetAvailablePhysicalMemory()
|
||||
{
|
||||
const mach_port_t host_port = mach_host_self();
|
||||
vm_size_t page_size;
|
||||
|
||||
// Get the system's page size.
|
||||
if (host_page_size(host_port, &page_size) != KERN_SUCCESS)
|
||||
return 0;
|
||||
|
||||
vm_statistics64_data_t vm_stat;
|
||||
mach_msg_type_number_t host_size = sizeof(vm_statistics64_data_t) / sizeof(integer_t);
|
||||
|
||||
// Get system memory statistics.
|
||||
if (host_statistics64(host_port, HOST_VM_INFO, reinterpret_cast<host_info64_t>(&vm_stat), &host_size) != KERN_SUCCESS)
|
||||
return 0;
|
||||
|
||||
// Get the number of free and inactive pages.
|
||||
const u64 free_pages = static_cast<u64>(vm_stat.free_count);
|
||||
const u64 inactive_pages = static_cast<u64>(vm_stat.inactive_count);
|
||||
|
||||
// Calculate available memory.
|
||||
const u64 get_available_mem = (free_pages + inactive_pages) * page_size;
|
||||
|
||||
return get_available_mem;
|
||||
}
|
||||
|
||||
static mach_timebase_info_data_t s_timebase_info;
|
||||
static const u64 tickfreq = []() {
|
||||
if (mach_timebase_info(&s_timebase_info) != KERN_SUCCESS)
|
||||
|
||||
@@ -181,6 +181,7 @@ private:
|
||||
extern u64 GetTickFrequency();
|
||||
extern u64 GetCPUTicks();
|
||||
extern u64 GetPhysicalMemory();
|
||||
extern u64 GetAvailablePhysicalMemory();
|
||||
/// Spin for a short period of time (call while spinning waiting for a lock)
|
||||
/// Returns the approximate number of ns that passed
|
||||
extern u32 ShortSpin();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include <spawn.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
@@ -40,6 +41,49 @@ u64 GetPhysicalMemory()
|
||||
return pages * getpagesize();
|
||||
}
|
||||
|
||||
u64 GetAvailablePhysicalMemory()
|
||||
{
|
||||
// Try to read MemAvailable from /proc/meminfo.
|
||||
FILE* file = fopen("/proc/meminfo", "r");
|
||||
if (file)
|
||||
{
|
||||
u64 mem_available = 0;
|
||||
u64 mem_free = 0, buffers = 0, cached = 0, sreclaimable = 0, shmem = 0;
|
||||
char line[256];
|
||||
|
||||
while (fgets(line, sizeof(line), file))
|
||||
{
|
||||
// Modern kernels provide MemAvailable directly - preferred and most accurate.
|
||||
if (sscanf(line, "MemAvailable: %llu kB", &mem_available) == 1)
|
||||
{
|
||||
fclose(file);
|
||||
return mem_available * _1kb;
|
||||
}
|
||||
|
||||
// Fallback values for manual approximation.
|
||||
sscanf(line, "MemFree: %llu kB", &mem_free);
|
||||
sscanf(line, "Buffers: %llu kB", &buffers);
|
||||
sscanf(line, "Cached: %llu kB", &cached);
|
||||
sscanf(line, "SReclaimable: %llu kB", &sreclaimable);
|
||||
sscanf(line, "Shmem: %llu kB", &shmem);
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
// Fallback approximation: Linux-like heuristic.
|
||||
// available = MemFree + Buffers + Cached + SReclaimable - Shmem.
|
||||
const u64 available_kb = mem_free + buffers + cached + sreclaimable - shmem;
|
||||
return available_kb * _1kb;
|
||||
}
|
||||
|
||||
// Fallback to sysinfo if /proc/meminfo couldn't be read.
|
||||
struct sysinfo info = {};
|
||||
if (sysinfo(&info) != 0)
|
||||
return 0;
|
||||
|
||||
// Note: This does NOT include cached memory - only free + buffer.
|
||||
return (static_cast<u64>(info.freeram) + static_cast<u64>(info.bufferram)) * static_cast<u64>(info.mem_unit);
|
||||
}
|
||||
|
||||
u64 GetTickFrequency()
|
||||
{
|
||||
return 1000000000; // unix measures in nanoseconds
|
||||
|
||||
@@ -57,6 +57,14 @@ u64 GetPhysicalMemory()
|
||||
return status.ullTotalPhys;
|
||||
}
|
||||
|
||||
u64 GetAvailablePhysicalMemory()
|
||||
{
|
||||
MEMORYSTATUSEX status;
|
||||
status.dwLength = sizeof(status);
|
||||
GlobalMemoryStatusEx(&status);
|
||||
return status.ullAvailPhys;
|
||||
}
|
||||
|
||||
// Calculates the Windows OS Version and processor architecture, and returns it as a
|
||||
// human-readable string. :)
|
||||
std::string GetOSVersionString()
|
||||
|
||||
@@ -42,6 +42,7 @@ BreakpointDialog::BreakpointDialog(QWidget* parent, DebugInterface* cpu, Breakpo
|
||||
m_ui.rdoExecute->setChecked(true);
|
||||
m_ui.chkEnable->setChecked(bp->enabled);
|
||||
m_ui.txtAddress->setText(QtUtils::FilledQStringFromValue(bp->addr, 16));
|
||||
m_ui.txtDescription->setText(QString::fromStdString(bp->description));
|
||||
|
||||
if (bp->hasCond)
|
||||
m_ui.txtCondition->setText(QString::fromStdString(bp->cond.expressionString));
|
||||
@@ -53,6 +54,8 @@ BreakpointDialog::BreakpointDialog(QWidget* parent, DebugInterface* cpu, Breakpo
|
||||
m_ui.txtAddress->setText(QtUtils::FilledQStringFromValue(mc->start, 16));
|
||||
m_ui.txtSize->setText(QtUtils::FilledQStringFromValue(mc->end - mc->start, 16));
|
||||
|
||||
m_ui.txtDescription->setText(QString::fromStdString(mc->description));
|
||||
|
||||
m_ui.chkRead->setChecked(mc->memCond & MEMCHECK_READ);
|
||||
m_ui.chkWrite->setChecked(mc->memCond & MEMCHECK_WRITE);
|
||||
m_ui.chkChange->setChecked(mc->memCond & MEMCHECK_WRITE_ONCHANGE);
|
||||
@@ -102,6 +105,7 @@ void BreakpointDialog::accept()
|
||||
}
|
||||
|
||||
bp->addr = address;
|
||||
bp->description = m_ui.txtDescription->text().toStdString();
|
||||
|
||||
bp->enabled = m_ui.chkEnable->isChecked();
|
||||
|
||||
@@ -138,6 +142,7 @@ void BreakpointDialog::accept()
|
||||
|
||||
mc->start = startAddress;
|
||||
mc->end = startAddress + size;
|
||||
mc->description = m_ui.txtDescription->text().toStdString();
|
||||
|
||||
if (!m_ui.txtCondition->text().isEmpty())
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>375</width>
|
||||
<height>250</height>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@@ -22,19 +22,19 @@
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>375</width>
|
||||
<height>250</height>
|
||||
<height>300</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>375</width>
|
||||
<height>250</height>
|
||||
<height>300</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="baseSize">
|
||||
<size>
|
||||
<width>375</width>
|
||||
<height>250</height>
|
||||
<height>300</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -44,7 +44,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>210</y>
|
||||
<y>260</y>
|
||||
<width>341</width>
|
||||
<height>32</height>
|
||||
</rect>
|
||||
@@ -102,14 +102,17 @@
|
||||
<rect>
|
||||
<x>110</x>
|
||||
<y>10</y>
|
||||
<width>251</width>
|
||||
<height>41</height>
|
||||
<width>250</width>
|
||||
<height>79</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="formAlignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
@@ -139,6 +142,29 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Description</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="txtDescription">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>19</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>19</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="grpMemory">
|
||||
@@ -148,7 +174,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>110</x>
|
||||
<y>50</y>
|
||||
<y>100</y>
|
||||
<width>251</width>
|
||||
<height>91</height>
|
||||
</rect>
|
||||
@@ -224,13 +250,13 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>110</x>
|
||||
<y>140</y>
|
||||
<y>190</y>
|
||||
<width>251</width>
|
||||
<height>61</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string></string>
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0">
|
||||
|
||||
@@ -72,11 +72,13 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||
switch (index.column())
|
||||
{
|
||||
case BreakpointColumns::ENABLED:
|
||||
return "";
|
||||
return (bp->enabled) ? tr("Enabled") : tr("Disabled");
|
||||
case BreakpointColumns::TYPE:
|
||||
return tr("Execute");
|
||||
case BreakpointColumns::OFFSET:
|
||||
return QtUtils::FilledQStringFromValue(bp->addr, 16);
|
||||
case BreakpointColumns::DESCRIPTION:
|
||||
return QString::fromStdString(bp->description);
|
||||
case BreakpointColumns::SIZE_LABEL:
|
||||
return QString::fromStdString(m_cpu.GetSymbolGuardian().FunctionStartingAtAddress(bp->addr).name);
|
||||
case BreakpointColumns::OPCODE:
|
||||
@@ -105,6 +107,8 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||
}
|
||||
case BreakpointColumns::OFFSET:
|
||||
return QtUtils::FilledQStringFromValue(mc->start, 16);
|
||||
case BreakpointColumns::DESCRIPTION:
|
||||
return QString::fromStdString(mc->description);
|
||||
case BreakpointColumns::SIZE_LABEL:
|
||||
return QString::number(mc->end - mc->start, 16);
|
||||
case BreakpointColumns::OPCODE:
|
||||
@@ -116,6 +120,29 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (role == Qt::EditRole)
|
||||
{
|
||||
if (const auto* bp = std::get_if<BreakPoint>(&bp_mc))
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
case BreakpointColumns::CONDITION:
|
||||
return bp->hasCond ? QString::fromStdString(bp->cond.expressionString) : "";
|
||||
case BreakpointColumns::DESCRIPTION:
|
||||
return QString::fromStdString(bp->description);
|
||||
}
|
||||
}
|
||||
else if (const auto* mc = std::get_if<MemCheck>(&bp_mc))
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
case BreakpointColumns::CONDITION:
|
||||
return mc->hasCond ? QString::fromStdString(mc->cond.expressionString) : "";
|
||||
case BreakpointColumns::DESCRIPTION:
|
||||
return QString::fromStdString(mc->description);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (role == BreakpointModel::DataRole)
|
||||
{
|
||||
if (const auto* bp = std::get_if<BreakPoint>(&bp_mc))
|
||||
@@ -128,6 +155,8 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||
return MEMCHECK_INVALID;
|
||||
case BreakpointColumns::OFFSET:
|
||||
return bp->addr;
|
||||
case BreakpointColumns::DESCRIPTION:
|
||||
return QString::fromStdString(bp->description);
|
||||
case BreakpointColumns::SIZE_LABEL:
|
||||
return QString::fromStdString(m_cpu.GetSymbolGuardian().FunctionStartingAtAddress(bp->addr).name);
|
||||
case BreakpointColumns::OPCODE:
|
||||
@@ -149,6 +178,8 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||
return mc->memCond;
|
||||
case BreakpointColumns::OFFSET:
|
||||
return mc->start;
|
||||
case BreakpointColumns::DESCRIPTION:
|
||||
return QString::fromStdString(mc->description);
|
||||
case BreakpointColumns::SIZE_LABEL:
|
||||
return mc->end - mc->start;
|
||||
case BreakpointColumns::OPCODE:
|
||||
@@ -172,6 +203,8 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||
return MEMCHECK_INVALID;
|
||||
case BreakpointColumns::OFFSET:
|
||||
return QtUtils::FilledQStringFromValue(bp->addr, 16);
|
||||
case BreakpointColumns::DESCRIPTION:
|
||||
return QString::fromStdString(bp->description);
|
||||
case BreakpointColumns::SIZE_LABEL:
|
||||
return QString::fromStdString(m_cpu.GetSymbolGuardian().FunctionStartingAtAddress(bp->addr).name);
|
||||
case BreakpointColumns::OPCODE:
|
||||
@@ -191,6 +224,8 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||
return mc->memCond;
|
||||
case BreakpointColumns::OFFSET:
|
||||
return QtUtils::FilledQStringFromValue(mc->start, 16);
|
||||
case BreakpointColumns::DESCRIPTION:
|
||||
return QString::fromStdString(mc->description);
|
||||
case BreakpointColumns::SIZE_LABEL:
|
||||
return mc->end - mc->start;
|
||||
case BreakpointColumns::OPCODE:
|
||||
@@ -233,6 +268,8 @@ QVariant BreakpointModel::headerData(int section, Qt::Orientation orientation, i
|
||||
case BreakpointColumns::OFFSET:
|
||||
//: Warning: limited space available. Abbreviate if needed.
|
||||
return tr("OFFSET");
|
||||
case BreakpointColumns::DESCRIPTION:
|
||||
return "DESCRIPTION";
|
||||
case BreakpointColumns::SIZE_LABEL:
|
||||
//: Warning: limited space available. Abbreviate if needed.
|
||||
return tr("SIZE / LABEL");
|
||||
@@ -260,6 +297,8 @@ QVariant BreakpointModel::headerData(int section, Qt::Orientation orientation, i
|
||||
return "TYPE";
|
||||
case BreakpointColumns::OFFSET:
|
||||
return "OFFSET";
|
||||
case BreakpointColumns::DESCRIPTION:
|
||||
return "DESCRIPTION";
|
||||
case BreakpointColumns::SIZE_LABEL:
|
||||
return "SIZE / LABEL";
|
||||
case BreakpointColumns::OPCODE:
|
||||
@@ -282,6 +321,7 @@ Qt::ItemFlags BreakpointModel::flags(const QModelIndex& index) const
|
||||
switch (index.column())
|
||||
{
|
||||
case BreakpointColumns::CONDITION:
|
||||
case BreakpointColumns::DESCRIPTION:
|
||||
return Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEditable;
|
||||
case BreakpointColumns::TYPE:
|
||||
case BreakpointColumns::OPCODE:
|
||||
@@ -395,6 +435,27 @@ bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, i
|
||||
emit dataChanged(index, index);
|
||||
return true;
|
||||
}
|
||||
else if (role == Qt::EditRole && index.column() == BreakpointColumns::DESCRIPTION)
|
||||
{
|
||||
// Update BreakPoint description
|
||||
if (auto* bp = std::get_if<BreakPoint>(&bp_mc))
|
||||
{
|
||||
const QString descValue = value.toString();
|
||||
Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), bp, descValue] {
|
||||
CBreakPoints::ChangeBreakPointDescription(cpu, bp->addr, descValue.toStdString());
|
||||
});
|
||||
}
|
||||
// Update MemCheck description
|
||||
else if (auto* mc = std::get_if<MemCheck>(&bp_mc))
|
||||
{
|
||||
const QString descValue = value.toString();
|
||||
Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), mc, descValue] {
|
||||
CBreakPoints::ChangeMemCheckDescription(cpu, mc->start, mc->end, descValue.toStdString());
|
||||
});
|
||||
}
|
||||
emit dataChanged(index, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -451,7 +512,7 @@ bool BreakpointModel::insertBreakpointRows(int row, int count, std::vector<Break
|
||||
{
|
||||
Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), bp = *bp] {
|
||||
CBreakPoints::AddBreakPoint(cpu, bp.addr, false, bp.enabled);
|
||||
|
||||
CBreakPoints::ChangeBreakPointDescription(cpu, bp.addr, bp.description);
|
||||
if (bp.hasCond)
|
||||
{
|
||||
CBreakPoints::ChangeBreakPointAddCond(cpu, bp.addr, bp.cond);
|
||||
@@ -462,6 +523,7 @@ bool BreakpointModel::insertBreakpointRows(int row, int count, std::vector<Break
|
||||
{
|
||||
Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), mc = *mc] {
|
||||
CBreakPoints::AddMemCheck(cpu, mc.start, mc.end, mc.memCond, mc.result);
|
||||
CBreakPoints::ChangeMemCheckDescription(cpu, mc.start, mc.end, mc.description);
|
||||
if (mc.hasCond)
|
||||
{
|
||||
CBreakPoints::ChangeMemCheckAddCond(cpu, mc.start, mc.end, mc.cond);
|
||||
@@ -548,6 +610,12 @@ void BreakpointModel::loadBreakpointFromFieldList(QStringList fields)
|
||||
return;
|
||||
}
|
||||
|
||||
// Description
|
||||
if (!fields[BreakpointColumns::DESCRIPTION].isEmpty())
|
||||
{
|
||||
bp.description = fields[BreakpointColumns::DESCRIPTION].toStdString();
|
||||
}
|
||||
|
||||
insertBreakpointRows(0, 1, {bp});
|
||||
}
|
||||
else
|
||||
@@ -608,6 +676,12 @@ void BreakpointModel::loadBreakpointFromFieldList(QStringList fields)
|
||||
}
|
||||
mc.result = static_cast<MemCheckResult>(result);
|
||||
|
||||
// Description
|
||||
if (!fields[BreakpointColumns::DESCRIPTION].isEmpty())
|
||||
{
|
||||
mc.description = fields[BreakpointColumns::DESCRIPTION].toStdString();
|
||||
}
|
||||
|
||||
insertBreakpointRows(0, 1, {mc});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
ENABLED = 0,
|
||||
TYPE,
|
||||
OFFSET,
|
||||
DESCRIPTION,
|
||||
SIZE_LABEL,
|
||||
OPCODE,
|
||||
CONDITION,
|
||||
@@ -38,6 +39,7 @@ public:
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
QHeaderView::ResizeMode::Stretch,
|
||||
QHeaderView::ResizeMode::Stretch,
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
|
||||
@@ -21,11 +21,7 @@ BreakpointView::BreakpointView(const DebuggerViewParameters& parameters)
|
||||
connect(m_ui.breakpointList, &QTableView::doubleClicked, this, &BreakpointView::onDoubleClicked);
|
||||
|
||||
m_ui.breakpointList->setModel(m_model);
|
||||
for (std::size_t i = 0; auto mode : BreakpointModel::HeaderResizeModes)
|
||||
{
|
||||
m_ui.breakpointList->horizontalHeader()->setSectionResizeMode(i, mode);
|
||||
i++;
|
||||
}
|
||||
this->resizeColumns();
|
||||
}
|
||||
|
||||
void BreakpointView::onDoubleClicked(const QModelIndex& index)
|
||||
@@ -124,6 +120,7 @@ void BreakpointView::contextDelete()
|
||||
void BreakpointView::contextNew()
|
||||
{
|
||||
BreakpointDialog* bpDialog = new BreakpointDialog(this, &cpu(), *m_model);
|
||||
connect(bpDialog, &QDialog::accepted, this, &BreakpointView::resizeColumns);
|
||||
bpDialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
bpDialog->show();
|
||||
}
|
||||
@@ -140,6 +137,7 @@ void BreakpointView::contextEdit()
|
||||
auto bpObject = m_model->at(selectedRow);
|
||||
|
||||
BreakpointDialog* bpDialog = new BreakpointDialog(this, &cpu(), *m_model, bpObject, selectedRow);
|
||||
connect(bpDialog, &QDialog::accepted, this, &BreakpointView::resizeColumns);
|
||||
bpDialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
bpDialog->show();
|
||||
}
|
||||
@@ -172,3 +170,12 @@ void BreakpointView::saveBreakpointsToDebuggerSettings()
|
||||
{
|
||||
DebuggerSettingsManager::saveGameSettings(m_model);
|
||||
}
|
||||
|
||||
void BreakpointView::resizeColumns()
|
||||
{
|
||||
for (std::size_t i = 0; auto mode : BreakpointModel::HeaderResizeModes)
|
||||
{
|
||||
m_ui.breakpointList->horizontalHeader()->setSectionResizeMode(i, mode);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ public:
|
||||
void contextEdit();
|
||||
void contextPasteCSV();
|
||||
|
||||
void resizeColumns();
|
||||
|
||||
void saveBreakpointsToDebuggerSettings();
|
||||
|
||||
private:
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "VMManager.h"
|
||||
|
||||
std::mutex DebuggerSettingsManager::writeLock;
|
||||
const QString DebuggerSettingsManager::settingsFileVersion = "0.00";
|
||||
const QString DebuggerSettingsManager::settingsFileVersion = "0.01";
|
||||
|
||||
QJsonObject DebuggerSettingsManager::loadGameSettingsJSON()
|
||||
{
|
||||
@@ -62,6 +62,17 @@ void DebuggerSettingsManager::loadGameSettings(BreakpointModel* bpModel)
|
||||
return;
|
||||
}
|
||||
|
||||
// Breakpoint descriptions were added at debugger settings file version 0.01. If loading
|
||||
// saved breakpoints from a previous version (only 0.00 existed prior), the breakpoints will be
|
||||
// missing a description. This code will add in an empty description so that the previous
|
||||
// version, 0.00, is compatible with 0.01.
|
||||
bool isMissingDescription = false;
|
||||
const QJsonValue savedVersionValue = loadGameSettingsJSON().value("Version");
|
||||
if (!savedVersionValue.isUndefined())
|
||||
{
|
||||
isMissingDescription = savedVersionValue.toString().toStdString() == "0.00";
|
||||
}
|
||||
|
||||
const QJsonArray breakpointsArray = breakpointsValue.toArray();
|
||||
for (u32 row = 0; row < breakpointsArray.size(); row++)
|
||||
{
|
||||
@@ -71,7 +82,13 @@ void DebuggerSettingsManager::loadGameSettings(BreakpointModel* bpModel)
|
||||
Console.WriteLn("Debugger Settings Manager: Failed to load invalid Breakpoint object.");
|
||||
continue;
|
||||
}
|
||||
const QJsonObject rowObject = rowValue.toObject();
|
||||
QJsonObject rowObject = rowValue.toObject();
|
||||
|
||||
// Add empty description for saved breakpoints from debugger settings versions prior to 0.01
|
||||
if (isMissingDescription)
|
||||
{
|
||||
rowObject.insert(QString("DESCRIPTION"), QJsonValue(""));
|
||||
}
|
||||
|
||||
QStringList fields;
|
||||
u32 col = 0;
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1000</width>
|
||||
<height>20</height>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
@@ -50,6 +50,7 @@
|
||||
<property name="title">
|
||||
<string>Windows</string>
|
||||
</property>
|
||||
<addaction name="actionWindowsDummy"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuView">
|
||||
<property name="title">
|
||||
@@ -72,6 +73,7 @@
|
||||
<property name="title">
|
||||
<string>Tools</string>
|
||||
</property>
|
||||
<addaction name="actionToolsDummy"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuView"/>
|
||||
@@ -318,6 +320,16 @@
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionToolsDummy">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionWindowsDummy">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
@@ -298,7 +298,10 @@ void DockManager::resetAllLayouts()
|
||||
m_layouts.clear();
|
||||
|
||||
for (const DockTables::DefaultDockLayout& layout : DockTables::DEFAULT_DOCK_LAYOUTS)
|
||||
createLayout(tr(layout.name.c_str()), layout.cpu, true, layout.name);
|
||||
{
|
||||
QString name = QCoreApplication::translate("DebuggerLayout", layout.name.c_str());
|
||||
createLayout(name, layout.cpu, true, layout.name);
|
||||
}
|
||||
|
||||
switchToLayout(0);
|
||||
updateLayoutSwitcher();
|
||||
@@ -313,7 +316,10 @@ void DockManager::resetDefaultLayouts()
|
||||
m_layouts = std::vector<DockLayout>();
|
||||
|
||||
for (const DockTables::DefaultDockLayout& layout : DockTables::DEFAULT_DOCK_LAYOUTS)
|
||||
createLayout(tr(layout.name.c_str()), layout.cpu, true, layout.name);
|
||||
{
|
||||
QString name = QCoreApplication::translate("DebuggerLayout", layout.name.c_str());
|
||||
createLayout(name, layout.cpu, true, layout.name);
|
||||
}
|
||||
|
||||
for (DockLayout& layout : old_layouts)
|
||||
if (!layout.isDefault())
|
||||
|
||||
@@ -502,7 +502,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.aspectRatio, tr("Aspect Ratio"), tr("Auto Standard (4:3/3:2 Progressive)"),
|
||||
tr("Changes the aspect ratio used to display the console's output to the screen. The default is Auto Standard (4:3/3:2 "
|
||||
"Progressive) which automatically adjusts the aspect ratio to match how a game would be shown on a typical TV of the era."));
|
||||
"Progressive) which automatically adjusts the aspect ratio to match how a game would be shown on a typical TV of the era, and adapts to widescreen/ultrawide game patches."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.interlacing, tr("Deinterlacing"), tr("Automatic (Default)"), tr("Determines the deinterlacing method to be used on the interlaced screen of the emulated console. Automatic should be able to correctly deinterlace most games, but if you see visibly shaky graphics, try one of the available options."));
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Native (10:7)</string>
|
||||
<string>Native/Full (10:7)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
@@ -142,7 +142,7 @@
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Native (10:7)</string>
|
||||
<string>Native/Full (10:7)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
|
||||
@@ -28,7 +28,7 @@ const char* QtHost::GetDefaultThemeName()
|
||||
#ifdef __APPLE__
|
||||
return "";
|
||||
#else
|
||||
return "darkfusion";
|
||||
return "darkfusionblue";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -266,15 +266,17 @@ bool ThreadedFileReader::Precache2(ProgressCallback* progress, Error* error)
|
||||
|
||||
bool ThreadedFileReader::CheckAvailableMemoryForPrecaching(u64 required_size, Error* error)
|
||||
{
|
||||
// Don't allow precaching to use more than 50% of system memory.
|
||||
// Hopefully nobody's running 2-4GB potatoes anymore....
|
||||
const u64 memory_size = GetPhysicalMemory();
|
||||
const u64 max_precache_size = memory_size / 2;
|
||||
// We want to check available physical memory instead of total.
|
||||
const u64 memory_available = GetAvailablePhysicalMemory();
|
||||
// Reserve 2GB of available memory for headroom.
|
||||
constexpr u64 memory_reserve = 2147483648;
|
||||
const u64 max_precache_size = std::max(s64{0}, static_cast<s64>(memory_available - memory_reserve));
|
||||
|
||||
if (required_size > max_precache_size)
|
||||
{
|
||||
Error::SetStringFmt(error,
|
||||
TRANSLATE_FS("CDVD", "Required memory ({}GB) is the above the maximum allowed ({}GB)."),
|
||||
required_size / _1gb, max_precache_size / _1gb);
|
||||
TRANSLATE_FS("CDVD", "Not enough memory available for precaching ({:.2f} GB required)."),
|
||||
static_cast<double>(required_size + memory_reserve) / static_cast<double>(_1gb));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -309,6 +309,7 @@ set(pcsx2DEV9Sources
|
||||
DEV9/Sessions/TCP_Session/TCP_Session.cpp
|
||||
DEV9/Sessions/TCP_Session/TCP_Session_In.cpp
|
||||
DEV9/Sessions/TCP_Session/TCP_Session_Out.cpp
|
||||
DEV9/Sessions/UDP_Session/UDP_Common.cpp
|
||||
DEV9/Sessions/UDP_Session/UDP_FixedPort.cpp
|
||||
DEV9/Sessions/UDP_Session/UDP_Session.cpp
|
||||
DEV9/smap.cpp
|
||||
@@ -354,6 +355,7 @@ set(pcsx2DEV9Headers
|
||||
DEV9/Sessions/BaseSession.h
|
||||
DEV9/Sessions/ICMP_Session/ICMP_Session.h
|
||||
DEV9/Sessions/TCP_Session/TCP_Session.h
|
||||
DEV9/Sessions/UDP_Session/UDP_Common.h
|
||||
DEV9/Sessions/UDP_Session/UDP_FixedPort.h
|
||||
DEV9/Sessions/UDP_Session/UDP_BaseSession.h
|
||||
DEV9/Sessions/UDP_Session/UDP_Session.h
|
||||
|
||||
@@ -223,8 +223,8 @@ enum class DebugFunctionScanMode
|
||||
|
||||
enum class AspectRatioType : u8
|
||||
{
|
||||
Stretch,
|
||||
RAuto4_3_3_2,
|
||||
Stretch, // Stretches to the whole window/display size
|
||||
RAuto4_3_3_2, // Automatically scales to the target aspect ratio if there's a widescreen patch
|
||||
R4_3,
|
||||
R16_9,
|
||||
R10_7,
|
||||
@@ -233,7 +233,7 @@ enum class AspectRatioType : u8
|
||||
|
||||
enum class FMVAspectRatioSwitchType : u8
|
||||
{
|
||||
Off,
|
||||
Off, // Falls back on the selected generic aspect ratio type
|
||||
RAuto4_3_3_2,
|
||||
R4_3,
|
||||
R16_9,
|
||||
@@ -1324,6 +1324,8 @@ struct Pcsx2Config
|
||||
std::string CurrentIRX;
|
||||
std::string CurrentGameArgs;
|
||||
AspectRatioType CurrentAspectRatio = AspectRatioType::RAuto4_3_3_2;
|
||||
// Fall back aspect ratio for games that have patches (when AspectRatioType::RAuto4_3_3_2) is active.
|
||||
float CurrentCustomAspectRatio = 0.f;
|
||||
bool IsPortableMode = false;
|
||||
|
||||
Pcsx2Config();
|
||||
|
||||
@@ -16,5 +16,6 @@ namespace Sessions
|
||||
}
|
||||
|
||||
virtual bool WillRecive(PacketReader::IP::IP_Address parDestIP) = 0;
|
||||
virtual void ForceClose() { RaiseEventConnectionClosed(); };
|
||||
};
|
||||
} // namespace Sessions
|
||||
|
||||
193
pcsx2/DEV9/Sessions/UDP_Session/UDP_Common.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include <bit>
|
||||
|
||||
#include "common/Console.h"
|
||||
|
||||
#ifdef __POSIX__
|
||||
#define SOCKET_ERROR -1
|
||||
#define INVALID_SOCKET -1
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "common/RedtapeWindows.h"
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "UDP_Common.h"
|
||||
#include "DEV9/PacketReader/IP/UDP/UDP_Packet.h"
|
||||
|
||||
using namespace PacketReader;
|
||||
using namespace PacketReader::IP;
|
||||
using namespace PacketReader::IP::UDP;
|
||||
|
||||
namespace Sessions::UDP_Common
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SOCKET CreateSocket(IP_Address adapterIP, std::optional<u16> port)
|
||||
{
|
||||
SOCKET client = INVALID_SOCKET;
|
||||
#elif defined(__POSIX__)
|
||||
int CreateSocket(IP_Address adapterIP, std::optional<u16> port)
|
||||
{
|
||||
int client = INVALID_SOCKET;
|
||||
#endif
|
||||
|
||||
int ret;
|
||||
client = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (client == INVALID_SOCKET)
|
||||
{
|
||||
Console.Error("DEV9: UDP: Failed to open socket. Error: %d",
|
||||
#ifdef _WIN32
|
||||
WSAGetLastError());
|
||||
#elif defined(__POSIX__)
|
||||
errno);
|
||||
#endif
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
constexpr int reuseAddress = true; // BOOL on Windows
|
||||
ret = setsockopt(client, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char*>(&reuseAddress), sizeof(reuseAddress));
|
||||
|
||||
if (ret == SOCKET_ERROR)
|
||||
Console.Error("DEV9: UDP: Failed to set SO_REUSEADDR. Error: %d",
|
||||
#ifdef _WIN32
|
||||
WSAGetLastError());
|
||||
#elif defined(__POSIX__)
|
||||
errno);
|
||||
#endif
|
||||
|
||||
if (port.has_value() || adapterIP != IP_Address{{{0, 0, 0, 0}}})
|
||||
{
|
||||
sockaddr_in endpoint{};
|
||||
endpoint.sin_family = AF_INET;
|
||||
endpoint.sin_addr = std::bit_cast<in_addr>(adapterIP);
|
||||
if (port.has_value())
|
||||
endpoint.sin_port = htons(port.value());
|
||||
|
||||
ret = bind(client, reinterpret_cast<const sockaddr*>(&endpoint), sizeof(endpoint));
|
||||
|
||||
if (ret == SOCKET_ERROR)
|
||||
Console.Error("DEV9: UDP: Failed to bind socket. Error: %d",
|
||||
#ifdef _WIN32
|
||||
WSAGetLastError());
|
||||
#elif defined(__POSIX__)
|
||||
errno);
|
||||
#endif
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
std::tuple<std::optional<ReceivedPayload>, bool> RecvFrom(SOCKET client, u16 port)
|
||||
#elif defined(__POSIX__)
|
||||
std::tuple<std::optional<ReceivedPayload>, bool> RecvFrom(int client, u16 port)
|
||||
#endif
|
||||
{
|
||||
int ret;
|
||||
fd_set sReady;
|
||||
fd_set sExcept;
|
||||
|
||||
// not const Linux
|
||||
timeval nowait{};
|
||||
FD_ZERO(&sReady);
|
||||
FD_ZERO(&sExcept);
|
||||
FD_SET(client, &sReady);
|
||||
FD_SET(client, &sExcept);
|
||||
ret = select(client + 1, &sReady, nullptr, &sExcept, &nowait);
|
||||
|
||||
if (ret == SOCKET_ERROR)
|
||||
{
|
||||
Console.Error("DEV9: UDP: select failed. Error code: %d",
|
||||
#ifdef _WIN32
|
||||
WSAGetLastError());
|
||||
#elif defined(__POSIX__)
|
||||
errno);
|
||||
#endif
|
||||
return {std::nullopt, true};
|
||||
}
|
||||
else if (FD_ISSET(client, &sExcept))
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int len = sizeof(ret);
|
||||
if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&ret), &len) < 0)
|
||||
{
|
||||
Console.Error("DEV9: UDP: Unknown UDP connection error (getsockopt error: %d)", WSAGetLastError());
|
||||
}
|
||||
#elif defined(__POSIX__)
|
||||
socklen_t len = sizeof(ret);
|
||||
if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&ret), &len) < 0)
|
||||
Console.Error("DEV9: UDP: Unknown UDP connection error (getsockopt error: %d)", errno);
|
||||
#endif
|
||||
else
|
||||
Console.Error("DEV9: UDP: Socket error: %d", ret);
|
||||
|
||||
// All socket errors assumed fatal.
|
||||
return {std::nullopt, false};
|
||||
}
|
||||
else if (FD_ISSET(client, &sReady))
|
||||
{
|
||||
unsigned long available = 0;
|
||||
PayloadData* recived = nullptr;
|
||||
std::unique_ptr<u8[]> buffer;
|
||||
sockaddr_in endpoint{};
|
||||
|
||||
// FIONREAD returns total size of all available messages
|
||||
// however, we only read one message at a time
|
||||
#ifdef _WIN32
|
||||
ret = ioctlsocket(client, FIONREAD, &available);
|
||||
#elif defined(__POSIX__)
|
||||
ret = ioctl(client, FIONREAD, &available);
|
||||
#endif
|
||||
if (ret != SOCKET_ERROR)
|
||||
{
|
||||
buffer = std::make_unique<u8[]>(available);
|
||||
|
||||
#ifdef _WIN32
|
||||
int fromlen = sizeof(endpoint);
|
||||
#elif defined(__POSIX__)
|
||||
socklen_t fromlen = sizeof(endpoint);
|
||||
#endif
|
||||
ret = recvfrom(client, reinterpret_cast<char*>(buffer.get()), available, 0, reinterpret_cast<sockaddr*>(&endpoint), &fromlen);
|
||||
}
|
||||
|
||||
if (ret == SOCKET_ERROR)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
ret = WSAGetLastError();
|
||||
#elif defined(__POSIX__)
|
||||
ret = errno;
|
||||
#endif
|
||||
Console.Error("DEV9: UDP: recvfrom error: %d", ret);
|
||||
|
||||
/*
|
||||
* We can receive an ICMP Port Unreacable error as a WSAECONNRESET/ECONNREFUSED error
|
||||
* Ignore the error, recv will be retried next loop
|
||||
*/
|
||||
return {std::nullopt,
|
||||
#ifdef _WIN32
|
||||
ret == WSAECONNRESET};
|
||||
#elif defined(__POSIX__)
|
||||
ret == ECONNREFUSED};
|
||||
#endif
|
||||
}
|
||||
|
||||
recived = new PayloadData(ret);
|
||||
memcpy(recived->data.get(), buffer.get(), ret);
|
||||
|
||||
std::unique_ptr<UDP_Packet> iRet = std::make_unique<UDP_Packet>(recived);
|
||||
iRet->destinationPort = port;
|
||||
iRet->sourcePort = ntohs(endpoint.sin_port);
|
||||
|
||||
return {ReceivedPayload{std::bit_cast<IP_Address>(endpoint.sin_addr), std::move(iRet)}, true};
|
||||
}
|
||||
return {std::nullopt, true};
|
||||
}
|
||||
} // namespace Sessions::UDP_Common
|
||||
31
pcsx2/DEV9/Sessions/UDP_Session/UDP_Common.h
Normal file
@@ -0,0 +1,31 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
#include <tuple>
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#elif defined(__POSIX__)
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#include "common/Pcsx2Defs.h"
|
||||
#include "DEV9/Sessions/BaseSession.h"
|
||||
|
||||
namespace Sessions::UDP_Common
|
||||
{
|
||||
// Binds the socket when provided with an IP
|
||||
#ifdef _WIN32
|
||||
SOCKET CreateSocket(PacketReader::IP::IP_Address adapterIP, std::optional<u16> port);
|
||||
#elif defined(__POSIX__)
|
||||
int CreateSocket(PacketReader::IP::IP_Address adapterIP, std::optional<u16> port);
|
||||
#endif
|
||||
|
||||
// Receives from the client and packages the data into ReceivedPayload
|
||||
// port is the local port to be written to the UDP header in ReceivedPayload
|
||||
#ifdef _WIN32
|
||||
std::tuple<std::optional<ReceivedPayload>, bool> RecvFrom(SOCKET client, u16 port);
|
||||
#elif defined(__POSIX__)
|
||||
std::tuple<std::optional<ReceivedPayload>, bool> RecvFrom(int client, u16 port);
|
||||
#endif
|
||||
} // namespace Sessions::UDP_Common
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "UDP_Common.h"
|
||||
#include "UDP_FixedPort.h"
|
||||
#include "DEV9/PacketReader/IP/UDP/UDP_Packet.h"
|
||||
|
||||
@@ -51,33 +52,15 @@ namespace Sessions
|
||||
|
||||
void UDP_FixedPort::Init()
|
||||
{
|
||||
int ret;
|
||||
client = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
client = UDP_Common::CreateSocket(adapterIP, port);
|
||||
if (client == INVALID_SOCKET)
|
||||
{
|
||||
Console.Error("DEV9: UDP: Failed to open socket. Error: %d",
|
||||
#ifdef _WIN32
|
||||
WSAGetLastError());
|
||||
#elif defined(__POSIX__)
|
||||
errno);
|
||||
#endif
|
||||
RaiseEventConnectionClosed();
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr int reuseAddress = true; // BOOL on Windows
|
||||
ret = setsockopt(client, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char*>(&reuseAddress), sizeof(reuseAddress));
|
||||
|
||||
if (ret == SOCKET_ERROR)
|
||||
Console.Error("DEV9: UDP: Failed to set SO_REUSEADDR. Error: %d",
|
||||
#ifdef _WIN32
|
||||
WSAGetLastError());
|
||||
#elif defined(__POSIX__)
|
||||
errno);
|
||||
#endif
|
||||
|
||||
constexpr int broadcastEnable = true; // BOOL on Windows
|
||||
ret = setsockopt(client, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<const char*>(&broadcastEnable), sizeof(broadcastEnable));
|
||||
const int ret = setsockopt(client, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<const char*>(&broadcastEnable), sizeof(broadcastEnable));
|
||||
|
||||
if (ret == SOCKET_ERROR)
|
||||
Console.Error("DEV9: UDP: Failed to set SO_BROADCAST. Error: %d",
|
||||
@@ -87,25 +70,6 @@ namespace Sessions
|
||||
errno);
|
||||
#endif
|
||||
|
||||
sockaddr_in endpoint{};
|
||||
endpoint.sin_family = AF_INET;
|
||||
endpoint.sin_addr = std::bit_cast<in_addr>(adapterIP);
|
||||
endpoint.sin_port = htons(port);
|
||||
|
||||
ret = bind(client, reinterpret_cast<const sockaddr*>(&endpoint), sizeof(endpoint));
|
||||
|
||||
if (ret == SOCKET_ERROR)
|
||||
{
|
||||
Console.Error("DEV9: UDP: Failed to bind socket. Error: %d",
|
||||
#ifdef _WIN32
|
||||
WSAGetLastError());
|
||||
#elif defined(__POSIX__)
|
||||
errno);
|
||||
#endif
|
||||
RaiseEventConnectionClosed();
|
||||
return;
|
||||
}
|
||||
|
||||
open.store(true);
|
||||
}
|
||||
|
||||
@@ -114,102 +78,45 @@ namespace Sessions
|
||||
if (!open.load())
|
||||
return std::nullopt;
|
||||
|
||||
int ret;
|
||||
fd_set sReady;
|
||||
fd_set sExcept;
|
||||
std::optional<ReceivedPayload> ret;
|
||||
bool success;
|
||||
std::tie(ret, success) = UDP_Common::RecvFrom(client, port);
|
||||
|
||||
timeval nowait{};
|
||||
FD_ZERO(&sReady);
|
||||
FD_ZERO(&sExcept);
|
||||
FD_SET(client, &sReady);
|
||||
FD_SET(client, &sExcept);
|
||||
ret = select(client + 1, &sReady, nullptr, &sExcept, &nowait);
|
||||
|
||||
bool hasData;
|
||||
if (ret == SOCKET_ERROR)
|
||||
if (!success)
|
||||
{
|
||||
hasData = false;
|
||||
Console.Error("DEV9: UDP: select failed. Error code: %d",
|
||||
#ifdef _WIN32
|
||||
WSAGetLastError());
|
||||
#elif defined(__POSIX__)
|
||||
errno);
|
||||
#endif
|
||||
}
|
||||
else if (FD_ISSET(client, &sExcept))
|
||||
{
|
||||
hasData = false;
|
||||
|
||||
int error = 0;
|
||||
#ifdef _WIN32
|
||||
int len = sizeof(error);
|
||||
if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&error), &len) < 0)
|
||||
Console.Error("DEV9: UDP: Unknown UDP connection error (getsockopt error: %d)", WSAGetLastError());
|
||||
#elif defined(__POSIX__)
|
||||
socklen_t len = sizeof(error);
|
||||
if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&error), &len) < 0)
|
||||
Console.Error("DEV9: UDP: Unknown UDP connection error (getsockopt error: %d)", errno);
|
||||
#endif
|
||||
else
|
||||
Console.Error("DEV9: UDP: Recv error: %d", error);
|
||||
}
|
||||
else
|
||||
hasData = FD_ISSET(client, &sReady);
|
||||
|
||||
if (hasData)
|
||||
{
|
||||
unsigned long available = 0;
|
||||
PayloadData* recived = nullptr;
|
||||
std::unique_ptr<u8[]> buffer;
|
||||
sockaddr_in endpoint{};
|
||||
|
||||
// FIONREAD returns total size of all available messages
|
||||
// however, we only read one message at a time
|
||||
#ifdef _WIN32
|
||||
ret = ioctlsocket(client, FIONREAD, &available);
|
||||
#elif defined(__POSIX__)
|
||||
ret = ioctl(client, FIONREAD, &available);
|
||||
#endif
|
||||
if (ret != SOCKET_ERROR)
|
||||
// See Reset() for why we copy the vector.
|
||||
std::vector<UDP_BaseSession*> connectionsCopy;
|
||||
{
|
||||
buffer = std::make_unique<u8[]>(available);
|
||||
|
||||
#ifdef _WIN32
|
||||
int fromlen = sizeof(endpoint);
|
||||
#elif defined(__POSIX__)
|
||||
socklen_t fromlen = sizeof(endpoint);
|
||||
#endif
|
||||
ret = recvfrom(client, reinterpret_cast<char*>(buffer.get()), available, 0, reinterpret_cast<sockaddr*>(&endpoint), &fromlen);
|
||||
std::lock_guard numberlock(connectionSentry);
|
||||
open.store(false);
|
||||
connectionsCopy = connections;
|
||||
}
|
||||
|
||||
if (ret == SOCKET_ERROR)
|
||||
if (connectionsCopy.size() == 0)
|
||||
{
|
||||
Console.Error("DEV9: UDP: UDP recv error: %d",
|
||||
#ifdef _WIN32
|
||||
WSAGetLastError());
|
||||
#elif defined(__POSIX__)
|
||||
errno);
|
||||
#endif
|
||||
// Can close immediately.
|
||||
RaiseEventConnectionClosed();
|
||||
return std::nullopt;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Need to wait for child connections to close.
|
||||
for (size_t i = 0; i < connectionsCopy.size(); i++)
|
||||
connectionsCopy[i]->ForceClose();
|
||||
|
||||
recived = new PayloadData(ret);
|
||||
memcpy(recived->data.get(), buffer.get(), ret);
|
||||
|
||||
std::unique_ptr<UDP_Packet> iRet = std::make_unique<UDP_Packet>(recived);
|
||||
iRet->destinationPort = port;
|
||||
iRet->sourcePort = ntohs(endpoint.sin_port);
|
||||
|
||||
IP_Address srvIP = std::bit_cast<IP_Address>(endpoint.sin_addr);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
else if (ret.has_value())
|
||||
{
|
||||
{
|
||||
std::lock_guard numberlock(connectionSentry);
|
||||
|
||||
for (size_t i = 0; i < connections.size(); i++)
|
||||
{
|
||||
UDP_BaseSession* s = connections[i];
|
||||
if (s->WillRecive(srvIP))
|
||||
return ReceivedPayload{srvIP, std::move(iRet)};
|
||||
if (s->WillRecive(ret.value().sourceIP))
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
Console.Error("DEV9: UDP: Unexpected packet, dropping");
|
||||
@@ -225,10 +132,12 @@ namespace Sessions
|
||||
|
||||
void UDP_FixedPort::Reset()
|
||||
{
|
||||
// Reseting a session may cause that session to close itself,
|
||||
// when that happens, the connections vector gets modified via our close handler.
|
||||
// Duplicate the vector to avoid iterating over a modified collection,
|
||||
// this also avoids the issue of recursive locking when our close handler takes a lock.
|
||||
/*
|
||||
* Reseting a session may cause that session to close itself,
|
||||
* when that happens, the connections vector gets modified via our close handler.
|
||||
* Duplicate the vector to avoid iterating over a modified collection,
|
||||
* this also avoids the issue of recursive locking when our close handler takes a lock.
|
||||
*/
|
||||
std::vector<UDP_BaseSession*> connectionsCopy;
|
||||
{
|
||||
std::lock_guard numberlock(connectionSentry);
|
||||
@@ -241,16 +150,15 @@ namespace Sessions
|
||||
|
||||
UDP_Session* UDP_FixedPort::NewClientSession(ConnectionKey parNewKey, bool parIsBrodcast, bool parIsMulticast)
|
||||
{
|
||||
// Lock the whole function so we can't race between the open check and creating the session
|
||||
std::lock_guard numberlock(connectionSentry);
|
||||
if (!open.load())
|
||||
return nullptr;
|
||||
|
||||
UDP_Session* s = new UDP_Session(parNewKey, adapterIP, parIsBrodcast, parIsMulticast, client);
|
||||
|
||||
s->AddConnectionClosedHandler([&](BaseSession* session) { HandleChildConnectionClosed(session); });
|
||||
{
|
||||
std::lock_guard numberlock(connectionSentry);
|
||||
connections.push_back(s);
|
||||
}
|
||||
connections.push_back(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -272,6 +180,8 @@ namespace Sessions
|
||||
|
||||
UDP_FixedPort::~UDP_FixedPort()
|
||||
{
|
||||
DevCon.WriteLn("DEV9: Socket: UDPFixedPort %d had %d child connections", port, connections.size());
|
||||
|
||||
open.store(false);
|
||||
if (client != INVALID_SOCKET)
|
||||
{
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#endif
|
||||
|
||||
#include "UDP_Session.h"
|
||||
#include "UDP_Common.h"
|
||||
#include "DEV9/PacketReader/IP/UDP/UDP_Packet.h"
|
||||
|
||||
using namespace PacketReader;
|
||||
@@ -75,97 +76,17 @@ namespace Sessions
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
int ret;
|
||||
fd_set sReady;
|
||||
fd_set sExcept;
|
||||
std::optional<ReceivedPayload> ret;
|
||||
bool success;
|
||||
std::tie(ret, success) = UDP_Common::RecvFrom(client, srcPort);
|
||||
|
||||
timeval nowait{};
|
||||
FD_ZERO(&sReady);
|
||||
FD_ZERO(&sExcept);
|
||||
FD_SET(client, &sReady);
|
||||
FD_SET(client, &sExcept);
|
||||
ret = select(client + 1, &sReady, nullptr, &sExcept, &nowait);
|
||||
|
||||
bool hasData;
|
||||
if (ret == SOCKET_ERROR)
|
||||
if (!success)
|
||||
{
|
||||
hasData = false;
|
||||
Console.Error("DEV9: UDP: Select failed. Error code: %d",
|
||||
#ifdef _WIN32
|
||||
WSAGetLastError());
|
||||
#elif defined(__POSIX__)
|
||||
errno);
|
||||
#endif
|
||||
}
|
||||
else if (FD_ISSET(client, &sExcept))
|
||||
{
|
||||
hasData = false;
|
||||
|
||||
int error = 0;
|
||||
#ifdef _WIN32
|
||||
int len = sizeof(error);
|
||||
if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&error), &len) < 0)
|
||||
Console.Error("DEV9: UDP: Unknown UDP connection error (getsockopt error: %d)", WSAGetLastError());
|
||||
#elif defined(__POSIX__)
|
||||
socklen_t len = sizeof(error);
|
||||
if (getsockopt(client, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&error), &len) < 0)
|
||||
Console.Error("DEV9: UDP: Unknown UDP connection error (getsockopt error: %d)", errno);
|
||||
#endif
|
||||
else
|
||||
Console.Error("DEV9: UDP: Recv error: %d", error);
|
||||
}
|
||||
else
|
||||
hasData = FD_ISSET(client, &sReady);
|
||||
|
||||
if (hasData)
|
||||
{
|
||||
unsigned long available = 0;
|
||||
PayloadData* recived = nullptr;
|
||||
std::unique_ptr<u8[]> buffer;
|
||||
sockaddr_in endpoint{};
|
||||
|
||||
// FIONREAD returns total size of all available messages
|
||||
// however, we only read one message at a time
|
||||
#ifdef _WIN32
|
||||
ret = ioctlsocket(client, FIONREAD, &available);
|
||||
#elif defined(__POSIX__)
|
||||
ret = ioctl(client, FIONREAD, &available);
|
||||
#endif
|
||||
if (ret != SOCKET_ERROR)
|
||||
{
|
||||
buffer = std::make_unique<u8[]>(available);
|
||||
|
||||
#ifdef _WIN32
|
||||
int fromlen = sizeof(endpoint);
|
||||
#elif defined(__POSIX__)
|
||||
socklen_t fromlen = sizeof(endpoint);
|
||||
#endif
|
||||
ret = recvfrom(client, reinterpret_cast<char*>(buffer.get()), available, 0, reinterpret_cast<sockaddr*>(&endpoint), &fromlen);
|
||||
}
|
||||
|
||||
if (ret == SOCKET_ERROR)
|
||||
{
|
||||
Console.Error("DEV9: UDP: Recv error: %d",
|
||||
#ifdef _WIN32
|
||||
WSAGetLastError());
|
||||
#elif defined(__POSIX__)
|
||||
errno);
|
||||
#endif
|
||||
RaiseEventConnectionClosed();
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
recived = new PayloadData(ret);
|
||||
memcpy(recived->data.get(), buffer.get(), ret);
|
||||
|
||||
std::unique_ptr<UDP_Packet> iRet = std::make_unique<UDP_Packet>(recived);
|
||||
iRet->destinationPort = srcPort;
|
||||
iRet->sourcePort = destPort;
|
||||
|
||||
deathClockStart.store(std::chrono::steady_clock::now());
|
||||
|
||||
return ReceivedPayload{destIP, std::move(iRet)};
|
||||
RaiseEventConnectionClosed();
|
||||
return std::nullopt;
|
||||
}
|
||||
else if (ret.has_value())
|
||||
return ret;
|
||||
|
||||
if (std::chrono::steady_clock::now() - deathClockStart.load() > MAX_IDLE)
|
||||
{
|
||||
@@ -211,54 +132,19 @@ namespace Sessions
|
||||
destPort = udp.destinationPort;
|
||||
srcPort = udp.sourcePort;
|
||||
|
||||
int ret;
|
||||
client = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
client = UDP_Common::CreateSocket(adapterIP, std::nullopt);
|
||||
if (client == INVALID_SOCKET)
|
||||
{
|
||||
Console.Error("DEV9: UDP: Failed to open socket. Error: %d",
|
||||
#ifdef _WIN32
|
||||
WSAGetLastError());
|
||||
#elif defined(__POSIX__)
|
||||
errno);
|
||||
#endif
|
||||
RaiseEventConnectionClosed();
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr int reuseAddress = true; // BOOL on Windows
|
||||
ret = setsockopt(client, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char*>(&reuseAddress), sizeof(reuseAddress));
|
||||
|
||||
if (ret == SOCKET_ERROR)
|
||||
Console.Error("DEV9: UDP: Failed to set SO_REUSEADDR. Error: %d",
|
||||
#ifdef _WIN32
|
||||
WSAGetLastError());
|
||||
#elif defined(__POSIX__)
|
||||
errno);
|
||||
#endif
|
||||
|
||||
if (adapterIP.integer != 0)
|
||||
{
|
||||
sockaddr_in endpoint{};
|
||||
endpoint.sin_family = AF_INET;
|
||||
endpoint.sin_addr = std::bit_cast<in_addr>(adapterIP);
|
||||
|
||||
ret = bind(client, reinterpret_cast<const sockaddr*>(&endpoint), sizeof(endpoint));
|
||||
|
||||
if (ret == SOCKET_ERROR)
|
||||
Console.Error("DEV9: UDP: Failed to bind socket. Error: %d",
|
||||
#ifdef _WIN32
|
||||
WSAGetLastError());
|
||||
#elif defined(__POSIX__)
|
||||
errno);
|
||||
#endif
|
||||
}
|
||||
|
||||
sockaddr_in endpoint{};
|
||||
endpoint.sin_family = AF_INET;
|
||||
endpoint.sin_addr = std::bit_cast<in_addr>(destIP);
|
||||
endpoint.sin_port = htons(destPort);
|
||||
|
||||
ret = connect(client, reinterpret_cast<const sockaddr*>(&endpoint), sizeof(endpoint));
|
||||
const int ret = connect(client, reinterpret_cast<const sockaddr*>(&endpoint), sizeof(endpoint));
|
||||
|
||||
if (ret == SOCKET_ERROR)
|
||||
{
|
||||
|
||||
@@ -203,14 +203,19 @@ bool SocketAdapter::recv(NetPacket* pkt)
|
||||
|
||||
ScopedGuard cleanup([&]() {
|
||||
// Garbage collect closed connections
|
||||
for (BaseSession* s : deleteQueueRecvThread)
|
||||
delete s;
|
||||
deleteQueueRecvThread.clear();
|
||||
if (deleteQueueRecvThread.size() != 0)
|
||||
{
|
||||
std::lock_guard deletelock(deleteRecvSentry);
|
||||
for (BaseSession* s : deleteQueueRecvThread)
|
||||
delete s;
|
||||
deleteQueueRecvThread.clear();
|
||||
}
|
||||
});
|
||||
|
||||
EthernetFrame* bFrame;
|
||||
if (!vRecBuffer.Dequeue(&bFrame))
|
||||
{
|
||||
std::lock_guard deletelock(deleteSendSentry);
|
||||
std::vector<ConnectionKey> keys = connections.GetKeys();
|
||||
for (size_t i = 0; i < keys.size(); i++)
|
||||
{
|
||||
@@ -259,9 +264,13 @@ bool SocketAdapter::send(NetPacket* pkt)
|
||||
pxAssert(std::this_thread::get_id() == sendThreadId);
|
||||
ScopedGuard cleanup([&]() {
|
||||
// Garbage collect closed connections
|
||||
for (BaseSession* s : deleteQueueSendThread)
|
||||
delete s;
|
||||
deleteQueueSendThread.clear();
|
||||
if (deleteQueueSendThread.size() != 0)
|
||||
{
|
||||
std::lock_guard deletelock(deleteSendSentry);
|
||||
for (BaseSession* s : deleteQueueSendThread)
|
||||
delete s;
|
||||
deleteQueueSendThread.clear();
|
||||
}
|
||||
});
|
||||
|
||||
EthernetFrame frame(pkt);
|
||||
@@ -375,6 +384,7 @@ bool SocketAdapter::SendIP(IP_Packet* ipPkt)
|
||||
Key.ip = ipPkt->destinationIP;
|
||||
Key.protocol = ipPkt->protocol;
|
||||
|
||||
std::lock_guard deletelock(deleteRecvSentry);
|
||||
switch (ipPkt->protocol) //(Prase Payload)
|
||||
{
|
||||
case (u8)IP_Type::ICMP:
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "net.h"
|
||||
@@ -23,14 +24,17 @@ class SocketAdapter : public NetAdapter
|
||||
bool initialized = false;
|
||||
PacketReader::IP::IP_Address adapterIP;
|
||||
|
||||
//Sentrys replaced by the requirment for each session class to have thread safe destructor
|
||||
|
||||
ThreadSafeMap<Sessions::ConnectionKey, Sessions::BaseSession*> connections;
|
||||
ThreadSafeMap<u16, Sessions::BaseSession*> fixedUDPPorts;
|
||||
|
||||
std::thread::id sendThreadId;
|
||||
std::vector<Sessions::BaseSession*> deleteQueueSendThread;
|
||||
std::vector<Sessions::BaseSession*> deleteQueueRecvThread;
|
||||
//Mutex to be held when processing the delete queue.
|
||||
//The Send thread will lock the RecvSentry to prevent the recv thread
|
||||
//from deleting a session the send thread might be currently working on.
|
||||
std::mutex deleteSendSentry;
|
||||
std::mutex deleteRecvSentry;
|
||||
|
||||
public:
|
||||
SocketAdapter();
|
||||
|
||||
@@ -285,6 +285,16 @@ BreakPointCond* CBreakPoints::GetBreakPointCondition(BreakPointCpu cpu, u32 addr
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CBreakPoints::ChangeBreakPointDescription(BreakPointCpu cpu, u32 addr, const std::string& description)
|
||||
{
|
||||
const size_t bp = FindBreakpoint(cpu, addr, true, false);
|
||||
if (bp != INVALID_BREAKPOINT)
|
||||
{
|
||||
breakPoints_[bp].description = description;
|
||||
Update();
|
||||
}
|
||||
}
|
||||
|
||||
void CBreakPoints::AddMemCheck(BreakPointCpu cpu, u32 start, u32 end, MemCheckCondition cond, MemCheckResult result)
|
||||
{
|
||||
// This will ruin any pending memchecks.
|
||||
@@ -356,6 +366,16 @@ void CBreakPoints::ChangeMemCheckAddCond(BreakPointCpu cpu, u32 start, u32 end,
|
||||
}
|
||||
}
|
||||
|
||||
void CBreakPoints::ChangeMemCheckDescription(BreakPointCpu cpu, u32 start, u32 end, const std::string& description)
|
||||
{
|
||||
const size_t mc = FindMemCheck(cpu, start, end);
|
||||
if (mc != INVALID_MEMCHECK)
|
||||
{
|
||||
memChecks_[mc].description = description;
|
||||
Update(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
void CBreakPoints::ClearAllMemChecks()
|
||||
{
|
||||
// This will ruin any pending memchecks.
|
||||
|
||||
@@ -37,6 +37,8 @@ struct BreakPoint
|
||||
BreakPointCond cond;
|
||||
BreakPointCpu cpu;
|
||||
|
||||
std::string description;
|
||||
|
||||
bool operator==(const BreakPoint& other) const
|
||||
{
|
||||
return addr == other.addr;
|
||||
@@ -78,6 +80,8 @@ struct MemCheck
|
||||
MemCheckResult result;
|
||||
BreakPointCpu cpu;
|
||||
|
||||
std::string description;
|
||||
|
||||
u32 numHits;
|
||||
|
||||
u32 lastPC;
|
||||
@@ -119,12 +123,14 @@ public:
|
||||
static void ChangeBreakPointAddCond(BreakPointCpu cpu, u32 addr, const BreakPointCond& cond);
|
||||
static void ChangeBreakPointRemoveCond(BreakPointCpu cpu, u32 addr);
|
||||
static BreakPointCond* GetBreakPointCondition(BreakPointCpu cpu, u32 addr);
|
||||
static void ChangeBreakPointDescription(BreakPointCpu cpu, u32 addr, const std::string& description);
|
||||
|
||||
static void AddMemCheck(BreakPointCpu cpu, u32 start, u32 end, MemCheckCondition cond, MemCheckResult result);
|
||||
static void RemoveMemCheck(BreakPointCpu cpu, u32 start, u32 end);
|
||||
static void ChangeMemCheck(BreakPointCpu cpu, u32 start, u32 end, MemCheckCondition cond, MemCheckResult result);
|
||||
static void ChangeMemCheckRemoveCond(BreakPointCpu cpu, u32 start, u32 end);
|
||||
static void ChangeMemCheckAddCond(BreakPointCpu cpu, u32 start, u32 end, const BreakPointCond& cond);
|
||||
static void ChangeMemCheckDescription(BreakPointCpu cpu, u32 start, u32 end, const std::string& description);
|
||||
static void ClearAllMemChecks();
|
||||
|
||||
static void SetSkipFirst(BreakPointCpu cpu, u32 pc);
|
||||
|
||||
@@ -435,6 +435,15 @@ void GSgifTransfer3(u8* mem, u32 size)
|
||||
|
||||
void GSvsync(u32 field, bool registers_written)
|
||||
{
|
||||
// Update this here because we need to check if the pending draw affects the current frame, so our regs need to be updated.
|
||||
g_gs_renderer->PCRTCDisplays.SetVideoMode(g_gs_renderer->GetVideoMode());
|
||||
g_gs_renderer->PCRTCDisplays.EnableDisplays(g_gs_renderer->m_regs->PMODE, g_gs_renderer->m_regs->SMODE2, g_gs_renderer->isReallyInterlaced());
|
||||
g_gs_renderer->PCRTCDisplays.CheckSameSource();
|
||||
g_gs_renderer->PCRTCDisplays.SetRects(0, g_gs_renderer->m_regs->DISP[0].DISPLAY, g_gs_renderer->m_regs->DISP[0].DISPFB);
|
||||
g_gs_renderer->PCRTCDisplays.SetRects(1, g_gs_renderer->m_regs->DISP[1].DISPLAY, g_gs_renderer->m_regs->DISP[1].DISPFB);
|
||||
g_gs_renderer->PCRTCDisplays.CalculateDisplayOffset(g_gs_renderer->m_scanmask_used);
|
||||
g_gs_renderer->PCRTCDisplays.CalculateFramebufferOffset(g_gs_renderer->m_scanmask_used);
|
||||
|
||||
// Do not move the flush into the VSync() method. It's here because EE transfers
|
||||
// get cleared in HW VSync, and may be needed for a buffered draw (FFX FMVs).
|
||||
g_gs_renderer->Flush(GSState::VSYNC);
|
||||
|
||||
@@ -119,6 +119,10 @@ GSState::~GSState()
|
||||
_aligned_free(m_vertex.buff);
|
||||
if (m_index.buff)
|
||||
_aligned_free(m_index.buff);
|
||||
if (m_draw_vertex.buff)
|
||||
_aligned_free(m_draw_vertex.buff);
|
||||
if (m_draw_index.buff)
|
||||
_aligned_free(m_draw_index.buff);
|
||||
}
|
||||
|
||||
std::string GSState::GetDrawDumpPath(const char* format, ...)
|
||||
@@ -467,7 +471,8 @@ void GSState::DumpVertices(const std::string& filename)
|
||||
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.R) << DEL;
|
||||
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.G) << DEL;
|
||||
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.B) << DEL;
|
||||
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.A);
|
||||
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.A) << DEL;
|
||||
file << "FOG: " << std::setfill('0') << std::setw(3) << unsigned(v.FOG);
|
||||
file << std::endl;
|
||||
}
|
||||
|
||||
@@ -849,7 +854,7 @@ void GSState::ApplyTEX0(GIFRegTEX0& TEX0)
|
||||
// Urban Chaos writes to the memory backing the CLUT in the middle of a shuffle, and
|
||||
// it's unclear whether the CLUT would actually get reloaded in that case.
|
||||
if (TEX0.CBP != m_mem.m_clut.GetCLUTCBP())
|
||||
m_channel_shuffle = false;
|
||||
m_channel_shuffle_abort = true;
|
||||
}
|
||||
|
||||
TEX0.CPSM &= 0xa; // 1010b
|
||||
@@ -1472,6 +1477,35 @@ void GSState::Flush(GSFlushReason reason)
|
||||
|
||||
if (m_index.tail > 0)
|
||||
{
|
||||
// Unless Vsync really needs the pending draw, don't do it when VSync happens as it can really screw up our heuristics when looking ahead.
|
||||
if (reason == VSYNC)
|
||||
{
|
||||
GSDrawingContext* draw_ctx = &m_prev_env.CTXT[m_prev_env.PRIM.CTXT];
|
||||
const u32 start_bp = GSLocalMemory::GetStartBlockAddress(draw_ctx->FRAME.Block(), draw_ctx->FRAME.FBW, draw_ctx->FRAME.PSM, temp_draw_rect);
|
||||
const u32 end_bp = GSLocalMemory::GetEndBlockAddress(draw_ctx->FRAME.Block(), draw_ctx->FRAME.FBW, draw_ctx->FRAME.PSM, temp_draw_rect);
|
||||
bool needs_flush[2] = {PCRTCDisplays.PCRTCDisplays[0].enabled, PCRTCDisplays.PCRTCDisplays[1].enabled};
|
||||
|
||||
if (PCRTCDisplays.PCRTCDisplays[1].enabled)
|
||||
{
|
||||
const u32 out_start_bp = GSLocalMemory::GetStartBlockAddress(PCRTCDisplays.PCRTCDisplays[1].Block(), PCRTCDisplays.PCRTCDisplays[1].FBW, PCRTCDisplays.PCRTCDisplays[1].PSM, PCRTCDisplays.PCRTCDisplays[1].framebufferRect);
|
||||
const u32 out_end_bp = GSLocalMemory::GetEndBlockAddress(PCRTCDisplays.PCRTCDisplays[1].Block(), PCRTCDisplays.PCRTCDisplays[1].FBW, PCRTCDisplays.PCRTCDisplays[1].PSM, PCRTCDisplays.PCRTCDisplays[1].framebufferRect);
|
||||
|
||||
if (out_start_bp > end_bp || out_end_bp < start_bp)
|
||||
needs_flush[1] = false;
|
||||
}
|
||||
|
||||
if (PCRTCDisplays.PCRTCDisplays[0].enabled)
|
||||
{
|
||||
const u32 out_start_bp = GSLocalMemory::GetStartBlockAddress(PCRTCDisplays.PCRTCDisplays[0].Block(), PCRTCDisplays.PCRTCDisplays[0].FBW, PCRTCDisplays.PCRTCDisplays[0].PSM, PCRTCDisplays.PCRTCDisplays[0].framebufferRect);
|
||||
const u32 out_end_bp = GSLocalMemory::GetEndBlockAddress(PCRTCDisplays.PCRTCDisplays[0].Block(), PCRTCDisplays.PCRTCDisplays[0].FBW, PCRTCDisplays.PCRTCDisplays[0].PSM, PCRTCDisplays.PCRTCDisplays[0].framebufferRect);
|
||||
|
||||
if (out_start_bp > end_bp || out_end_bp < start_bp)
|
||||
needs_flush[0] = false;
|
||||
}
|
||||
|
||||
if (!needs_flush[0] && !needs_flush[1])
|
||||
return;
|
||||
}
|
||||
m_state_flush_reason = reason;
|
||||
|
||||
// Used to prompt the current draw that it's modifying its own CLUT.
|
||||
@@ -1674,7 +1708,8 @@ void GSState::FlushPrim()
|
||||
Console.Warning("GS: Possible invalid draw, Frame PSM %x ZPSM %x", m_context->FRAME.PSM, m_context->ZBUF.PSM);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Update scissor, it may have been modified by a previous draw
|
||||
m_env.CTXT[PRIM->CTXT].UpdateScissor();
|
||||
m_vt.Update(m_vertex.buff, m_index.buff, m_vertex.tail, m_index.tail, GSUtil::GetPrimClass(PRIM->PRIM));
|
||||
|
||||
// Texel coordinate rounding
|
||||
@@ -1723,6 +1758,7 @@ void GSState::FlushPrim()
|
||||
|
||||
// Skip draw if Z test is enabled, but set to fail all pixels.
|
||||
const bool skip_draw = (m_context->TEST.ZTE && m_context->TEST.ZTST == ZTST_NEVER);
|
||||
m_quad_check_valid = false;
|
||||
|
||||
if (!skip_draw)
|
||||
Draw();
|
||||
@@ -1936,10 +1972,10 @@ void GSState::Write(const u8* mem, int len)
|
||||
m_draw_transfers.push_back(new_transfer);
|
||||
}
|
||||
|
||||
GL_CACHE("Write! %u ... => 0x%x W:%d F:%s (DIR %d%d), dPos(%d %d) size(%d %d)", s_transfer_n,
|
||||
GL_CACHE("Write! %u ... => 0x%x W:%d F:%s (DIR %d%d), dPos(%d %d) size(%d %d) draw %d", s_transfer_n,
|
||||
blit.DBP, blit.DBW, psm_str(blit.DPSM),
|
||||
m_env.TRXPOS.DIRX, m_env.TRXPOS.DIRY,
|
||||
m_env.TRXPOS.DSAX, m_env.TRXPOS.DSAY, w, h);
|
||||
m_env.TRXPOS.DSAX, m_env.TRXPOS.DSAY, w, h, s_n);
|
||||
|
||||
if (len >= m_tr.total)
|
||||
{
|
||||
@@ -2794,8 +2830,10 @@ void GSState::GrowVertexBuffer()
|
||||
const u32 maxcount = std::max<u32>(m_vertex.maxcount * 3 / 2, 10000);
|
||||
|
||||
GSVertex* vertex = static_cast<GSVertex*>(_aligned_malloc(sizeof(GSVertex) * maxcount, 32));
|
||||
GSVertex* draw_vertex = static_cast<GSVertex*>(_aligned_malloc(sizeof(GSVertex) * maxcount, 32));
|
||||
// Worst case index list is a list of points with vs expansion, 6 indices per point
|
||||
u16* index = static_cast<u16*>(_aligned_malloc(sizeof(u16) * maxcount * 6, 32));
|
||||
u16* draw_index = static_cast<u16*>(_aligned_malloc(sizeof(u16) * maxcount * 6, 32));
|
||||
|
||||
if (!vertex || !index)
|
||||
{
|
||||
@@ -2821,16 +2859,38 @@ void GSState::GrowVertexBuffer()
|
||||
_aligned_free(m_index.buff);
|
||||
}
|
||||
|
||||
if (m_draw_vertex.buff)
|
||||
{
|
||||
std::memcpy(draw_vertex, m_draw_vertex.buff, sizeof(GSVertex) * m_vertex.tail);
|
||||
|
||||
_aligned_free(m_draw_vertex.buff);
|
||||
}
|
||||
|
||||
if (m_draw_index.buff)
|
||||
{
|
||||
std::memcpy(draw_index, m_draw_index.buff, sizeof(u16) * m_index.tail);
|
||||
|
||||
_aligned_free(m_draw_index.buff);
|
||||
}
|
||||
|
||||
m_draw_vertex.buff = draw_vertex;
|
||||
m_draw_index.buff = draw_index;
|
||||
m_vertex.buff = vertex;
|
||||
m_vertex.maxcount = maxcount - 3; // -3 to have some space at the end of the buffer before DrawingKick can grow it
|
||||
m_index.buff = index;
|
||||
}
|
||||
|
||||
bool GSState::TrianglesAreQuads(bool shuffle_check) const
|
||||
bool GSState::TrianglesAreQuads(bool shuffle_check)
|
||||
{
|
||||
// If this is a quad, there should only be two distinct values for both X and Y, which
|
||||
// also happen to be the minimum/maximum bounds of the primitive.
|
||||
if (!shuffle_check && m_quad_check_valid)
|
||||
return m_are_quads;
|
||||
|
||||
const GSVertex* const v = m_vertex.buff;
|
||||
m_are_quads = false;
|
||||
m_quad_check_valid = !shuffle_check;
|
||||
|
||||
for (u32 idx = 0; idx < m_index.tail; idx += 6)
|
||||
{
|
||||
const u16* const i = m_index.buff + idx;
|
||||
@@ -2839,29 +2899,65 @@ bool GSState::TrianglesAreQuads(bool shuffle_check) const
|
||||
if (idx > 0)
|
||||
{
|
||||
const u16* const prev_tri= m_index.buff + (idx - 3);
|
||||
GIFRegXYZ vert = v[i[0]].XYZ;
|
||||
GIFRegXYZ last_vert = v[i[2]].XYZ;
|
||||
GIFRegXYZ new_verts[3] = {v[i[0]].XYZ, v[i[1]].XYZ, v[i[2]].XYZ};
|
||||
|
||||
if (shuffle_check)
|
||||
{
|
||||
vert.X -= 8 << 4;
|
||||
last_vert.X -= 8 << 4;
|
||||
new_verts[0].X -= 8 << 4;
|
||||
new_verts[1].X -= 8 << 4;
|
||||
new_verts[2].X -= 8 << 4;
|
||||
}
|
||||
u32 match_vert_count = 0;
|
||||
|
||||
if (vert != m_vertex.buff[prev_tri[0]].XYZ && vert != m_vertex.buff[prev_tri[1]].XYZ && vert != m_vertex.buff[prev_tri[2]].XYZ &&
|
||||
last_vert != m_vertex.buff[prev_tri[0]].XYZ && last_vert != m_vertex.buff[prev_tri[1]].XYZ && last_vert != m_vertex.buff[prev_tri[2]].XYZ)
|
||||
if (!(new_verts[0] != m_vertex.buff[prev_tri[0]].XYZ && new_verts[0] != m_vertex.buff[prev_tri[1]].XYZ && new_verts[0] != m_vertex.buff[prev_tri[2]].XYZ))
|
||||
match_vert_count++;
|
||||
if (!(new_verts[1] != m_vertex.buff[prev_tri[0]].XYZ && new_verts[1] != m_vertex.buff[prev_tri[1]].XYZ && new_verts[1] != m_vertex.buff[prev_tri[2]].XYZ))
|
||||
match_vert_count++;
|
||||
if (!(new_verts[2] != m_vertex.buff[prev_tri[0]].XYZ && new_verts[2] != m_vertex.buff[prev_tri[1]].XYZ && new_verts[2] != m_vertex.buff[prev_tri[2]].XYZ))
|
||||
match_vert_count++;
|
||||
|
||||
if (match_vert_count != 2)
|
||||
return false;
|
||||
}
|
||||
// Degenerate triangles should've been culled already, so we can check indices.
|
||||
u32 extra_verts = 0;
|
||||
for (u32 j = 3; j < 6; j++)
|
||||
// This doesn't really make much sense when it's a triangle strip as it will always have 1 extra vert, so check for distinct values for them.
|
||||
if (PRIM->PRIM != GS_TRIANGLESTRIP)
|
||||
{
|
||||
const u16 tri2_idx = i[j];
|
||||
if (tri2_idx != i[0] && tri2_idx != i[1] && tri2_idx != i[2])
|
||||
extra_verts++;
|
||||
u32 extra_verts = 0;
|
||||
for (u32 j = 3; j < 6; j++)
|
||||
{
|
||||
const u16 tri2_idx = i[j];
|
||||
if (tri2_idx != i[0] && tri2_idx != i[1] && tri2_idx != i[2])
|
||||
extra_verts++;
|
||||
}
|
||||
if (extra_verts == 1)
|
||||
continue;
|
||||
}
|
||||
else if (m_index.tail == 6)
|
||||
{
|
||||
const int first_X = m_vertex.buff[m_index.buff[0]].XYZ.X;
|
||||
const int first_Y = m_vertex.buff[m_index.buff[0]].XYZ.Y;
|
||||
const int second_X = m_vertex.buff[m_index.buff[1]].XYZ.X;
|
||||
const int second_Y = m_vertex.buff[m_index.buff[1]].XYZ.Y;
|
||||
const int third_X = m_vertex.buff[m_index.buff[2]].XYZ.X;
|
||||
const int third_Y = m_vertex.buff[m_index.buff[2]].XYZ.Y;
|
||||
const int new_X = m_vertex.buff[m_index.buff[5]].XYZ.X;
|
||||
const int new_Y = m_vertex.buff[m_index.buff[5]].XYZ.Y;
|
||||
|
||||
const int middle_Y = (second_Y >= third_Y) ? (third_Y + ((second_Y - third_Y) / 2)) : (second_Y + ((third_Y - second_Y) / 2));
|
||||
const int middle_X = (second_X >= third_X) ? (third_X + ((second_X - third_X) / 2)) : (second_X + ((third_X - second_X) / 2));
|
||||
const bool first_lt_X = first_X <= middle_X;
|
||||
const bool first_lt_Y = first_Y <= middle_Y;
|
||||
const bool new_lt_X = new_X <= middle_X;
|
||||
const bool new_lt_Y = new_Y <= middle_Y;
|
||||
|
||||
// Check if verts are on the same side. Not totally accurate, but should be good enough.
|
||||
if (first_lt_X == new_lt_X && new_lt_Y == first_lt_Y)
|
||||
return false;
|
||||
|
||||
m_prim_overlap = PRIM_OVERLAP_NO;
|
||||
break;
|
||||
}
|
||||
if (extra_verts == 1)
|
||||
continue;
|
||||
|
||||
// As a fallback, they might've used different vertices with a tri list, not strip.
|
||||
// Note that this won't work unless the quad is axis-aligned.
|
||||
@@ -2889,6 +2985,7 @@ bool GSState::TrianglesAreQuads(bool shuffle_check) const
|
||||
}
|
||||
}
|
||||
|
||||
m_are_quads = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3051,6 +3148,46 @@ bool GSState::SpriteDrawWithoutGaps()
|
||||
return true;
|
||||
}
|
||||
|
||||
// Assume it's small sprites. NFSMW and a few other games draw 32x32 sprites in rows to fill the screen.
|
||||
if (((first_dpY + 8) >> 4) == GSLocalMemory::m_psm[m_context->FRAME.PSM].pgs.y)
|
||||
{
|
||||
int lastXEdge = std::max(v[1].XYZ.X, v[0].XYZ.X);
|
||||
int lastYEdge = std::max(v[1].XYZ.Y, v[0].XYZ.Y);
|
||||
for (u32 i = 2; i < m_vertex.next; i += 2)
|
||||
{
|
||||
const int dpY = v[i + 1].XYZ.Y - v[i].XYZ.Y;
|
||||
|
||||
if (first_dpY != dpY)
|
||||
return false;
|
||||
|
||||
const int newYStart = std::min(v[i + 1].XYZ.Y, v[i].XYZ.Y);
|
||||
const int newXEdge = std::max(v[i + 1].XYZ.X, v[i].XYZ.X);
|
||||
if (lastYEdge != newYStart)
|
||||
{
|
||||
if (newYStart != static_cast<int>(m_context->XYOFFSET.OFY))
|
||||
return false;
|
||||
|
||||
const int newXStart = std::min(v[i + 1].XYZ.X, v[i].XYZ.X);
|
||||
|
||||
if (newXStart != lastXEdge)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int dpX = v[i + 1].XYZ.X - v[i].XYZ.X;
|
||||
if (first_dpX != dpX || lastXEdge != newXEdge)
|
||||
return false;
|
||||
}
|
||||
|
||||
lastXEdge = newXEdge;
|
||||
lastYEdge = std::max(v[i + 1].XYZ.Y, v[i].XYZ.Y);
|
||||
}
|
||||
|
||||
m_prim_overlap = PRIM_OVERLAP_NO;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3069,7 +3206,7 @@ void GSState::CalculatePrimitiveCoversWithoutGaps()
|
||||
}
|
||||
else if (m_vt.m_primclass == GS_TRIANGLE_CLASS)
|
||||
{
|
||||
m_primitive_covers_without_gaps = (m_index.tail == 6 && TrianglesAreQuads()) ? m_primitive_covers_without_gaps : GapsFound;
|
||||
m_primitive_covers_without_gaps = ((m_index.tail == 6 || ((m_index.tail % 6) == 0 && m_primitive_covers_without_gaps == FullCover)) && TrianglesAreQuads()) ? m_primitive_covers_without_gaps : GapsFound;
|
||||
return;
|
||||
}
|
||||
else if (m_vt.m_primclass != GS_SPRITE_CLASS)
|
||||
@@ -3094,6 +3231,16 @@ __forceinline bool GSState::IsAutoFlushDraw(u32 prim)
|
||||
if (!(GSUtil::GetChannelMask(m_context->TEX0.PSM) & GSUtil::GetChannelMask(m_context->FRAME.PSM, m_context->FRAME.FBMSK | ~(GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk))))
|
||||
return false;
|
||||
|
||||
// Try to detect shuffles, because these will not autoflush, they by design clash.
|
||||
if (GSLocalMemory::m_psm[m_context->FRAME.PSM].bpp == 16 && GSLocalMemory::m_psm[m_context->TEX0.PSM].bpp == 16)
|
||||
{
|
||||
// Pretty confident here...
|
||||
GSVertex* buffer = &m_vertex.buff[0];
|
||||
const bool const_spacing = std::abs(buffer[m_index.buff[0]].U - buffer[m_index.buff[0]].XYZ.X) == std::abs(m_v.U - m_v.XYZ.X) && std::abs(buffer[m_index.buff[1]].XYZ.X - buffer[m_index.buff[0]].XYZ.X) <= 256; // Lequal to 16 pixels apart.
|
||||
|
||||
if (const_spacing)
|
||||
return false;
|
||||
}
|
||||
const u32 frame_mask = GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk;
|
||||
const bool frame_hit = m_context->FRAME.Block() == m_context->TEX0.TBP0 && !(m_context->TEST.ATE && m_context->TEST.ATST == 0 && m_context->TEST.AFAIL == 2) && ((m_context->FRAME.FBMSK & frame_mask) != frame_mask);
|
||||
// There's a strange behaviour we need to test on a PS2 here, if the FRAME is a Z format, like Powerdrome something swaps over, and it seems Alpha Fail of "FB Only" writes to the Z.. it's odd.
|
||||
@@ -3859,7 +4006,8 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
|
||||
const GSVector2 grad(uv_range / pos_range);
|
||||
// Adjust texture range when sprites get scissor clipped. Since we linearly interpolate, this
|
||||
// optimization doesn't work when perspective correction is enabled.
|
||||
if (m_vt.m_primclass == GS_SPRITE_CLASS && PRIM->FST == 1 && m_primitive_covers_without_gaps != NoGapsType::GapsFound)
|
||||
// Allowing for quads when the gradiant is 1. It's not guaranteed (would need to check the grandient on each vector), but should be close enough.
|
||||
if (m_primitive_covers_without_gaps != NoGapsType::GapsFound && (m_vt.m_primclass == GS_SPRITE_CLASS || (m_vt.m_primclass == GS_TRIANGLE_CLASS && grad.x == 1.0f && grad.y == 1.0f && TrianglesAreQuads(false))))
|
||||
{
|
||||
// When coordinates are fractional, GS appears to draw to the right/bottom (effectively
|
||||
// taking the ceiling), not to the top/left (taking the floor).
|
||||
@@ -3870,11 +4018,24 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
|
||||
|
||||
const GSVertex* vert_first = &m_vertex.buff[m_index.buff[0]];
|
||||
const GSVertex* vert_second = &m_vertex.buff[m_index.buff[1]];
|
||||
const GSVertex* vert_third = &m_vertex.buff[m_index.buff[2]];
|
||||
|
||||
GSVector4 new_st = st;
|
||||
bool u_forward_check = false;
|
||||
bool x_forward_check = false;
|
||||
if (m_vt.m_primclass == GS_TRIANGLE_CLASS)
|
||||
{
|
||||
u_forward_check = PRIM->FST ? ((vert_first->U < vert_second->U) || (vert_first->U < vert_third->U)) : (((vert_first->ST.S / vert_first->RGBAQ.Q) < (vert_second->ST.S / vert_second->RGBAQ.Q)) || ((vert_first->ST.S / vert_first->RGBAQ.Q) < (vert_third->ST.S / vert_third->RGBAQ.Q)));
|
||||
x_forward_check = (vert_first->XYZ.X < vert_second->XYZ.X) || (vert_first->XYZ.X < vert_third->XYZ.X);
|
||||
}
|
||||
else
|
||||
{
|
||||
u_forward_check = PRIM->FST ? (vert_first->U < vert_second->U) : ((vert_first->ST.T / vert_first->RGBAQ.Q) < (vert_second->ST.T / vert_first->RGBAQ.Q));
|
||||
x_forward_check = vert_first->XYZ.Y < vert_second->XYZ.Y;
|
||||
}
|
||||
// Check if the UV coords are going in a different direction to the verts, if they match direction, no need to swap
|
||||
const bool u_forward = vert_first->U < vert_second->U;
|
||||
const bool x_forward = vert_first->XYZ.X < vert_second->XYZ.X;
|
||||
const bool u_forward = u_forward_check;
|
||||
const bool x_forward = x_forward_check;
|
||||
const bool swap_x = u_forward != x_forward;
|
||||
|
||||
if (int_rc.left < scissored_rc.left)
|
||||
@@ -3897,9 +4058,20 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
|
||||
st.x = new_st.x;
|
||||
st.z = new_st.z;
|
||||
}
|
||||
|
||||
const bool v_forward = vert_first->V < vert_second->V;
|
||||
const bool y_forward = vert_first->XYZ.Y < vert_second->XYZ.Y;
|
||||
bool v_forward_check = false;
|
||||
bool y_forward_check = false;
|
||||
if (m_vt.m_primclass == GS_TRIANGLE_CLASS)
|
||||
{
|
||||
v_forward_check = PRIM->FST ? ((vert_first->V < vert_second->V) || (vert_first->V < vert_third->V)) : (((vert_first->ST.T / vert_first->RGBAQ.Q) < (vert_second->ST.T / vert_second->RGBAQ.Q)) || ((vert_first->ST.T / vert_first->RGBAQ.Q) < (vert_third->ST.T / vert_third->RGBAQ.Q)));
|
||||
y_forward_check = (vert_first->XYZ.Y < vert_second->XYZ.Y) || (vert_first->XYZ.Y < vert_third->XYZ.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
v_forward_check = PRIM->FST ? (vert_first->V < vert_second->V) : ((vert_first->ST.T / vert_first->RGBAQ.Q) < (vert_second->ST.T / vert_first->RGBAQ.Q));
|
||||
y_forward_check = vert_first->XYZ.Y < vert_second->XYZ.Y;
|
||||
}
|
||||
const bool v_forward = v_forward_check;
|
||||
const bool y_forward = y_forward_check;
|
||||
const bool swap_y = v_forward != y_forward;
|
||||
|
||||
if (int_rc.top < scissored_rc.top)
|
||||
@@ -4409,7 +4581,7 @@ bool GSState::GSTransferBuffer::Update(int tw, int th, int bpp, int& len)
|
||||
{
|
||||
if (len > packet_size)
|
||||
{
|
||||
#if defined(PCSX2_DEVBUILD) || defined(_DEBUG)
|
||||
#if defined(_DEBUG)
|
||||
Console.Warning("GS transfer buffer overflow len %d remaining %d, tex_size %d tw %d th %d bpp %d", len, remaining, tex_size, tw, th, bpp);
|
||||
#endif
|
||||
}
|
||||
@@ -4669,10 +4841,16 @@ GSVector2i GSState::GSPCRTCRegs::GetFramebufferSize(int display)
|
||||
void GSState::GSPCRTCRegs::SetRects(int display, GSRegDISPLAY displayReg, GSRegDISPFB framebufferReg)
|
||||
{
|
||||
// Save framebuffer information first, while we're here.
|
||||
PCRTCDisplays[display].prevFramebufferReg.FBP = PCRTCDisplays[display].FBP;
|
||||
PCRTCDisplays[display].prevFramebufferReg.FBW = PCRTCDisplays[display].FBW;
|
||||
PCRTCDisplays[display].prevFramebufferReg.PSM = PCRTCDisplays[display].PSM;
|
||||
PCRTCDisplays[display].prevFramebufferReg.DBX = PCRTCDisplays[display].DBX;
|
||||
PCRTCDisplays[display].prevFramebufferReg.DBY = PCRTCDisplays[display].DBY;
|
||||
PCRTCDisplays[display].FBP = framebufferReg.FBP;
|
||||
PCRTCDisplays[display].FBW = framebufferReg.FBW;
|
||||
PCRTCDisplays[display].PSM = framebufferReg.PSM;
|
||||
PCRTCDisplays[display].prevFramebufferReg = framebufferReg;
|
||||
PCRTCDisplays[display].DBX = framebufferReg.DBX;
|
||||
PCRTCDisplays[display].DBY = framebufferReg.DBY;
|
||||
// Probably not really enabled but will cause a mess.
|
||||
// Q-Ball Billiards enables both circuits but doesn't set one of them up.
|
||||
if (PCRTCDisplays[display].FBW == 0 && displayReg.DW == 0 && displayReg.DH == 0 && displayReg.MAGH == 0)
|
||||
|
||||
@@ -145,6 +145,21 @@ protected:
|
||||
u32 tail;
|
||||
} m_index = {};
|
||||
|
||||
struct
|
||||
{
|
||||
GSVertex* buff;
|
||||
u32 head, tail, next, maxcount; // head: first vertex, tail: last vertex + 1, next: last indexed + 1
|
||||
u32 xy_tail;
|
||||
GSVector4i xy[4];
|
||||
GSVector4i xyhead;
|
||||
} m_draw_vertex = {};
|
||||
|
||||
struct
|
||||
{
|
||||
u16* buff;
|
||||
u32 tail;
|
||||
} m_draw_index = {};
|
||||
|
||||
void UpdateContext();
|
||||
void UpdateScissor();
|
||||
|
||||
@@ -219,11 +234,19 @@ public:
|
||||
GSVector4i temp_draw_rect = {};
|
||||
std::unique_ptr<GSDumpBase> m_dump;
|
||||
bool m_scissor_invalid = false;
|
||||
bool m_quad_check_valid = false;
|
||||
bool m_are_quads = false;
|
||||
bool m_nativeres = false;
|
||||
bool m_mipmap = false;
|
||||
bool m_texflush_flag = false;
|
||||
bool m_isPackedUV_HackFlag = false;
|
||||
bool m_channel_shuffle = false;
|
||||
bool m_using_temp_z = false;
|
||||
bool m_temp_z_full_copy = false;
|
||||
bool m_in_target_draw = false;
|
||||
bool m_channel_shuffle_abort = false;
|
||||
|
||||
u32 m_target_offset = 0;
|
||||
u8 m_scanmask_used = 0;
|
||||
u32 m_dirty_gs_regs = 0;
|
||||
int m_backed_up_ctx = 0;
|
||||
@@ -302,6 +325,8 @@ public:
|
||||
int FBP;
|
||||
int FBW;
|
||||
int PSM;
|
||||
int DBY;
|
||||
int DBX;
|
||||
GSRegDISPFB prevFramebufferReg;
|
||||
GSVector2i prevDisplayOffset;
|
||||
GSVector2i displayOffset;
|
||||
@@ -416,7 +441,7 @@ public:
|
||||
|
||||
void DumpVertices(const std::string& filename);
|
||||
|
||||
bool TrianglesAreQuads(bool shuffle_check = false) const;
|
||||
bool TrianglesAreQuads(bool shuffle_check = false);
|
||||
PRIM_OVERLAP PrimitiveOverlap();
|
||||
bool SpriteDrawWithoutGaps();
|
||||
void CalculatePrimitiveCoversWithoutGaps();
|
||||
|
||||
@@ -1599,6 +1599,11 @@ public:
|
||||
return loadh(&v);
|
||||
}
|
||||
|
||||
__forceinline static GSVector4i loadl(const GSVector2i& v)
|
||||
{
|
||||
return loadl(&v);
|
||||
}
|
||||
|
||||
__forceinline static GSVector4i load(const void* pl, const void* ph)
|
||||
{
|
||||
return loadh(ph, loadl(pl));
|
||||
|
||||
@@ -46,8 +46,8 @@ const char* shaderName(ShaderConvert value)
|
||||
case ShaderConvert::DATM_0: return "ps_datm0";
|
||||
case ShaderConvert::DATM_1_RTA_CORRECTION: return "ps_datm1_rta_correction";
|
||||
case ShaderConvert::DATM_0_RTA_CORRECTION: return "ps_datm0_rta_correction";
|
||||
case ShaderConvert::HDR_INIT: return "ps_hdr_init";
|
||||
case ShaderConvert::HDR_RESOLVE: return "ps_hdr_resolve";
|
||||
case ShaderConvert::COLCLIP_INIT: return "ps_colclip_init";
|
||||
case ShaderConvert::COLCLIP_RESOLVE: return "ps_colclip_resolve";
|
||||
case ShaderConvert::RTA_CORRECTION: return "ps_rta_correction";
|
||||
case ShaderConvert::RTA_DECORRECTION: return "ps_rta_decorrection";
|
||||
case ShaderConvert::TRANSPARENCY_FILTER: return "ps_filter_transparency";
|
||||
@@ -103,7 +103,9 @@ const char* shaderName(PresentShader value)
|
||||
enum class TextureLabel
|
||||
{
|
||||
ColorRT,
|
||||
HDRRT,
|
||||
ColorHQRT,
|
||||
ColorHDRRT,
|
||||
ColorClipRT,
|
||||
U16RT,
|
||||
U32RT,
|
||||
DepthStencil,
|
||||
@@ -127,8 +129,12 @@ static TextureLabel GetTextureLabel(GSTexture::Type type, GSTexture::Format form
|
||||
{
|
||||
case GSTexture::Format::Color:
|
||||
return TextureLabel::ColorRT;
|
||||
case GSTexture::Format::HDRColor:
|
||||
return TextureLabel::HDRRT;
|
||||
case GSTexture::Format::ColorHQ:
|
||||
return TextureLabel::ColorHQRT;
|
||||
case GSTexture::Format::ColorHDR:
|
||||
return TextureLabel::ColorHDRRT;
|
||||
case GSTexture::Format::ColorClip:
|
||||
return TextureLabel::ColorClipRT;
|
||||
case GSTexture::Format::UInt16:
|
||||
return TextureLabel::U16RT;
|
||||
case GSTexture::Format::UInt32:
|
||||
@@ -149,6 +155,7 @@ static TextureLabel GetTextureLabel(GSTexture::Type type, GSTexture::Format form
|
||||
case GSTexture::Format::BC2:
|
||||
case GSTexture::Format::BC3:
|
||||
case GSTexture::Format::BC7:
|
||||
case GSTexture::Format::ColorHDR:
|
||||
return TextureLabel::ReplacementTexture;
|
||||
default:
|
||||
return TextureLabel::Other;
|
||||
@@ -163,14 +170,19 @@ static TextureLabel GetTextureLabel(GSTexture::Type type, GSTexture::Format form
|
||||
}
|
||||
}
|
||||
|
||||
// Debug names
|
||||
static const char* TextureLabelString(TextureLabel label)
|
||||
{
|
||||
switch (label)
|
||||
{
|
||||
case TextureLabel::ColorRT:
|
||||
return "Color RT";
|
||||
case TextureLabel::HDRRT:
|
||||
return "HDR RT";
|
||||
case TextureLabel::ColorHQRT:
|
||||
return "Color HQ RT";
|
||||
case TextureLabel::ColorHDRRT:
|
||||
return "Color HDR RT";
|
||||
case TextureLabel::ColorClipRT:
|
||||
return "Color Clip RT";
|
||||
case TextureLabel::U16RT:
|
||||
return "U16 RT";
|
||||
case TextureLabel::U32RT:
|
||||
@@ -904,6 +916,7 @@ bool GSHWDrawConfig::BlendState::IsEffective(ColorMaskSelector colormask) const
|
||||
|
||||
// clang-format off
|
||||
|
||||
// Maps PS2 blend modes to our best approximation of them with PC hardware
|
||||
const std::array<HWBlend, 3*3*3*3> GSDevice::m_blendMap =
|
||||
{{
|
||||
{ BLEND_NO_REC , OP_ADD , CONST_ONE , CONST_ZERO} , // 0000: (Cs - Cs)*As + Cs ==> Cs
|
||||
|
||||
@@ -22,8 +22,8 @@ enum class ShaderConvert
|
||||
DATM_0,
|
||||
DATM_1_RTA_CORRECTION,
|
||||
DATM_0_RTA_CORRECTION,
|
||||
HDR_INIT,
|
||||
HDR_RESOLVE,
|
||||
COLCLIP_INIT,
|
||||
COLCLIP_RESOLVE,
|
||||
RTA_CORRECTION,
|
||||
RTA_DECORRECTION,
|
||||
TRANSPARENCY_FILTER,
|
||||
@@ -257,11 +257,15 @@ enum HWBlendFlags
|
||||
BLEND_A_MAX = 0x8000, // Impossible blending uses coeff bigger than 1
|
||||
};
|
||||
|
||||
// Determines the HW blend function for DX11/OGL
|
||||
// Determines the HW blend function for the video backend
|
||||
struct HWBlend
|
||||
{
|
||||
typedef u8 BlendOp; /*GSDevice::BlendOp*/
|
||||
typedef u8 BlendFactor; /*GSDevice::BlendFactor*/
|
||||
|
||||
u16 flags;
|
||||
u8 op, src, dst;
|
||||
BlendOp op;
|
||||
BlendFactor src, dst;
|
||||
};
|
||||
|
||||
struct alignas(16) GSHWDrawConfig
|
||||
@@ -354,12 +358,12 @@ struct alignas(16) GSHWDrawConfig
|
||||
u32 blend_c : 2;
|
||||
u32 blend_d : 2;
|
||||
u32 fixed_one_a : 1;
|
||||
u32 blend_hw : 3;
|
||||
u32 blend_hw : 3; /*HWBlendType*/
|
||||
u32 a_masked : 1;
|
||||
u32 hdr : 1;
|
||||
u32 colclip_hw : 1; // colclip (COLCLAMP off) emulation through HQ textures
|
||||
u32 rta_correction : 1;
|
||||
u32 rta_source_correction : 1;
|
||||
u32 colclip : 1;
|
||||
u32 colclip : 1; // COLCLAMP off (color blend outputs wrap around 0-255)
|
||||
u32 blend_mix : 2;
|
||||
u32 round_inv : 1; // Blending will invert the value, so rounding needs to go the other way
|
||||
u32 pabe : 1;
|
||||
@@ -631,26 +635,30 @@ struct alignas(16) GSHWDrawConfig
|
||||
return true;
|
||||
}
|
||||
};
|
||||
// For hardware rendering backends
|
||||
struct BlendState
|
||||
{
|
||||
typedef u8 BlendOp; /*GSDevice::BlendOp*/
|
||||
typedef u8 BlendFactor; /*GSDevice::BlendFactor*/
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u8 enable : 1;
|
||||
u8 constant_enable : 1;
|
||||
u8 op : 6;
|
||||
u8 src_factor : 4;
|
||||
u8 dst_factor : 4;
|
||||
u8 src_factor_alpha : 4;
|
||||
u8 dst_factor_alpha : 4;
|
||||
bool enable : 1;
|
||||
bool constant_enable : 1;
|
||||
BlendOp op : 6;
|
||||
BlendFactor src_factor : 4;
|
||||
BlendFactor dst_factor : 4;
|
||||
BlendFactor src_factor_alpha : 4;
|
||||
BlendFactor dst_factor_alpha : 4;
|
||||
u8 constant;
|
||||
};
|
||||
u32 key;
|
||||
};
|
||||
constexpr BlendState(): key(0) {}
|
||||
constexpr BlendState(bool enable_, u8 src_factor_, u8 dst_factor_, u8 op_,
|
||||
u8 src_alpha_factor_, u8 dst_alpha_factor_, bool constant_enable_, u8 constant_)
|
||||
constexpr BlendState(bool enable_, BlendFactor src_factor_, BlendFactor dst_factor_, BlendOp op_,
|
||||
BlendFactor src_alpha_factor_, BlendFactor dst_alpha_factor_, bool constant_enable_, u8 constant_)
|
||||
: key(0)
|
||||
{
|
||||
enable = enable_;
|
||||
@@ -675,7 +683,7 @@ struct alignas(16) GSHWDrawConfig
|
||||
Full, ///< Full emulation (using barriers / ROV)
|
||||
};
|
||||
|
||||
enum class HDRMode : u8
|
||||
enum class ColClipMode : u8
|
||||
{
|
||||
NoModify = 0,
|
||||
ConvertOnly = 1,
|
||||
@@ -730,7 +738,7 @@ struct alignas(16) GSHWDrawConfig
|
||||
struct BlendMultiPass
|
||||
{
|
||||
BlendState blend;
|
||||
u8 blend_hw;
|
||||
u8 blend_hw; /*HWBlendType*/
|
||||
u8 dither;
|
||||
bool enable;
|
||||
};
|
||||
@@ -742,9 +750,9 @@ struct alignas(16) GSHWDrawConfig
|
||||
PSConstantBuffer cb_ps;
|
||||
|
||||
// These are here as they need to be preserved between draws, and the state clear only does up to the constant buffers.
|
||||
HDRMode hdr_mode;
|
||||
GIFRegFRAME hdr_frame;
|
||||
GSVector4i hdr_update_area; ///< Area in the framebuffer which HDR will modify;
|
||||
ColClipMode colclip_mode;
|
||||
GIFRegFRAME colclip_frame;
|
||||
GSVector4i colclip_update_area; ///< Area in the framebuffer which colclip will modify;
|
||||
};
|
||||
|
||||
class GSDevice : public GSAlignedClass<32>
|
||||
@@ -865,7 +873,7 @@ protected:
|
||||
GSTexture* m_target_tmp = nullptr;
|
||||
GSTexture* m_current = nullptr;
|
||||
GSTexture* m_cas = nullptr;
|
||||
GSTexture* m_hdr_rt = nullptr; ///< Temp HDR texture
|
||||
GSTexture* m_colclip_rt = nullptr; ///< Temp hw colclip texture
|
||||
|
||||
bool AcquireWindow(bool recreate_window);
|
||||
|
||||
@@ -890,9 +898,9 @@ public:
|
||||
/// Returns a string containing current adapter in use.
|
||||
const std::string& GetName() const { return m_name; }
|
||||
|
||||
GSTexture* GetHDRTexture() const { return m_hdr_rt; }
|
||||
GSTexture* GetColorClipTexture() const { return m_colclip_rt; }
|
||||
|
||||
void SetHDRTexture(GSTexture* tex) { m_hdr_rt = tex; }
|
||||
void SetColorClipTexture(GSTexture* tex) { m_colclip_rt = tex; }
|
||||
|
||||
/// Returns a string representing the specified API.
|
||||
static const char* RenderAPIToString(RenderAPI api);
|
||||
|
||||
@@ -87,10 +87,6 @@ bool GSRenderer::Merge(int field)
|
||||
int y_offset[3] = { 0, 0, 0 };
|
||||
const bool feedback_merge = m_regs->EXTWRITE.WRITE == 1;
|
||||
|
||||
PCRTCDisplays.SetVideoMode(GetVideoMode());
|
||||
PCRTCDisplays.EnableDisplays(m_regs->PMODE, m_regs->SMODE2, isReallyInterlaced());
|
||||
PCRTCDisplays.CheckSameSource();
|
||||
|
||||
if (!PCRTCDisplays.PCRTCDisplays[0].enabled && !PCRTCDisplays.PCRTCDisplays[1].enabled)
|
||||
{
|
||||
m_real_size = GSVector2i(0, 0);
|
||||
@@ -101,11 +97,6 @@ bool GSRenderer::Merge(int field)
|
||||
const bool game_deinterlacing = (m_regs->DISP[0].DISPFB.DBY != PCRTCDisplays.PCRTCDisplays[0].prevFramebufferReg.DBY) !=
|
||||
(m_regs->DISP[1].DISPFB.DBY != PCRTCDisplays.PCRTCDisplays[1].prevFramebufferReg.DBY);
|
||||
|
||||
PCRTCDisplays.SetRects(0, m_regs->DISP[0].DISPLAY, m_regs->DISP[0].DISPFB);
|
||||
PCRTCDisplays.SetRects(1, m_regs->DISP[1].DISPLAY, m_regs->DISP[1].DISPFB);
|
||||
PCRTCDisplays.CalculateDisplayOffset(m_scanmask_used);
|
||||
PCRTCDisplays.CalculateFramebufferOffset(m_scanmask_used);
|
||||
|
||||
// Only need to check the right/bottom on software renderer, hardware always gets the full texture then cuts a bit out later.
|
||||
if (PCRTCDisplays.FrameRectMatch() && !PCRTCDisplays.FrameWrap() && !feedback_merge)
|
||||
{
|
||||
@@ -277,8 +268,25 @@ float GSRenderer::GetModXYOffset()
|
||||
|
||||
static float GetCurrentAspectRatioFloat(bool is_progressive)
|
||||
{
|
||||
static constexpr std::array<float, static_cast<size_t>(AspectRatioType::MaxCount) + 1> ars = {{4.0f / 3.0f, 4.0f / 3.0f, 4.0f / 3.0f, 16.0f / 9.0f, 10.0f / 7.0f, 3.0f / 2.0f}};
|
||||
return ars[static_cast<u32>(GSConfig.AspectRatio) + (3u * (is_progressive && GSConfig.AspectRatio == AspectRatioType::RAuto4_3_3_2))];
|
||||
switch (GSConfig.AspectRatio)
|
||||
{
|
||||
default:
|
||||
// We don't know the AR of the display here, nor we care about it
|
||||
case AspectRatioType::Stretch:
|
||||
case AspectRatioType::RAuto4_3_3_2:
|
||||
if (EmuConfig.CurrentCustomAspectRatio > 0.f)
|
||||
return EmuConfig.CurrentCustomAspectRatio;
|
||||
else if (is_progressive)
|
||||
return 3.0f / 2.0f;
|
||||
else
|
||||
return 4.0f / 3.0f;
|
||||
case AspectRatioType::R4_3:
|
||||
return 4.0f / 3.0f;
|
||||
case AspectRatioType::R16_9:
|
||||
return 16.0f / 9.0f;
|
||||
case AspectRatioType::R10_7:
|
||||
return 10.0f / 7.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static GSVector4 CalculateDrawDstRect(s32 window_width, s32 window_height, const GSVector4i& src_rect, const GSVector2i& src_size, GSDisplayAlignment alignment, bool flip_y, bool is_progressive)
|
||||
@@ -294,6 +302,9 @@ static GSVector4 CalculateDrawDstRect(s32 window_width, s32 window_height, const
|
||||
targetAr = 3.0f / 2.0f;
|
||||
else
|
||||
targetAr = 4.0f / 3.0f;
|
||||
// Fall back on the custom aspect ratio set by patches (e.g. 16:9, 21:9)
|
||||
if (EmuConfig.CurrentCustomAspectRatio > 0.f)
|
||||
targetAr = EmuConfig.CurrentCustomAspectRatio;
|
||||
}
|
||||
else if (EmuConfig.CurrentAspectRatio == AspectRatioType::R4_3)
|
||||
{
|
||||
|
||||
@@ -66,7 +66,9 @@ const char* GSTexture::GetFormatName(Format format)
|
||||
static constexpr const char* format_names[] = {
|
||||
"Invalid",
|
||||
"Color",
|
||||
"HDRColor",
|
||||
"ColorHQ",
|
||||
"ColorHDR",
|
||||
"ColorClip",
|
||||
"DepthStencil",
|
||||
"UNorm8",
|
||||
"UInt16",
|
||||
@@ -90,7 +92,9 @@ u32 GSTexture::GetCompressedBytesPerBlock(Format format)
|
||||
static constexpr u32 bytes_per_block[] = {
|
||||
1, // Invalid
|
||||
4, // Color/RGBA8
|
||||
8, // HDRColor/RGBA16
|
||||
4, // ColorHQ/RGB10A2
|
||||
8, // ColorHDR/RGBA16F
|
||||
8, // ColorClip/RGBA16
|
||||
4, // DepthStencil
|
||||
1, // UNorm8/R8
|
||||
2, // UInt16/R16UI
|
||||
@@ -99,7 +103,7 @@ u32 GSTexture::GetCompressedBytesPerBlock(Format format)
|
||||
8, // BC1 - 16 pixels in 64 bits
|
||||
16, // BC2 - 16 pixels in 128 bits
|
||||
16, // BC3 - 16 pixels in 128 bits
|
||||
16, // BC4 - 16 pixels in 128 bits
|
||||
16, // BC7 - 16 pixels in 128 bits
|
||||
};
|
||||
|
||||
return bytes_per_block[static_cast<u32>(format)];
|
||||
|
||||
@@ -22,15 +22,17 @@ public:
|
||||
Invalid = 0,
|
||||
RenderTarget = 1,
|
||||
DepthStencil,
|
||||
Texture,
|
||||
RWTexture,
|
||||
Texture, // Generic texture (usually is color textures loaded by the game)
|
||||
RWTexture, // UAV
|
||||
};
|
||||
|
||||
enum class Format : u8
|
||||
{
|
||||
Invalid = 0, ///< Used for initialization
|
||||
Color, ///< Standard (RGBA8) color texture
|
||||
HDRColor, ///< Color texture with more bits for colclip emulation (RGBA16Unorm)
|
||||
Color, ///< Standard (RGBA8) color texture (used to store most of PS2's textures)
|
||||
ColorHQ, ///< High quality (RGB10A2) color texture (no proper alpha)
|
||||
ColorHDR, ///< High dynamic range (RGBA16F) color texture
|
||||
ColorClip, ///< Color texture with more bits for colclip (wrap) emulation, given that blending requires 9bpc (RGBA16Unorm)
|
||||
DepthStencil, ///< Depth stencil texture
|
||||
UNorm8, ///< A8UNorm texture for paletted textures and the OSD font
|
||||
UInt16, ///< UInt16 texture for reading back 16-bit depth
|
||||
@@ -40,6 +42,7 @@ public:
|
||||
BC2, ///< BC2, aka DXT2/3 compressed texture for replacements
|
||||
BC3, ///< BC3, aka DXT4/5 compressed texture for replacements
|
||||
BC7, ///< BC7, aka BPTC compressed texture for replacements
|
||||
Last = BC7,
|
||||
};
|
||||
|
||||
enum class State : u8
|
||||
|
||||
@@ -87,6 +87,7 @@ std::vector<GSAdapterInfo> D3D::GetAdapterInfo(IDXGIFactory5* factory)
|
||||
ai.max_upscale_multiplier = GSGetMaxUpscaleMultiplier(ai.max_texture_size);
|
||||
|
||||
wil::com_ptr_nothrow<IDXGIOutput> output;
|
||||
// Only check the first output, which would be the primary display (if any is connected)
|
||||
if (SUCCEEDED(hr = adapter->EnumOutputs(0, &output)))
|
||||
{
|
||||
UINT num_modes = 0;
|
||||
@@ -111,7 +112,7 @@ std::vector<GSAdapterInfo> D3D::GetAdapterInfo(IDXGIFactory5* factory)
|
||||
ERROR_LOG("GetDisplayModeList() failed: {:08X}", static_cast<unsigned>(hr));
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (hr != DXGI_ERROR_NOT_FOUND)
|
||||
{
|
||||
ERROR_LOG("EnumOutputs() failed: {:08X}", static_cast<unsigned>(hr));
|
||||
}
|
||||
@@ -515,7 +516,7 @@ wil::com_ptr_nothrow<ID3DBlob> D3D::CompileShader(D3D::ShaderType type, D3D_FEAT
|
||||
}
|
||||
|
||||
static constexpr UINT flags_non_debug = D3DCOMPILE_OPTIMIZATION_LEVEL3;
|
||||
static constexpr UINT flags_debug = D3DCOMPILE_SKIP_OPTIMIZATION | D3DCOMPILE_DEBUG;
|
||||
static constexpr UINT flags_debug = D3DCOMPILE_SKIP_OPTIMIZATION | D3DCOMPILE_DEBUG | D3DCOMPILE_DEBUG_NAME_FOR_SOURCE;
|
||||
|
||||
wil::com_ptr_nothrow<ID3DBlob> blob;
|
||||
wil::com_ptr_nothrow<ID3DBlob> error_blob;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "GS/Renderers/DX11/D3D11ShaderCache.h"
|
||||
#include "GS/Renderers/DX11/GSDevice11.h"
|
||||
#include "GS/GS.h"
|
||||
|
||||
#include "Config.h"
|
||||
@@ -300,6 +301,12 @@ wil::com_ptr_nothrow<ID3D11VertexShader> D3D11ShaderCache::GetVertexShader(ID3D1
|
||||
return {};
|
||||
}
|
||||
|
||||
const char* shader_name = entry_point; // Ideally we'd feed in a proper name
|
||||
if (shader_name)
|
||||
{
|
||||
GSDevice11::SetD3DDebugObjectName(shader.get(), shader_name);
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
@@ -320,6 +327,12 @@ bool D3D11ShaderCache::GetVertexShaderAndInputLayout(ID3D11Device* device, ID3D1
|
||||
return {};
|
||||
}
|
||||
|
||||
const char* shader_name = entry_point; // Ideally we'd feed in a proper name
|
||||
if (shader_name)
|
||||
{
|
||||
GSDevice11::SetD3DDebugObjectName(actual_vs.get(), shader_name);
|
||||
}
|
||||
|
||||
hr = device->CreateInputLayout(layout, layout_size, blob->GetBufferPointer(), blob->GetBufferSize(), il);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
@@ -348,6 +361,12 @@ wil::com_ptr_nothrow<ID3D11PixelShader> D3D11ShaderCache::GetPixelShader(ID3D11D
|
||||
return {};
|
||||
}
|
||||
|
||||
const char* shader_name = entry_point; // Ideally we'd feed in a proper name
|
||||
if (shader_name)
|
||||
{
|
||||
GSDevice11::SetD3DDebugObjectName(shader.get(), shader_name);
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
@@ -368,6 +387,12 @@ wil::com_ptr_nothrow<ID3D11ComputeShader> D3D11ShaderCache::GetComputeShader(ID3
|
||||
return {};
|
||||
}
|
||||
|
||||
const char* shader_name = entry_point; // Ideally we'd feed in a proper name
|
||||
if (shader_name)
|
||||
{
|
||||
GSDevice11::SetD3DDebugObjectName(shader.get(), shader_name);
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
|
||||
@@ -1307,7 +1307,6 @@ void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
else
|
||||
{
|
||||
ds = GSVector2i(m_window_info.surface_width, m_window_info.surface_height);
|
||||
|
||||
}
|
||||
|
||||
// om
|
||||
@@ -1318,8 +1317,6 @@ void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
|
||||
OMSetBlendState(bs, 0);
|
||||
|
||||
|
||||
|
||||
// ia
|
||||
|
||||
const float left = dRect.x * 2 / ds.x - 1.0f;
|
||||
@@ -1336,7 +1333,6 @@ void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
};
|
||||
|
||||
|
||||
|
||||
IASetVertexBuffer(vertices, sizeof(vertices[0]), std::size(vertices));
|
||||
IASetInputLayout(m_convert.il.get());
|
||||
IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
@@ -1345,7 +1341,6 @@ void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
|
||||
VSSetShader(m_convert.vs.get(), nullptr);
|
||||
|
||||
|
||||
// ps
|
||||
|
||||
PSSetShaderResource(0, sTex);
|
||||
@@ -1382,8 +1377,6 @@ void GSDevice11::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
OMSetDepthStencilState(m_convert.dss.get(), 0);
|
||||
OMSetBlendState(m_convert.bs[D3D11_COLOR_WRITE_ENABLE_ALL].get(), 0);
|
||||
|
||||
|
||||
|
||||
// ia
|
||||
|
||||
const float left = dRect.x * 2 / ds.x - 1.0f;
|
||||
@@ -1399,8 +1392,6 @@ void GSDevice11::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
{GSVector4(right, bottom, 0.5f, 1.0f), GSVector2(sRect.z, sRect.w)},
|
||||
};
|
||||
|
||||
|
||||
|
||||
IASetVertexBuffer(vertices, sizeof(vertices[0]), std::size(vertices));
|
||||
IASetInputLayout(m_present.il.get());
|
||||
IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
@@ -1409,7 +1400,6 @@ void GSDevice11::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
|
||||
VSSetShader(m_present.vs.get(), nullptr);
|
||||
|
||||
|
||||
// ps
|
||||
|
||||
PSSetShaderResource(0, sTex);
|
||||
@@ -1748,7 +1738,7 @@ void GSDevice11::SetupPS(const PSSelector& sel, const GSHWDrawConfig::PSConstant
|
||||
sm.AddMacro("PS_DST_FMT", sel.dst_fmt);
|
||||
sm.AddMacro("PS_DEPTH_FMT", sel.depth_fmt);
|
||||
sm.AddMacro("PS_PAL_FMT", sel.pal_fmt);
|
||||
sm.AddMacro("PS_HDR", sel.hdr);
|
||||
sm.AddMacro("PS_COLCLIP_HW", sel.colclip_hw);
|
||||
sm.AddMacro("PS_RTA_CORRECTION", sel.rta_correction);
|
||||
sm.AddMacro("PS_RTA_SRC_CORRECTION", sel.rta_source_correction);
|
||||
sm.AddMacro("PS_COLCLIP", sel.colclip);
|
||||
@@ -2182,8 +2172,6 @@ void GSDevice11::SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vert
|
||||
//
|
||||
|
||||
DrawPrimitive();
|
||||
|
||||
//
|
||||
}
|
||||
|
||||
void* GSDevice11::IAMapVertexBuffer(u32 stride, u32 count)
|
||||
@@ -2521,43 +2509,43 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
|
||||
GSVector2i rtsize = (config.rt ? config.rt : config.ds)->GetSize();
|
||||
|
||||
GSTexture* hdr_rt = g_gs_device->GetHDRTexture();
|
||||
GSTexture* colclip_rt = g_gs_device->GetColorClipTexture();
|
||||
|
||||
if (hdr_rt)
|
||||
if (colclip_rt)
|
||||
{
|
||||
if (config.hdr_mode == GSHWDrawConfig::HDRMode::EarlyResolve)
|
||||
if (config.colclip_mode == GSHWDrawConfig::ColClipMode::EarlyResolve)
|
||||
{
|
||||
const GSVector2i size = config.rt->GetSize();
|
||||
const GSVector4 dRect(config.hdr_update_area);
|
||||
const GSVector4 dRect(config.colclip_update_area);
|
||||
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
|
||||
StretchRect(hdr_rt, sRect, config.rt, dRect, ShaderConvert::HDR_RESOLVE, false);
|
||||
StretchRect(colclip_rt, sRect, config.rt, dRect, ShaderConvert::COLCLIP_RESOLVE, false);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
Recycle(hdr_rt);
|
||||
Recycle(colclip_rt);
|
||||
|
||||
g_gs_device->SetHDRTexture(nullptr);
|
||||
g_gs_device->SetColorClipTexture(nullptr);
|
||||
|
||||
hdr_rt = nullptr;
|
||||
colclip_rt = nullptr;
|
||||
}
|
||||
else
|
||||
config.ps.hdr = 1;
|
||||
config.ps.colclip_hw = 1;
|
||||
}
|
||||
|
||||
if (config.ps.hdr)
|
||||
if (config.ps.colclip_hw)
|
||||
{
|
||||
if (!hdr_rt)
|
||||
if (!colclip_rt)
|
||||
{
|
||||
config.hdr_update_area = config.drawarea;
|
||||
config.colclip_update_area = config.drawarea;
|
||||
|
||||
const GSVector4 dRect = GSVector4((config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly) ? GSVector4i::loadh(rtsize) : config.drawarea);
|
||||
const GSVector4 dRect = GSVector4((config.colclip_mode == GSHWDrawConfig::ColClipMode::ConvertOnly) ? GSVector4i::loadh(rtsize) : config.drawarea);
|
||||
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
|
||||
hdr_rt = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor);
|
||||
if (!hdr_rt)
|
||||
colclip_rt = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::ColorClip);
|
||||
if (!colclip_rt)
|
||||
return;
|
||||
|
||||
g_gs_device->SetHDRTexture(hdr_rt);
|
||||
g_gs_device->SetColorClipTexture(colclip_rt);
|
||||
// Warning: StretchRect must be called before BeginScene otherwise
|
||||
// vertices will be overwritten. Trust me you don't want to do that.
|
||||
StretchRect(config.rt, sRect, hdr_rt, dRect, ShaderConvert::HDR_INIT, false);
|
||||
StretchRect(config.rt, sRect, colclip_rt, dRect, ShaderConvert::COLCLIP_INIT, false);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
}
|
||||
}
|
||||
@@ -2569,7 +2557,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
if (!primid_tex)
|
||||
return;
|
||||
|
||||
StretchRect(hdr_rt ? hdr_rt : config.rt, GSVector4(config.drawarea) / GSVector4(rtsize).xyxy(),
|
||||
StretchRect(colclip_rt ? colclip_rt : config.rt, GSVector4(config.drawarea) / GSVector4(rtsize).xyxy(),
|
||||
primid_tex, GSVector4(config.drawarea), m_date.primid_init_ps[static_cast<u8>(config.datm)].get(), nullptr, false);
|
||||
}
|
||||
else if (config.destination_alpha != GSHWDrawConfig::DestinationAlphaMode::Off)
|
||||
@@ -2585,7 +2573,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
{GSVector4(dst.z, -dst.w, 0.5f, 1.0f), GSVector2(src.z, src.w)},
|
||||
};
|
||||
|
||||
SetupDATE(hdr_rt ? hdr_rt : config.rt, config.ds, vertices, config.datm);
|
||||
SetupDATE(colclip_rt ? colclip_rt : config.rt, config.ds, vertices, config.datm);
|
||||
}
|
||||
|
||||
if (config.vs.expand != GSHWDrawConfig::VSExpand::None)
|
||||
@@ -2643,13 +2631,13 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
}
|
||||
|
||||
GSTexture* rt_copy = nullptr;
|
||||
if (config.require_one_barrier || (config.tex && config.tex == config.rt)) // Used as "bind rt" flag when texture barrier is unsupported
|
||||
if (config.require_one_barrier || (config.tex && config.tex == config.rt)) // Used as "bind rt" flag when texture barrier is unsupported.
|
||||
{
|
||||
// Bind the RT.This way special effect can use it.
|
||||
// Do not always bind the rt when it's not needed,
|
||||
// only bind it when effects use it such as fbmask emulation currently
|
||||
// because we copy the frame buffer and it is quite slow.
|
||||
CloneTexture(hdr_rt ? hdr_rt : config.rt, &rt_copy, config.drawarea);
|
||||
CloneTexture(colclip_rt ? colclip_rt : config.rt, &rt_copy, config.drawarea);
|
||||
if (rt_copy)
|
||||
{
|
||||
if (config.require_one_barrier)
|
||||
@@ -2679,7 +2667,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
}
|
||||
|
||||
SetupOM(config.depth, OMBlendSelector(config.colormask, config.blend), config.blend.constant);
|
||||
OMSetRenderTargets(hdr_rt ? hdr_rt : config.rt, config.ds, &config.scissor);
|
||||
OMSetRenderTargets(colclip_rt ? colclip_rt : config.rt, config.ds, &config.scissor);
|
||||
DrawIndexedPrimitive();
|
||||
|
||||
if (config.blend_multi_pass.enable)
|
||||
@@ -2714,20 +2702,20 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
if (primid_tex)
|
||||
Recycle(primid_tex);
|
||||
|
||||
if (hdr_rt)
|
||||
if (colclip_rt)
|
||||
{
|
||||
config.hdr_update_area = config.hdr_update_area.runion(config.drawarea);
|
||||
config.colclip_update_area = config.colclip_update_area.runion(config.drawarea);
|
||||
|
||||
if (config.hdr_mode == GSHWDrawConfig::HDRMode::ResolveOnly || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve)
|
||||
if (config.colclip_mode == GSHWDrawConfig::ColClipMode::ResolveOnly || config.colclip_mode == GSHWDrawConfig::ColClipMode::ConvertAndResolve)
|
||||
{
|
||||
const GSVector2i size = config.rt->GetSize();
|
||||
const GSVector4 dRect(config.hdr_update_area);
|
||||
const GSVector4 dRect(config.colclip_update_area);
|
||||
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
|
||||
StretchRect(hdr_rt, sRect, config.rt, dRect, ShaderConvert::HDR_RESOLVE, false);
|
||||
StretchRect(colclip_rt, sRect, config.rt, dRect, ShaderConvert::COLCLIP_RESOLVE, false);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
Recycle(hdr_rt);
|
||||
Recycle(colclip_rt);
|
||||
|
||||
g_gs_device->SetHDRTexture(nullptr);
|
||||
g_gs_device->SetColorClipTexture(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,9 @@ DXGI_FORMAT GSTexture11::GetDXGIFormat(Format format)
|
||||
switch (format)
|
||||
{
|
||||
case GSTexture::Format::Color: return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case GSTexture::Format::HDRColor: return DXGI_FORMAT_R16G16B16A16_UNORM;
|
||||
case GSTexture::Format::ColorHQ: return DXGI_FORMAT_R10G10B10A2_UNORM;
|
||||
case GSTexture::Format::ColorHDR: return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
case GSTexture::Format::ColorClip: return DXGI_FORMAT_R16G16B16A16_UNORM;
|
||||
case GSTexture::Format::DepthStencil: return DXGI_FORMAT_R32G8X24_TYPELESS;
|
||||
case GSTexture::Format::UNorm8: return DXGI_FORMAT_A8_UNORM;
|
||||
case GSTexture::Format::UInt16: return DXGI_FORMAT_R16_UINT;
|
||||
|
||||
@@ -739,7 +739,9 @@ bool GSDevice12::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
return false;
|
||||
}
|
||||
|
||||
CompileCASPipelines();
|
||||
if (!CompileCASPipelines())
|
||||
return false;
|
||||
|
||||
if (!CompileImGuiPipeline())
|
||||
return false;
|
||||
|
||||
@@ -1265,13 +1267,17 @@ void GSDevice12::DrawIndexedPrimitive(int offset, int count)
|
||||
void GSDevice12::LookupNativeFormat(GSTexture::Format format, DXGI_FORMAT* d3d_format, DXGI_FORMAT* srv_format,
|
||||
DXGI_FORMAT* rtv_format, DXGI_FORMAT* dsv_format) const
|
||||
{
|
||||
static constexpr std::array<std::array<DXGI_FORMAT, 4>, static_cast<int>(GSTexture::Format::BC7) + 1>
|
||||
static constexpr std::array<std::array<DXGI_FORMAT, 4>, static_cast<int>(GSTexture::Format::Last) + 1>
|
||||
s_format_mapping = {{
|
||||
{DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN}, // Invalid
|
||||
{DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
DXGI_FORMAT_UNKNOWN}, // Color
|
||||
{DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM,
|
||||
DXGI_FORMAT_UNKNOWN}, // ColorHQ
|
||||
{DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT,
|
||||
DXGI_FORMAT_UNKNOWN}, // ColorHDR
|
||||
{DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM,
|
||||
DXGI_FORMAT_UNKNOWN}, // HDRColor
|
||||
DXGI_FORMAT_UNKNOWN}, // ColorClip
|
||||
{DXGI_FORMAT_D32_FLOAT_S8X24_UINT, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, DXGI_FORMAT_UNKNOWN,
|
||||
DXGI_FORMAT_D32_FLOAT_S8X24_UINT}, // DepthStencil
|
||||
{DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_UNKNOWN}, // UNorm8
|
||||
@@ -1424,9 +1430,10 @@ void GSDevice12::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
GL_PUSH("ColorCopy Red:%d Green:%d Blue:%d Alpha:%d", red, green, blue, alpha);
|
||||
|
||||
const u32 index = (red ? 1 : 0) | (green ? 2 : 0) | (blue ? 4 : 0) | (alpha ? 8 : 0);
|
||||
int rta_offset = (shader == ShaderConvert::RTA_CORRECTION) ? 16 : 0;
|
||||
const bool allow_discard = (index == 0xf);
|
||||
DoStretchRect(static_cast<GSTexture12*>(sTex), sRect, static_cast<GSTexture12*>(dTex), dRect,
|
||||
m_color_copy[index].get(), false, allow_discard);
|
||||
m_color_copy[index + rta_offset].get(), false, allow_discard);
|
||||
}
|
||||
|
||||
void GSDevice12::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
@@ -2520,13 +2527,6 @@ bool GSDevice12::CompileConvertPipelines()
|
||||
// compile color copy pipelines
|
||||
gpb.SetRenderTarget(0, DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
gpb.SetDepthStencilFormat(DXGI_FORMAT_UNKNOWN);
|
||||
|
||||
ComPtr<ID3DBlob> ps(GetUtilityPixelShader(*shader, shaderName(i)));
|
||||
if (!ps)
|
||||
return false;
|
||||
|
||||
gpb.SetPixelShader(ps.get());
|
||||
|
||||
for (u32 j = 16; j < 32; j++)
|
||||
{
|
||||
pxAssert(!m_color_copy[j]);
|
||||
@@ -2540,10 +2540,10 @@ bool GSDevice12::CompileConvertPipelines()
|
||||
j & 1u, (j >> 1) & 1u, (j >> 2) & 1u, (j >> 3) & 1u));
|
||||
}
|
||||
}
|
||||
else if (i == ShaderConvert::HDR_INIT || i == ShaderConvert::HDR_RESOLVE)
|
||||
else if (i == ShaderConvert::COLCLIP_INIT || i == ShaderConvert::COLCLIP_RESOLVE)
|
||||
{
|
||||
const bool is_setup = i == ShaderConvert::HDR_INIT;
|
||||
std::array<ComPtr<ID3D12PipelineState>, 2>& arr = is_setup ? m_hdr_setup_pipelines : m_hdr_finish_pipelines;
|
||||
const bool is_setup = i == ShaderConvert::COLCLIP_INIT;
|
||||
std::array<ComPtr<ID3D12PipelineState>, 2>& arr = is_setup ? m_colclip_setup_pipelines : m_colclip_finish_pipelines;
|
||||
for (u32 ds = 0; ds < 2; ds++)
|
||||
{
|
||||
pxAssert(!arr[ds]);
|
||||
@@ -2554,7 +2554,7 @@ bool GSDevice12::CompileConvertPipelines()
|
||||
if (!arr[ds])
|
||||
return false;
|
||||
|
||||
D3D12::SetObjectName(arr[ds].get(), TinyString::from_format("HDR {}/copy pipeline (ds={})", is_setup ? "setup" : "finish", ds));
|
||||
D3D12::SetObjectName(arr[ds].get(), TinyString::from_format("ColorClip {}/copy pipeline (ds={})", is_setup ? "setup" : "finish", ds));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2598,8 +2598,8 @@ bool GSDevice12::CompilePresentPipelines()
|
||||
return false;
|
||||
}
|
||||
|
||||
ComPtr<ID3DBlob> m_convert_vs = GetUtilityVertexShader(*shader, "vs_main");
|
||||
if (!m_convert_vs)
|
||||
ComPtr<ID3DBlob> vs = GetUtilityVertexShader(*shader, "vs_main");
|
||||
if (!vs)
|
||||
return false;
|
||||
|
||||
D3D12::GraphicsPipelineBuilder gpb;
|
||||
@@ -2607,7 +2607,7 @@ bool GSDevice12::CompilePresentPipelines()
|
||||
AddUtilityVertexAttributes(gpb);
|
||||
gpb.SetNoCullRasterizationState();
|
||||
gpb.SetNoBlendingState();
|
||||
gpb.SetVertexShader(m_convert_vs.get());
|
||||
gpb.SetVertexShader(vs.get());
|
||||
gpb.SetDepthState(false, false, D3D12_COMPARISON_FUNC_ALWAYS);
|
||||
gpb.SetNoStencilState();
|
||||
gpb.SetRenderTarget(0, DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
@@ -2663,7 +2663,7 @@ bool GSDevice12::CompileInterlacePipelines()
|
||||
if (!m_interlace[i])
|
||||
return false;
|
||||
|
||||
D3D12::SetObjectName(m_convert[i].get(), TinyString::from_format("Interlace pipeline {}", static_cast<int>(i)));
|
||||
D3D12::SetObjectName(m_interlace[i].get(), TinyString::from_format("Interlace pipeline {}", static_cast<int>(i)));
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -2700,7 +2700,7 @@ bool GSDevice12::CompileMergePipelines()
|
||||
if (!m_merge[i])
|
||||
return false;
|
||||
|
||||
D3D12::SetObjectName(m_convert[i].get(), TinyString::from_format("Merge pipeline {}", i));
|
||||
D3D12::SetObjectName(m_merge[i].get(), TinyString::from_format("Merge pipeline {}", i));
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -2780,8 +2780,8 @@ void GSDevice12::DestroyResources()
|
||||
m_color_copy = {};
|
||||
m_present = {};
|
||||
m_convert = {};
|
||||
m_hdr_setup_pipelines = {};
|
||||
m_hdr_finish_pipelines = {};
|
||||
m_colclip_setup_pipelines = {};
|
||||
m_colclip_finish_pipelines = {};
|
||||
m_date_image_setup_pipelines = {};
|
||||
m_fxaa_pipeline.reset();
|
||||
m_shadeboost_pipeline.reset();
|
||||
@@ -2897,7 +2897,7 @@ const ID3DBlob* GSDevice12::GetTFXPixelShader(const GSHWDrawConfig::PSSelector&
|
||||
sm.AddMacro("PS_DST_FMT", sel.dst_fmt);
|
||||
sm.AddMacro("PS_DEPTH_FMT", sel.depth_fmt);
|
||||
sm.AddMacro("PS_PAL_FMT", sel.pal_fmt);
|
||||
sm.AddMacro("PS_HDR", sel.hdr);
|
||||
sm.AddMacro("PS_COLCLIP_HW", sel.colclip_hw);
|
||||
sm.AddMacro("PS_RTA_CORRECTION", sel.rta_correction);
|
||||
sm.AddMacro("PS_RTA_SRC_CORRECTION", sel.rta_source_correction);
|
||||
sm.AddMacro("PS_COLCLIP", sel.colclip);
|
||||
@@ -2955,7 +2955,7 @@ GSDevice12::ComPtr<ID3D12PipelineState> GSDevice12::CreateTFXPipeline(const Pipe
|
||||
{
|
||||
const GSTexture::Format format = IsDATEModePrimIDInit(p.ps.date) ?
|
||||
GSTexture::Format::PrimID :
|
||||
(p.ps.hdr ? GSTexture::Format::HDRColor : GSTexture::Format::Color);
|
||||
(p.ps.colclip_hw ? GSTexture::Format::ColorClip : GSTexture::Format::Color);
|
||||
|
||||
DXGI_FORMAT native_format;
|
||||
LookupNativeFormat(format, nullptr, nullptr, &native_format, nullptr);
|
||||
@@ -3817,7 +3817,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
const bool stencil_DATE = (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::Stencil ||
|
||||
config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne);
|
||||
|
||||
GSTexture12* hdr_rt = static_cast<GSTexture12*>(g_gs_device->GetHDRTexture());
|
||||
GSTexture12* colclip_rt = static_cast<GSTexture12*>(g_gs_device->GetColorClipTexture());
|
||||
GSTexture12* draw_rt = static_cast<GSTexture12*>(config.rt);
|
||||
GSTexture12* draw_ds = static_cast<GSTexture12*>(config.ds);
|
||||
GSTexture12* draw_rt_clone = nullptr;
|
||||
@@ -3830,15 +3830,15 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
// figure out the pipeline
|
||||
UpdateHWPipelineSelector(config);
|
||||
|
||||
// now blit the hdr texture back to the original target
|
||||
if (hdr_rt)
|
||||
// now blit the colclip texture back to the original target
|
||||
if (colclip_rt)
|
||||
{
|
||||
if (config.hdr_mode == GSHWDrawConfig::HDRMode::EarlyResolve)
|
||||
if (config.colclip_mode == GSHWDrawConfig::ColClipMode::EarlyResolve)
|
||||
{
|
||||
GL_PUSH("Blit HDR back to RT");
|
||||
GL_PUSH("Blit ColorClip back to RT");
|
||||
|
||||
EndRenderPass();
|
||||
hdr_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
colclip_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
|
||||
draw_rt = static_cast<GSTexture12*>(config.rt);
|
||||
OMSetRenderTargets(draw_rt, draw_ds, config.scissor);
|
||||
@@ -3850,19 +3850,19 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
draw_rt->GetUNormClearColor(), 0.0f, 0);
|
||||
|
||||
const GSVector4 sRect(GSVector4(config.hdr_update_area) / GSVector4(rtsize.x, rtsize.y).xyxy());
|
||||
SetPipeline(m_hdr_finish_pipelines[pipe.ds].get());
|
||||
SetUtilityTexture(hdr_rt, m_point_sampler_cpu);
|
||||
DrawStretchRect(sRect, GSVector4(config.hdr_update_area), rtsize);
|
||||
const GSVector4 sRect(GSVector4(config.colclip_update_area) / GSVector4(rtsize.x, rtsize.y).xyxy());
|
||||
SetPipeline(m_colclip_finish_pipelines[pipe.ds].get());
|
||||
SetUtilityTexture(colclip_rt, m_point_sampler_cpu);
|
||||
DrawStretchRect(sRect, GSVector4(config.colclip_update_area), rtsize);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
|
||||
Recycle(hdr_rt);
|
||||
g_gs_device->SetHDRTexture(nullptr);
|
||||
Recycle(colclip_rt);
|
||||
g_gs_device->SetColorClipTexture(nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
draw_rt = hdr_rt;
|
||||
pipe.ps.hdr = 1;
|
||||
draw_rt = colclip_rt;
|
||||
pipe.ps.colclip_hw = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3900,10 +3900,10 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
}
|
||||
}
|
||||
|
||||
if (config.require_one_barrier)
|
||||
if (config.require_one_barrier || (config.tex && config.tex == config.rt)) // Used as "bind rt" flag when texture barrier is unsupported.
|
||||
{
|
||||
// requires a copy of the RT
|
||||
draw_rt_clone = static_cast<GSTexture12*>(CreateTexture(rtsize.x, rtsize.y, 1, hdr_rt ? GSTexture::Format::HDRColor : GSTexture::Format::Color, true));
|
||||
draw_rt_clone = static_cast<GSTexture12*>(CreateTexture(rtsize.x, rtsize.y, 1, colclip_rt ? GSTexture::Format::ColorClip : GSTexture::Format::Color, true));
|
||||
if (draw_rt_clone)
|
||||
{
|
||||
EndRenderPass();
|
||||
@@ -3913,23 +3913,26 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
|
||||
draw_rt_clone->SetState(GSTexture::State::Invalidated);
|
||||
CopyRect(draw_rt, draw_rt_clone, config.drawarea, config.drawarea.left, config.drawarea.top);
|
||||
PSSetShaderResource(2, draw_rt_clone, true);
|
||||
if (config.require_one_barrier)
|
||||
PSSetShaderResource(2, draw_rt_clone, true);
|
||||
if (config.tex && config.tex == config.rt)
|
||||
PSSetShaderResource(0, draw_rt_clone, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Switch to hdr target for colclip rendering
|
||||
if (pipe.ps.hdr)
|
||||
// Switch to colclip target for colclip hw rendering
|
||||
if (pipe.ps.colclip_hw)
|
||||
{
|
||||
if (!hdr_rt)
|
||||
if (!colclip_rt)
|
||||
{
|
||||
config.hdr_update_area = config.drawarea;
|
||||
config.colclip_update_area = config.drawarea;
|
||||
|
||||
EndRenderPass();
|
||||
|
||||
hdr_rt = static_cast<GSTexture12*>(CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor, false));
|
||||
if (!hdr_rt)
|
||||
colclip_rt = static_cast<GSTexture12*>(CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::ColorClip, false));
|
||||
if (!colclip_rt)
|
||||
{
|
||||
Console.WriteLn("D3D12: Failed to allocate HDR render target, aborting draw.");
|
||||
Console.WriteLn("D3D12: Failed to allocate ColorClip render target, aborting draw.");
|
||||
|
||||
if (date_image)
|
||||
Recycle(date_image);
|
||||
@@ -3937,17 +3940,17 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
return;
|
||||
}
|
||||
|
||||
g_gs_device->SetHDRTexture(static_cast<GSTexture*>(hdr_rt));
|
||||
g_gs_device->SetColorClipTexture(static_cast<GSTexture*>(colclip_rt));
|
||||
|
||||
// propagate clear value through if the hdr render is the first
|
||||
// propagate clear value through if the colclip render is the first
|
||||
if (draw_rt->GetState() == GSTexture::State::Cleared)
|
||||
{
|
||||
hdr_rt->SetState(GSTexture::State::Cleared);
|
||||
hdr_rt->SetClearColor(draw_rt->GetClearColor());
|
||||
colclip_rt->SetState(GSTexture::State::Cleared);
|
||||
colclip_rt->SetClearColor(draw_rt->GetClearColor());
|
||||
}
|
||||
else if (draw_rt->GetState() == GSTexture::State::Dirty)
|
||||
{
|
||||
GL_PUSH_("HDR Render Target Setup");
|
||||
GL_PUSH_("ColorClip Render Target Setup");
|
||||
draw_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
}
|
||||
|
||||
@@ -3956,7 +3959,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
PSSetShaderResource(2, draw_rt, true);
|
||||
}
|
||||
|
||||
draw_rt = hdr_rt;
|
||||
draw_rt = colclip_rt;
|
||||
}
|
||||
|
||||
// clear texture binding when it's bound to RT or DS
|
||||
@@ -3966,11 +3969,10 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
PSSetShaderResource(0, nullptr, false);
|
||||
}
|
||||
|
||||
// avoid restarting the render pass just to switch from rt+depth to rt and vice versa
|
||||
if (m_in_render_pass && (m_current_render_target == draw_rt || m_current_depth_target == draw_ds))
|
||||
{
|
||||
// avoid restarting the render pass just to switch from rt+depth to rt and vice versa
|
||||
// keep the depth even if doing HDR draws, because the next draw will probably re-enable depth
|
||||
// keep the depth even if doing colclip hw draws, because the next draw will probably re-enable depth
|
||||
if (!draw_rt && m_current_render_target && config.tex != m_current_render_target &&
|
||||
m_current_render_target->GetSize() == draw_ds->GetSize())
|
||||
{
|
||||
@@ -3991,9 +3993,9 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
if (!m_in_render_pass)
|
||||
{
|
||||
GSVector4 clear_color = draw_rt ? draw_rt->GetUNormClearColor() : GSVector4::zero();
|
||||
if (pipe.ps.hdr)
|
||||
if (pipe.ps.colclip_hw)
|
||||
{
|
||||
// Denormalize clear color for HDR.
|
||||
// Denormalize clear color for hw colclip.
|
||||
clear_color *= GSVector4::cxpr(255.0f / 65535.0f, 255.0f / 65535.0f, 255.0f / 65535.0f, 1.0f);
|
||||
}
|
||||
BeginRenderPass(GetLoadOpForTexture(draw_rt),
|
||||
@@ -4007,13 +4009,13 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
clear_color, draw_ds ? draw_ds->GetClearDepth() : 0.0f, 1);
|
||||
}
|
||||
|
||||
// rt -> hdr blit if enabled
|
||||
if (hdr_rt && (config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve) && config.rt->GetState() == GSTexture::State::Dirty)
|
||||
// rt -> colclip hw blit if enabled
|
||||
if (colclip_rt && (config.colclip_mode == GSHWDrawConfig::ColClipMode::ConvertOnly || config.colclip_mode == GSHWDrawConfig::ColClipMode::ConvertAndResolve) && config.rt->GetState() == GSTexture::State::Dirty)
|
||||
{
|
||||
SetUtilityTexture(static_cast<GSTexture12*>(config.rt), m_point_sampler_cpu);
|
||||
SetPipeline(m_hdr_setup_pipelines[pipe.ds].get());
|
||||
SetPipeline(m_colclip_setup_pipelines[pipe.ds].get());
|
||||
|
||||
const GSVector4 drawareaf = GSVector4((config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly) ? GSVector4i::loadh(rtsize) : config.drawarea);
|
||||
const GSVector4 drawareaf = GSVector4((config.colclip_mode == GSHWDrawConfig::ColClipMode::ConvertOnly) ? GSVector4i::loadh(rtsize) : config.drawarea);
|
||||
const GSVector4 sRect(drawareaf / GSVector4(rtsize.x, rtsize.y).xyxy());
|
||||
DrawStretchRect(sRect, GSVector4(drawareaf), rtsize);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
@@ -4021,9 +4023,9 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
GL_POP();
|
||||
}
|
||||
|
||||
// VB/IB upload, if we did DATE setup and it's not HDR this has already been done
|
||||
// VB/IB upload, if we did DATE setup and it's not colclip hw this has already been done
|
||||
SetPrimitiveTopology(s_primitive_topology_mapping[static_cast<u8>(config.topology)]);
|
||||
if (!date_image || hdr_rt)
|
||||
if (!date_image || colclip_rt)
|
||||
UploadHWDrawVerticesAndIndices(config);
|
||||
|
||||
// now we can do the actual draw
|
||||
@@ -4067,17 +4069,17 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
if (date_image)
|
||||
Recycle(date_image);
|
||||
|
||||
// now blit the hdr texture back to the original target
|
||||
if (hdr_rt)
|
||||
// now blit the colclip texture back to the original target
|
||||
if (colclip_rt)
|
||||
{
|
||||
config.hdr_update_area = config.hdr_update_area.runion(config.drawarea);
|
||||
config.colclip_update_area = config.colclip_update_area.runion(config.drawarea);
|
||||
|
||||
if ((config.hdr_mode == GSHWDrawConfig::HDRMode::ResolveOnly || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve))
|
||||
if ((config.colclip_mode == GSHWDrawConfig::ColClipMode::ResolveOnly || config.colclip_mode == GSHWDrawConfig::ColClipMode::ConvertAndResolve))
|
||||
{
|
||||
GL_PUSH("Blit HDR back to RT");
|
||||
GL_PUSH("Blit ColorClip back to RT");
|
||||
|
||||
EndRenderPass();
|
||||
hdr_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
colclip_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
|
||||
draw_rt = static_cast<GSTexture12*>(config.rt);
|
||||
OMSetRenderTargets(draw_rt, draw_ds, config.scissor);
|
||||
@@ -4089,14 +4091,14 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
draw_rt->GetUNormClearColor(), 0.0f, 0);
|
||||
|
||||
const GSVector4 sRect(GSVector4(config.hdr_update_area) / GSVector4(rtsize.x, rtsize.y).xyxy());
|
||||
SetPipeline(m_hdr_finish_pipelines[pipe.ds].get());
|
||||
SetUtilityTexture(hdr_rt, m_point_sampler_cpu);
|
||||
DrawStretchRect(sRect, GSVector4(config.hdr_update_area), rtsize);
|
||||
const GSVector4 sRect(GSVector4(config.colclip_update_area) / GSVector4(rtsize.x, rtsize.y).xyxy());
|
||||
SetPipeline(m_colclip_finish_pipelines[pipe.ds].get());
|
||||
SetUtilityTexture(colclip_rt, m_point_sampler_cpu);
|
||||
DrawStretchRect(sRect, GSVector4(config.colclip_update_area), rtsize);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
|
||||
Recycle(hdr_rt);
|
||||
g_gs_device->SetHDRTexture(nullptr);
|
||||
Recycle(colclip_rt);
|
||||
g_gs_device->SetColorClipTexture(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,8 +315,8 @@ private:
|
||||
std::array<ComPtr<ID3D12PipelineState>, 32> m_color_copy{};
|
||||
std::array<ComPtr<ID3D12PipelineState>, 2> m_merge{};
|
||||
std::array<ComPtr<ID3D12PipelineState>, NUM_INTERLACE_SHADERS> m_interlace{};
|
||||
std::array<ComPtr<ID3D12PipelineState>, 2> m_hdr_setup_pipelines{}; // [depth]
|
||||
std::array<ComPtr<ID3D12PipelineState>, 2> m_hdr_finish_pipelines{}; // [depth]
|
||||
std::array<ComPtr<ID3D12PipelineState>, 2> m_colclip_setup_pipelines{}; // [depth]
|
||||
std::array<ComPtr<ID3D12PipelineState>, 2> m_colclip_finish_pipelines{}; // [depth]
|
||||
std::array<std::array<ComPtr<ID3D12PipelineState>, 4>, 2> m_date_image_setup_pipelines{}; // [depth][datm]
|
||||
ComPtr<ID3D12PipelineState> m_fxaa_pipeline;
|
||||
ComPtr<ID3D12PipelineState> m_shadeboost_pipeline;
|
||||
|
||||
@@ -35,52 +35,6 @@ static bool s_nativeres;
|
||||
// Partial level, broken on all renderers.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool GSHwHack::GSC_DeathByDegreesTekkenNinaWilliams(GSRendererHW& r, int& skip)
|
||||
{
|
||||
// Note: Game also has issues with texture shuffle not supported on strange clamp mode.
|
||||
// See https://forums.pcsx2.net/Thread-GSDX-Texture-Cache-Bug-Report-Death-By-Degrees-SLUS-20934-NTSC
|
||||
if (skip == 0)
|
||||
{
|
||||
if (!s_nativeres && RTME && RFBP == 0 && RTBP0 == 0x34a0 && RTPSM == PSMCT32)
|
||||
{
|
||||
// Don't enable hack on native res if crc is below aggressive.
|
||||
// Upscaling issue similar to Tekken 5.
|
||||
skip = 1; // Animation pane
|
||||
}
|
||||
#if 0
|
||||
else if (RFBP == 0x3500 && RTPSM == PSMT8 && RFBMSK == 0xFFFF00FF)
|
||||
{
|
||||
// Needs to be further tested so put it on Aggressive for now, likely channel shuffle.
|
||||
skip = 4; // Underwater white fog
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!s_nativeres && RTME && (RFBP | RTBP0 | RFPSM | RTPSM) && RFBMSK == 0x00FFFFFF)
|
||||
{
|
||||
// Needs to be further tested so assume it's related with the upscaling hack.
|
||||
skip = 1; // Animation speed
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_GiTS(GSRendererHW& r, int& skip)
|
||||
{
|
||||
if (skip == 0)
|
||||
{
|
||||
if (RTME && RFBP == 0x03000 && RFPSM == PSMCT32 && RTPSM == PSMT8)
|
||||
{
|
||||
// Channel effect not properly supported yet
|
||||
skip = 9;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Channel effect not properly supported yet
|
||||
bool GSHwHack::GSC_Manhunt2(GSRendererHW& r, int& skip)
|
||||
{
|
||||
@@ -131,6 +85,22 @@ bool GSHwHack::GSC_SacredBlaze(GSRendererHW& r, int& skip)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_GuitarHero(GSRendererHW& r, int& skip)
|
||||
{
|
||||
// Crowd sprite generation is a mess, better done in software.
|
||||
if (skip == 0)
|
||||
{
|
||||
if (RTBW <= 4 && RTME && RFBW <= 4 && (r.m_context->TEX1.MMIN & 1) == 0)
|
||||
{
|
||||
r.ClearGSLocalMemory(r.m_context->offset.zb, r.m_r, 0);
|
||||
r.SwPrimRender(r, RFBP != 0x2DC0, false);
|
||||
skip = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_SFEX3(GSRendererHW& r, int& skip)
|
||||
{
|
||||
if (skip == 0)
|
||||
@@ -208,7 +178,7 @@ bool GSHwHack::GSC_DTGames(GSRendererHW& r, int& skip)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_Tekken5(GSRendererHW& r, int& skip)
|
||||
bool GSHwHack::GSC_NamcoGames(GSRendererHW& r, int& skip)
|
||||
{
|
||||
if (skip == 0)
|
||||
{
|
||||
@@ -225,7 +195,7 @@ bool GSHwHack::GSC_Tekken5(GSRendererHW& r, int& skip)
|
||||
if (!rt)
|
||||
return false;
|
||||
|
||||
GL_INS("GSC_Tekken5(): HLE channel shuffle");
|
||||
GL_INS("GSC_NamcoGames(): HLE channel shuffle");
|
||||
|
||||
// have to set up the palette ourselves too, since GSC executes before it does
|
||||
r.m_mem.m_clut.Read32(RTEX0, r.m_draw_env->TEXA);
|
||||
@@ -248,19 +218,25 @@ bool GSHwHack::GSC_Tekken5(GSRendererHW& r, int& skip)
|
||||
|
||||
if (!s_nativeres && r.PRIM->PRIM == GS_SPRITE && RTME && RTEX0.TFX == 1 && RFPSM == RTPSM && RTPSM == PSMCT32 && RFBMSK == 0xFF000000 && r.m_index.tail > 2)
|
||||
{
|
||||
GSVertex* v = &r.m_vertex.buff[0];
|
||||
// Don't enable hack on native res.
|
||||
// Fixes ghosting/blur effect and white lines appearing in stages: Moonfit Wilderness, Acid Rain - caused by upscaling.
|
||||
// Game copies the framebuffer as individual page rects with slight offsets (like 1/16 of a pixel etc) which doesn't wokr well with upscaling.
|
||||
// This should catch all the scenarios, maybe overdoes it, but it's for 1 game and it's non-detrimental, it's better than squares all over the screen.
|
||||
const GSVector4i draw_size(r.m_vt.m_min.p.x, r.m_vt.m_min.p.y, r.m_vt.m_max.p.x + 1.0f, r.m_vt.m_max.p.y + 1.0f);
|
||||
const GSVector4i read_size(r.m_vt.m_min.t.x, r.m_vt.m_min.t.y, r.m_vt.m_max.t.x + 0.5f, r.m_vt.m_max.t.y + 0.5f);
|
||||
r.ReplaceVerticesWithSprite(draw_size, read_size, GSVector2i(read_size.width(), read_size.height()), draw_size);
|
||||
}
|
||||
else if (RZTST == 1 && RTME && (RFBP == 0x02bc0 || RFBP == 0x02be0 || RFBP == 0x02d00 || RFBP == 0x03480 || RFBP == 0x034a0) && RFPSM == RTPSM && RTBP0 == 0x00000 && RTPSM == PSMCT32)
|
||||
{
|
||||
// The moving display effect(flames) is not emulated properly in the entire screen so let's remove the effect in the stage: Burning Temple. Related to half screen bottom issue.
|
||||
// Fixes black lines in the stage: Burning Temple - caused by upscaling. Note the black lines can also be fixed with Merge Sprite hack.
|
||||
skip = 2;
|
||||
if (v[0].XYZ.X & 0xF)
|
||||
{
|
||||
const GSVector4i draw_size(r.m_vt.m_min.p.x, r.m_vt.m_min.p.y, r.m_vt.m_max.p.x + 1.0f, r.m_vt.m_max.p.y + 1.0f);
|
||||
const GSVector4i read_size(r.m_vt.m_min.t.x, r.m_vt.m_min.t.y, r.m_vt.m_max.t.x + 0.5f, r.m_vt.m_max.t.y + 0.5f);
|
||||
r.ReplaceVerticesWithSprite(draw_size, read_size, GSVector2i(read_size.width(), read_size.height()), draw_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fixes the alignment of the two halves for the heat haze on the temple stage.
|
||||
for (u32 i = 0; i < r.m_index.tail; i+=2)
|
||||
{
|
||||
v[i].XYZ.Y -= 0x8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -766,7 +742,7 @@ bool GSHwHack::GSC_PolyphonyDigitalGames(GSRendererHW& r, int& skip)
|
||||
|
||||
for (u32 channel = 0; channel < 3; channel++)
|
||||
{
|
||||
const GIFRegTEX0 TEX0 = GIFRegTEX0::Create(base + channel * page_offset, RTEX0.TBW, PSMCT32);
|
||||
const GIFRegTEX0 TEX0 = GIFRegTEX0::Create(base + channel * page_offset, 10, PSMCT32);
|
||||
GSTextureCache::Target* dst = g_texture_cache->LookupTarget(TEX0, src->GetUnscaledSize(), src->GetScale(), GSTextureCache::RenderTarget, true, fbmsk);
|
||||
if (!dst)
|
||||
{
|
||||
@@ -799,6 +775,35 @@ bool GSHwHack::GSC_PolyphonyDigitalGames(GSRendererHW& r, int& skip)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool GSHwHack::GSC_Battlefield2(GSRendererHW& r, int& skip)
|
||||
{
|
||||
if (skip == 0)
|
||||
{
|
||||
if (RZBP >= RFBP && RFBP >= 0x2000 && RZBP >= 0x2700 && ((RZBP - RFBP) == 0x700))
|
||||
{
|
||||
skip = 7;
|
||||
|
||||
GIFRegTEX0 TEX0 = {};
|
||||
TEX0.TBP0 = RFBP;
|
||||
TEX0.TBW = 8;
|
||||
GSTextureCache::Target* dst = g_texture_cache->LookupTarget(TEX0, r.GetTargetSize(), r.GetTextureScaleFactor(), GSTextureCache::DepthStencil);
|
||||
|
||||
if (!dst)
|
||||
dst = g_texture_cache->CreateTarget(TEX0, r.GetTargetSize(), r.GetValidSize(nullptr), r.GetTextureScaleFactor(), GSTextureCache::DepthStencil,
|
||||
true, 0, false, false, false, GSVector4i(0,0,1,1), nullptr);
|
||||
|
||||
if (dst)
|
||||
{
|
||||
float dc = r.m_vertex.buff[1].XYZ.Z;
|
||||
g_gs_device->ClearDepth(dst->m_texture, dc * std::exp2(-32.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_BlueTongueGames(GSRendererHW& r, int& skip)
|
||||
{
|
||||
GSDrawingContext* context = r.m_context;
|
||||
@@ -915,44 +920,6 @@ bool GSHwHack::GSC_MetalGearSolid3(GSRendererHW& r, int& skip)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_BigMuthaTruckers(GSRendererHW& r, int& skip)
|
||||
{
|
||||
// Rendering pattern:
|
||||
// CRTC frontbuffer at 0x0 is interlaced (half vertical resolution),
|
||||
// game needs to do a depth effect (so green channel to alpha),
|
||||
// but there is a vram limitation so green is pushed into the alpha channel of the CRCT buffer,
|
||||
// vertical resolution is half so only half is processed at once
|
||||
// We, however, don't have this limitation so we'll replace the draw with a full-screen TS.
|
||||
|
||||
const GIFRegTEX0& Texture = RTEX0;
|
||||
|
||||
GIFRegTEX0 Frame = {};
|
||||
Frame.TBW = RFRAME.FBW;
|
||||
Frame.TBP0 = RFRAME.Block();
|
||||
const int frame_offset_pal = GSLocalMemory::GetEndBlockAddress(0xa00, 10, PSMCT32, GSVector4i(0, 0, 640, 256)) + 1;
|
||||
const int frame_offset_ntsc = GSLocalMemory::GetEndBlockAddress(0xa00, 10, PSMCT32, GSVector4i(0, 0, 640, 224)) + 1;
|
||||
const GSVector4i rect = GSVector4i(r.m_vt.m_min.p.x, r.m_vt.m_min.p.y, r.m_vt.m_max.p.x, r.m_vt.m_max.p.y);
|
||||
|
||||
if (RPRIM->TME && Frame.TBW == 10 && Texture.TBW == 10 && Texture.PSM == PSMCT16 && ((rect.w == 512 && Frame.TBP0 == frame_offset_pal) || (Frame.TBP0 == frame_offset_ntsc && rect.w == 448)))
|
||||
{
|
||||
// 224 ntsc, 256 pal.
|
||||
GL_INS("GSC_BigMuthaTruckers half bottom offset %d", r.m_context->XYOFFSET.OFX >> 4);
|
||||
|
||||
const size_t count = r.m_vertex.next;
|
||||
GSVertex* v = &r.m_vertex.buff[0];
|
||||
const u16 offset = (u16)rect.w * 16;
|
||||
|
||||
for (size_t i = 0; i < count; i++)
|
||||
v[i].XYZ.Y += offset;
|
||||
|
||||
r.m_vt.m_min.p.y += rect.w;
|
||||
r.m_vt.m_max.p.y += rect.w;
|
||||
r.m_cached_ctx.FRAME.FBP = 0x50; // 0xA00 >> 5
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_HitmanBloodMoney(GSRendererHW& r, int& skip)
|
||||
{
|
||||
// The game does a stupid thing where it backs up the last 2 pages of the framebuffer with shuffles, uploads a CT32 texture to it
|
||||
@@ -998,6 +965,10 @@ bool GSHwHack::OI_PointListPalette(GSRendererHW& r, GSTexture* rt, GSTexture* ds
|
||||
&& r.m_cached_ctx.FRAME.FBMSK == 0 // No frame buffer masking.
|
||||
)
|
||||
{
|
||||
const int mask = (r.m_vt.m_max.p.xyxy() == r.m_vt.m_min.p.xyxy()).mask();
|
||||
if (mask == 0xf)
|
||||
return true;
|
||||
|
||||
const u32 FBP = r.m_cached_ctx.FRAME.Block();
|
||||
const u32 FBW = r.m_cached_ctx.FRAME.FBW;
|
||||
GL_INS("PointListPalette - m_r = <%d, %d => %d, %d>, n_vertices = %u, FBP = 0x%x, FBW = %u", r.m_r.x, r.m_r.y, r.m_r.z, r.m_r.w, n_vertices, FBP, FBW);
|
||||
@@ -1099,7 +1070,7 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,
|
||||
// compute shadow in RG,
|
||||
// save result in alpha with a TS,
|
||||
// Restore RG channel that we previously copied to render shadows.
|
||||
|
||||
// Important note: The game downsizes the target to half height, then later expands it back up to full size, that's why PCSX2 doesn't like it, we don't support that behaviour.
|
||||
const GIFRegTEX0& Texture = RTEX0;
|
||||
|
||||
GIFRegTEX0 Frame = {};
|
||||
@@ -1110,20 +1081,48 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,
|
||||
if ((!rt) || (!RPRIM->TME) || (GSLocalMemory::m_psm[Texture.PSM].bpp != 16) || (GSLocalMemory::m_psm[Frame.PSM].bpp != 16) || (Texture.TBP0 == Frame.TBP0) || (Frame.TBW != 16 && Texture.TBW != 16))
|
||||
return true;
|
||||
|
||||
GL_INS("OI_SonicUnleashed replace draw by a copy");
|
||||
GL_INS("OI_SonicUnleashed replace draw by a copy draw %d", r.s_n);
|
||||
|
||||
GSTextureCache::Target* src = g_texture_cache->LookupTarget(Texture, GSVector2i(1, 1), r.GetTextureScaleFactor(), GSTextureCache::RenderTarget);
|
||||
GSTextureCache::Target* src = g_texture_cache->LookupTarget(Texture, GSVector2i(1, 1), r.GetTextureScaleFactor(), GSTextureCache::RenderTarget, true, 0, false, false, true, true, GSVector4i::zero(), true);
|
||||
|
||||
if (!src)
|
||||
return true;
|
||||
|
||||
const GSVector2i src_size(src->m_texture->GetSize());
|
||||
|
||||
GSTextureCache::Target* rt_again = g_texture_cache->LookupTarget(Frame, src_size, src->m_scale, GSTextureCache::RenderTarget);
|
||||
if ((rt_again->m_TEX0.PSM & 0x3) == PSMCT16)
|
||||
{
|
||||
GSVector4 dRect;
|
||||
|
||||
GSVector4 source_rect = GSVector4(static_cast<float>(rt_again->m_valid.x) / static_cast<float>(rt_again->m_unscaled_size.x), static_cast<float>(rt_again->m_valid.y) / static_cast<float>(rt_again->m_unscaled_size.y),
|
||||
static_cast<float>(rt_again->m_valid.z) / static_cast<float>(rt_again->m_unscaled_size.x), static_cast<float>(rt_again->m_valid.w) / static_cast<float>(rt_again->m_unscaled_size.y));
|
||||
|
||||
dRect = GSVector4(rt_again->m_valid) * rt_again->m_scale;
|
||||
dRect.y /= 2;
|
||||
dRect.w /= 2;
|
||||
rt_again->m_valid.y /= 2;
|
||||
rt_again->m_valid.w /= 2;
|
||||
rt_again->m_TEX0.PSM = PSMCT32;
|
||||
GSTexture* tex = g_gs_device->CreateRenderTarget(rt_again->m_unscaled_size.x * rt_again->m_scale, rt_again->m_unscaled_size.y * rt_again->m_scale, GSTexture::Format::Color, false);
|
||||
|
||||
if (!tex)
|
||||
return false;
|
||||
|
||||
|
||||
g_gs_device->StretchRect(rt_again->m_texture, source_rect, tex, dRect, ShaderConvert::COPY, false);
|
||||
|
||||
|
||||
g_gs_device->Recycle(rt_again->m_texture);
|
||||
rt_again->m_texture = tex;
|
||||
rt = tex;
|
||||
}
|
||||
|
||||
GSVector2i rt_size(rt->GetSize());
|
||||
|
||||
// This is awful, but so is the CRC hack... it's a texture shuffle split horizontally instead of vertically.
|
||||
if (rt_size.x < src_size.x || rt_size.y < src_size.y)
|
||||
{
|
||||
GSTextureCache::Target* rt_again = g_texture_cache->LookupTarget(Frame, src_size, src->m_scale, GSTextureCache::RenderTarget);
|
||||
if (rt_again->m_unscaled_size.x < src->m_unscaled_size.x || rt_again->m_unscaled_size.y < src->m_unscaled_size.y)
|
||||
{
|
||||
GSVector2i new_size = GSVector2i(std::max(rt_again->m_unscaled_size.x, src->m_unscaled_size.x),
|
||||
@@ -1134,10 +1133,12 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,
|
||||
rt_again->UpdateDrawn(GSVector4i::loadh(new_size));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const GSVector2i copy_size(std::min(rt_size.x, src_size.x), std::min(rt_size.y, src_size.y));
|
||||
|
||||
const GSVector4 sRect(0.0f, 0.0f, static_cast<float>(copy_size.x) / static_cast<float>(src_size.x), static_cast<float>(copy_size.y) / static_cast<float>(src_size.y));
|
||||
// This is kind of a bodge because the game confuses everything since the source is really 16bit and it assumes it's really drawing 16bit on the copy back, resizing the target.
|
||||
const GSVector4 dRect(0, 0, copy_size.x, copy_size.y);
|
||||
|
||||
g_gs_device->StretchRect(src->m_texture, sRect, rt, dRect, true, true, true, false);
|
||||
@@ -1199,43 +1200,6 @@ bool GSHwHack::OI_BurnoutGames(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GS
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_Battlefield2(GSRendererHW& r, int& skip)
|
||||
{
|
||||
if (skip == 0)
|
||||
{
|
||||
if (RZBP >= RFBP && RFBP >= 0x2000 && RZBP >= 0x2700 && ((RZBP - RFBP) == 0x700))
|
||||
{
|
||||
skip = 7;
|
||||
|
||||
GIFRegTEX0 TEX0 = {};
|
||||
TEX0.TBP0 = RFBP;
|
||||
TEX0.TBW = 8;
|
||||
GSTextureCache::Target* dst = g_texture_cache->LookupTarget(TEX0, r.GetTargetSize(), r.GetTextureScaleFactor(), GSTextureCache::DepthStencil);
|
||||
if (dst)
|
||||
{
|
||||
g_gs_device->ClearDepth(dst->m_texture, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::OI_Battlefield2(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t)
|
||||
{
|
||||
if (!RPRIM->TME || RFRAME.Block() > 0xD00 || RTEX0.TBP0 > 0x1D00)
|
||||
return true;
|
||||
|
||||
if (rt && t && RFRAME.Block() == 0 && RTEX0.TBP0 == 0x1000)
|
||||
{
|
||||
const GSVector4i rc(0, 0, std::min(rt->GetWidth(), t->m_texture->GetWidth()), std::min(rt->GetHeight(), t->m_texture->GetHeight()));
|
||||
g_gs_device->CopyRect(t->m_texture, rt, rc, 0, 0);
|
||||
}
|
||||
|
||||
g_texture_cache->InvalidateTemporarySource();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GSHwHack::OI_HauntingGround(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t)
|
||||
{
|
||||
// Haunting Ground clears two targets by doing a direct colour write at 0x3000, covering a target at 0x3380.
|
||||
@@ -1520,6 +1484,7 @@ const GSHwHack::Entry<GSRendererHW::GSC_Ptr> GSHwHack::s_get_skip_count_function
|
||||
CRC_F(GSC_Manhunt2),
|
||||
CRC_F(GSC_MidnightClub3),
|
||||
CRC_F(GSC_SacredBlaze),
|
||||
CRC_F(GSC_GuitarHero),
|
||||
CRC_F(GSC_SakuraWarsSoLongMyLove),
|
||||
CRC_F(GSC_Simple2000Vol114),
|
||||
CRC_F(GSC_SFEX3),
|
||||
@@ -1530,26 +1495,19 @@ const GSHwHack::Entry<GSRendererHW::GSC_Ptr> GSHwHack::s_get_skip_count_function
|
||||
CRC_F(GSC_ZettaiZetsumeiToshi2),
|
||||
CRC_F(GSC_BlackAndBurnoutSky),
|
||||
CRC_F(GSC_BlueTongueGames),
|
||||
CRC_F(GSC_Battlefield2),
|
||||
CRC_F(GSC_NFSUndercover),
|
||||
CRC_F(GSC_PolyphonyDigitalGames),
|
||||
CRC_F(GSC_MetalGearSolid3),
|
||||
CRC_F(GSC_HitmanBloodMoney),
|
||||
CRC_F(GSC_Battlefield2),
|
||||
|
||||
// Channel Effect
|
||||
CRC_F(GSC_GiTS),
|
||||
CRC_F(GSC_NamcoGames),
|
||||
CRC_F(GSC_SteambotChronicles),
|
||||
|
||||
// Depth Issue
|
||||
CRC_F(GSC_BurnoutGames),
|
||||
|
||||
// Half Screen bottom issue
|
||||
CRC_F(GSC_Tekken5),
|
||||
|
||||
// Texture shuffle
|
||||
CRC_F(GSC_DeathByDegreesTekkenNinaWilliams), // + Upscaling issues
|
||||
CRC_F(GSC_BigMuthaTruckers),
|
||||
|
||||
// Upscaling hacks
|
||||
CRC_F(GSC_UltramanFightingEvolution),
|
||||
};
|
||||
@@ -1561,7 +1519,6 @@ const GSHwHack::Entry<GSRendererHW::OI_Ptr> GSHwHack::s_before_draw_functions[]
|
||||
CRC_F(OI_SonicUnleashed),
|
||||
CRC_F(OI_ArTonelico2),
|
||||
CRC_F(OI_BurnoutGames),
|
||||
CRC_F(OI_Battlefield2),
|
||||
CRC_F(OI_HauntingGround),
|
||||
};
|
||||
|
||||
|
||||
@@ -6,13 +6,12 @@
|
||||
class GSHwHack
|
||||
{
|
||||
public:
|
||||
static bool GSC_DeathByDegreesTekkenNinaWilliams(GSRendererHW& r, int& skip);
|
||||
static bool GSC_GiTS(GSRendererHW& r, int& skip);
|
||||
static bool GSC_Manhunt2(GSRendererHW& r, int& skip);
|
||||
static bool GSC_SacredBlaze(GSRendererHW& r, int& skip);
|
||||
static bool GSC_GuitarHero(GSRendererHW& r, int& skip);
|
||||
static bool GSC_SFEX3(GSRendererHW& r, int& skip);
|
||||
static bool GSC_DTGames(GSRendererHW& r, int& skip);
|
||||
static bool GSC_Tekken5(GSRendererHW& r, int& skip);
|
||||
static bool GSC_NamcoGames(GSRendererHW& r, int& skip);
|
||||
static bool GSC_BurnoutGames(GSRendererHW& r, int& skip);
|
||||
static bool GSC_BlackAndBurnoutSky(GSRendererHW& r, int& skip);
|
||||
static bool GSC_MidnightClub3(GSRendererHW& r, int& skip);
|
||||
@@ -26,11 +25,10 @@ public:
|
||||
static bool GSC_UrbanReign(GSRendererHW& r, int& skip);
|
||||
static bool GSC_SteambotChronicles(GSRendererHW& r, int& skip);
|
||||
static bool GSC_BlueTongueGames(GSRendererHW& r, int& skip);
|
||||
static bool GSC_Battlefield2(GSRendererHW& r, int& skip);
|
||||
static bool GSC_NFSUndercover(GSRendererHW& r, int& skip);
|
||||
static bool GSC_Battlefield2(GSRendererHW& r, int& skip);
|
||||
static bool GSC_PolyphonyDigitalGames(GSRendererHW& r, int& skip);
|
||||
static bool GSC_MetalGearSolid3(GSRendererHW& r, int& skip);
|
||||
static bool GSC_BigMuthaTruckers(GSRendererHW& r, int& skip);
|
||||
static bool GSC_HitmanBloodMoney(GSRendererHW& r, int& skip);
|
||||
|
||||
static bool OI_PointListPalette(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
@@ -39,7 +37,6 @@ public:
|
||||
static bool OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
static bool OI_ArTonelico2(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
static bool OI_BurnoutGames(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
static bool OI_Battlefield2(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
static bool OI_HauntingGround(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
|
||||
static bool MV_Growlanser(GSRendererHW& r);
|
||||
|
||||
@@ -92,9 +92,9 @@ private:
|
||||
void DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Target* ds, GSTextureCache::Source* tex, const TextureMinMaxResult& tmm);
|
||||
|
||||
void ResetStates();
|
||||
void SetupIA(float target_scale, float sx, float sy);
|
||||
void SetupIA(float target_scale, float sx, float sy, bool req_vert_backup);
|
||||
void EmulateTextureShuffleAndFbmask(GSTextureCache::Target* rt, GSTextureCache::Source* tex);
|
||||
bool EmulateChannelShuffle(GSTextureCache::Target* src, bool test_only);
|
||||
bool EmulateChannelShuffle(GSTextureCache::Target* src, bool test_only, GSTextureCache::Target* rt = nullptr);
|
||||
void EmulateBlending(int rt_alpha_min, int rt_alpha_max, const bool DATE, bool& DATE_PRIMID, bool& DATE_BARRIER, GSTextureCache::Target* rt,
|
||||
bool can_scale_rt_alpha, bool& new_rt_alpha_scale);
|
||||
void CleanupDraw(bool invalidate_temp_src);
|
||||
@@ -111,14 +111,16 @@ private:
|
||||
void EmulateATST(float& AREF, GSHWDrawConfig::PSSelector& ps, bool pass_2);
|
||||
|
||||
void SetTCOffset();
|
||||
bool NextDrawHDR() const;
|
||||
bool NextDrawColClip() const;
|
||||
bool IsPossibleChannelShuffle() const;
|
||||
bool IsPageCopy() const;
|
||||
bool NextDrawMatchesShuffle() const;
|
||||
bool IsSplitTextureShuffle(GSTextureCache::Target* rt);
|
||||
bool IsSplitTextureShuffle(GIFRegTEX0& rt_TEX0, GSVector4i& valid_area);
|
||||
GSVector4i GetSplitTextureShuffleDrawRect() const;
|
||||
u32 GetEffectiveTextureShuffleFbmsk() const;
|
||||
|
||||
static GSVector4i GetDrawRectForPages(u32 bw, u32 psm, u32 num_pages);
|
||||
bool IsSinglePageDraw() const;
|
||||
bool TryToResolveSinglePageFramebuffer(GIFRegFRAME& FRAME, bool only_next_draw);
|
||||
|
||||
bool IsSplitClearActive() const;
|
||||
@@ -172,7 +174,13 @@ private:
|
||||
|
||||
u32 m_last_channel_shuffle_fbmsk = 0;
|
||||
u32 m_last_channel_shuffle_fbp = 0;
|
||||
u32 m_last_channel_shuffle_tbp = 0;
|
||||
u32 m_last_channel_shuffle_end_block = 0;
|
||||
u32 m_channel_shuffle_width = 0;
|
||||
GSVector4i m_channel_shuffle_src_valid = GSVector4i::zero();
|
||||
bool m_full_screen_shuffle = false;
|
||||
|
||||
GSTextureCache::Target* m_last_rt;
|
||||
|
||||
GIFRegFRAME m_split_clear_start = {};
|
||||
GIFRegZBUF m_split_clear_start_Z = {};
|
||||
@@ -199,6 +207,7 @@ public:
|
||||
|
||||
__fi static GSRendererHW* GetInstance() { return static_cast<GSRendererHW*>(g_gs_renderer.get()); }
|
||||
__fi HWCachedCtx* GetCachedCtx() { return &m_cached_ctx; }
|
||||
__fi u32 GetLastChannelShuffleFBP() { return m_last_channel_shuffle_fbp; }
|
||||
void Destroy() override;
|
||||
|
||||
void UpdateRenderFixes() override;
|
||||
|
||||