mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
411
.github/workflows/scripts/releases/generate-release-notes/package-lock.json
generated
vendored
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"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -181,6 +181,10 @@ private:
|
||||
extern u64 GetTickFrequency();
|
||||
extern u64 GetCPUTicks();
|
||||
extern u64 GetPhysicalMemory();
|
||||
#ifdef _WIN32
|
||||
// TODO: Someone do linux/mac.
|
||||
extern u64 GetAvailablePhysicalMemory();
|
||||
#endif
|
||||
/// 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();
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -28,7 +28,7 @@ const char* QtHost::GetDefaultThemeName()
|
||||
#ifdef __APPLE__
|
||||
return "";
|
||||
#else
|
||||
return "darkfusion";
|
||||
return "darkfusionblue";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -2392,7 +2392,12 @@ Leaderboard Position: {1} of {2}</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/CDVD/ThreadedFileReader.cpp" line="276"/>
|
||||
<location filename="../../pcsx2/CDVD/ThreadedFileReader.cpp" line="279"/>
|
||||
<source>Not enough free memory available for precaching, ({}GB) required.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/CDVD/ThreadedFileReader.cpp" line="292"/>
|
||||
<source>Required memory ({}GB) is the above the maximum allowed ({}GB).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -10789,77 +10794,77 @@ Do you want to load this save and continue?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="537"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="546"/>
|
||||
<source>Failed to change window after update. The log may contain more information.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1065"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1074"/>
|
||||
<source>Upscale multiplier set to {}x.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="441"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="432"/>
|
||||
<source>Saving screenshot to '{}'.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="453"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="444"/>
|
||||
<source>Saved screenshot to '{}'.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="460"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="451"/>
|
||||
<source>Failed to save screenshot to '{}'.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="531"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="522"/>
|
||||
<source>Host GPU device encountered an error and was recovered. This may have broken rendering.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="636"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="627"/>
|
||||
<source>CAS is not available, your graphics driver does not support the required functionality.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="691"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="682"/>
|
||||
<source>with no compression</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="698"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="689"/>
|
||||
<source>with LZMA compression</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="705"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="696"/>
|
||||
<source>with Zstandard compression</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="711"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="702"/>
|
||||
<source>Saving {0} GS dump {1} to '{2}'</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="712"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="703"/>
|
||||
<source>single frame</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="712"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="703"/>
|
||||
<source>multi-frame</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="732"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="723"/>
|
||||
<source>Failed to render/download screenshot.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="743"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="734"/>
|
||||
<source>Saved GS dump to '{}'.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -11787,7 +11792,7 @@ Scanning recursively takes more time, but will identify files in subdirectories.
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="51"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="366"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="363"/>
|
||||
<source>Restore</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -11833,237 +11838,237 @@ Scanning recursively takes more time, but will identify files in subdirectories.
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="173"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="172"/>
|
||||
<source>PS1 Disc</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="182"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="180"/>
|
||||
<source>ELF (PS2 Executable)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="194"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="191"/>
|
||||
<source>Region:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="210"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="207"/>
|
||||
<source>NTSC-B (Brazil)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="215"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="212"/>
|
||||
<source>NTSC-C (China)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="220"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="217"/>
|
||||
<source>NTSC-HK (Hong Kong)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="225"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="222"/>
|
||||
<source>NTSC-J (Japan)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="230"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="227"/>
|
||||
<source>NTSC-K (Korea)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="235"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="232"/>
|
||||
<source>NTSC-T (Taiwan)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="240"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="237"/>
|
||||
<source>NTSC-U (US)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="245"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="242"/>
|
||||
<source>Other</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="250"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="247"/>
|
||||
<source>PAL-A (Australia)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="255"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="252"/>
|
||||
<source>PAL-AF (South Africa)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="260"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="257"/>
|
||||
<source>PAL-AU (Austria)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="265"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="262"/>
|
||||
<source>PAL-BE (Belgium)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="270"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="267"/>
|
||||
<source>PAL-E (Europe/Australia)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="275"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="272"/>
|
||||
<source>PAL-F (France)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="280"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="277"/>
|
||||
<source>PAL-FI (Finland)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="285"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="282"/>
|
||||
<source>PAL-G (Germany)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="290"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="287"/>
|
||||
<source>PAL-GR (Greece)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="295"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="292"/>
|
||||
<source>PAL-I (Italy)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="300"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="297"/>
|
||||
<source>PAL-IN (India)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="305"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="302"/>
|
||||
<source>PAL-M (Europe/Australia)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="310"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="307"/>
|
||||
<source>PAL-NL (Netherlands)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="315"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="312"/>
|
||||
<source>PAL-NO (Norway)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="320"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="317"/>
|
||||
<source>PAL-P (Portugal)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="325"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="322"/>
|
||||
<source>PAL-PL (Poland)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="330"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="327"/>
|
||||
<source>PAL-R (Russia)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="335"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="332"/>
|
||||
<source>PAL-S (Spain)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="340"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="337"/>
|
||||
<source>PAL-SC (Scandinavia)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="345"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="342"/>
|
||||
<source>PAL-SW (Sweden)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="350"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="347"/>
|
||||
<source>PAL-SWI (Switzerland)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="355"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="352"/>
|
||||
<source>PAL-UK (United Kingdom)</source>
|
||||
<extracomment>Leave the code as-is, translate the country's name.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="375"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="372"/>
|
||||
<source>Compatibility:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="389"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="386"/>
|
||||
<source>Input Profile:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="403"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="400"/>
|
||||
<source>Shared</source>
|
||||
<extracomment>Refers to the shared settings profile.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="411"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="408"/>
|
||||
<source>Disc Path:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="423"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="420"/>
|
||||
<source>Browse...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="430"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="427"/>
|
||||
<source>Clear</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="482"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="479"/>
|
||||
<source>Verify</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="525"/>
|
||||
<location filename="../Settings/GameSummaryWidget.ui" line="522"/>
|
||||
<source>Search on Redump.org...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -14779,190 +14784,190 @@ Swap chain: see Microsoft's Terminology Portal.</extracomment>
|
||||
<context>
|
||||
<name>Hotkeys</name>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1086"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1094"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1114"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1121"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1095"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1103"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1123"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1130"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1136"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1142"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1148"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1153"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1166"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1179"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1207"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1219"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1233"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1139"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1145"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1151"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1157"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1162"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1175"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1188"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1216"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1228"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1242"/>
|
||||
<source>Graphics</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1087"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1096"/>
|
||||
<source>Save Screenshot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1094"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1103"/>
|
||||
<source>Toggle Video Capture</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1114"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1123"/>
|
||||
<source>Save Single Frame GS Dump</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1121"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1130"/>
|
||||
<source>Save Multi Frame GS Dump</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1131"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1140"/>
|
||||
<source>Toggle Software Rendering</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1137"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1146"/>
|
||||
<source>Increase Upscale Multiplier</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1143"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1152"/>
|
||||
<source>Decrease Upscale Multiplier</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1148"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1157"/>
|
||||
<source>Toggle On-Screen Display</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1153"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1162"/>
|
||||
<source>Cycle Aspect Ratio</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1162"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1171"/>
|
||||
<source>Aspect ratio set to '{}'.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1166"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1175"/>
|
||||
<source>Toggle Hardware Mipmapping</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1173"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1182"/>
|
||||
<source>Hardware mipmapping is now enabled.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1174"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1183"/>
|
||||
<source>Hardware mipmapping is now disabled.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1179"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1188"/>
|
||||
<source>Cycle Deinterlace Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1185"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1194"/>
|
||||
<source>Automatic</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1186"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1195"/>
|
||||
<source>Off</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1187"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1196"/>
|
||||
<source>Weave (Top Field First)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1188"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1197"/>
|
||||
<source>Weave (Bottom Field First)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1189"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1198"/>
|
||||
<source>Bob (Top Field First)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1190"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1199"/>
|
||||
<source>Bob (Bottom Field First)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1191"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1200"/>
|
||||
<source>Blend (Top Field First)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1192"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1201"/>
|
||||
<source>Blend (Bottom Field First)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1193"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1202"/>
|
||||
<source>Adaptive (Top Field First)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1194"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1203"/>
|
||||
<source>Adaptive (Bottom Field First)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1201"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1210"/>
|
||||
<source>Deinterlace mode set to '{}'.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1207"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1216"/>
|
||||
<source>Toggle Texture Dumping</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1213"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1222"/>
|
||||
<source>Texture dumping is now enabled.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1214"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1223"/>
|
||||
<source>Texture dumping is now disabled.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1220"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1229"/>
|
||||
<source>Toggle Texture Replacements</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1227"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1236"/>
|
||||
<source>Texture replacements are now enabled.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1228"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1237"/>
|
||||
<source>Texture replacements are now disabled.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1234"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1243"/>
|
||||
<source>Reload Texture Replacements</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1241"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1250"/>
|
||||
<source>Texture replacements are not enabled.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1246"/>
|
||||
<location filename="../../pcsx2/GS/GS.cpp" line="1255"/>
|
||||
<source>Reloading texture replacements...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
||||
@@ -266,10 +266,26 @@ bool ThreadedFileReader::Precache2(ProgressCallback* progress, Error* error)
|
||||
|
||||
bool ThreadedFileReader::CheckAvailableMemoryForPrecaching(u64 required_size, Error* error)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// 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(0LL, static_cast<s64>(memory_available - memory_reserve));
|
||||
|
||||
if (required_size > max_precache_size)
|
||||
{
|
||||
Error::SetStringFmt(error,
|
||||
TRANSLATE_FS("CDVD", "Not enough free memory available for precaching, ({}GB) required."),
|
||||
(required_size + memory_reserve) / _1gb);
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
// 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;
|
||||
|
||||
if (required_size > max_precache_size)
|
||||
{
|
||||
Error::SetStringFmt(error,
|
||||
@@ -277,6 +293,7 @@ bool ThreadedFileReader::CheckAvailableMemoryForPrecaching(u64 required_size, Er
|
||||
required_size / _1gb, max_precache_size / _1gb);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
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
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();
|
||||
|
||||
@@ -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;
|
||||
@@ -2853,15 +2913,44 @@ bool GSState::TrianglesAreQuads(bool shuffle_check) const
|
||||
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 +2978,7 @@ bool GSState::TrianglesAreQuads(bool shuffle_check) const
|
||||
}
|
||||
}
|
||||
|
||||
m_are_quads = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3051,6 +3141,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 +3199,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 +3224,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 +3999,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 +4011,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 +4051,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 +4574,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 +4834,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));
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
@@ -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,14 +1495,13 @@ 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_SteambotChronicles),
|
||||
|
||||
// Depth Issue
|
||||
@@ -1546,10 +1510,6 @@ const GSHwHack::Entry<GSRendererHW::GSC_Ptr> GSHwHack::s_get_skip_count_function
|
||||
// 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 +1521,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,10 +6,9 @@
|
||||
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);
|
||||
@@ -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);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
@@ -113,12 +113,14 @@ private:
|
||||
void SetTCOffset();
|
||||
bool NextDrawHDR() 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;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -206,6 +206,12 @@ public:
|
||||
bool operator()(const PaletteKey& lhs, const PaletteKey& rhs) const;
|
||||
};
|
||||
|
||||
struct TempZAddress
|
||||
{
|
||||
u32 ZBP;
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
class Target : public Surface
|
||||
{
|
||||
public:
|
||||
@@ -238,7 +244,7 @@ public:
|
||||
static Target* Create(GIFRegTEX0 TEX0, int w, int h, float scale, int type, bool clear);
|
||||
|
||||
__fi bool HasValidAlpha() const { return (m_valid_alpha_low | m_valid_alpha_high); }
|
||||
bool HasValidBitsForFormat(u32 psm, bool req_color, bool req_alpha);
|
||||
bool HasValidBitsForFormat(u32 psm, bool req_color, bool req_alpha, bool width_match);
|
||||
|
||||
void ResizeDrawn(const GSVector4i& rect);
|
||||
void UpdateDrawn(const GSVector4i& rect, bool can_resize = true);
|
||||
@@ -257,7 +263,7 @@ public:
|
||||
void UpdateValidChannels(u32 psm, u32 fbmsk);
|
||||
|
||||
/// Resizes target texture, DOES NOT RESCALE.
|
||||
bool ResizeTexture(int new_unscaled_width, int new_unscaled_height, bool recycle_old = true);
|
||||
bool ResizeTexture(int new_unscaled_width, int new_unscaled_height, bool recycle_old = true, bool require_offset = false, GSVector4i offset = GSVector4i::zero(), bool keep_old = false);
|
||||
|
||||
private:
|
||||
void UpdateTextureDebugName();
|
||||
@@ -427,6 +433,8 @@ protected:
|
||||
std::unordered_map<SurfaceOffsetKey, SurfaceOffset, SurfaceOffsetKeyHash, SurfaceOffsetKeyEqual> m_surface_offset_cache;
|
||||
|
||||
Source* m_temporary_source = nullptr; // invalidated after the draw
|
||||
GSTexture* m_temporary_z = nullptr; // invalidated after the draw
|
||||
TempZAddress m_temporary_z_info;
|
||||
|
||||
std::unique_ptr<GSDownloadTexture> m_color_download_texture;
|
||||
std::unique_ptr<GSDownloadTexture> m_uint16_download_texture;
|
||||
@@ -491,7 +499,7 @@ public:
|
||||
Target* FindTargetOverlap(Target* target, int type, int psm);
|
||||
Target* LookupTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, int type, bool used = true, u32 fbmask = 0,
|
||||
bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool preserve_rgb = true, bool preserve_alpha = true,
|
||||
const GSVector4i draw_rc = GSVector4i::zero(), bool is_shuffle = false, bool possible_clear = false, bool preserve_scale = false);
|
||||
const GSVector4i draw_rc = GSVector4i::zero(), bool is_shuffle = false, bool possible_clear = false, bool preserve_scale = false, GSTextureCache::Source* src = nullptr, GSTextureCache::Target* ds = nullptr, int offset = -1);
|
||||
Target* CreateTarget(GIFRegTEX0 TEX0, const GSVector2i& size, const GSVector2i& valid_size,float scale, int type, bool used = true, u32 fbmask = 0,
|
||||
bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool preserve_target = true,
|
||||
const GSVector4i draw_rc = GSVector4i::zero(), GSTextureCache::Source* src = nullptr);
|
||||
@@ -508,7 +516,7 @@ public:
|
||||
bool HasTargetInHeightCache(u32 bp, u32 fbw, u32 psm, u32 max_age = std::numeric_limits<u32>::max(), bool move_front = true);
|
||||
bool Has32BitTarget(u32 bp);
|
||||
|
||||
void InvalidateContainedTargets(u32 start_bp, u32 end_bp, u32 write_psm = PSMCT32);
|
||||
void InvalidateContainedTargets(u32 start_bp, u32 end_bp, u32 write_psm = PSMCT32, u32 write_bw = 1);
|
||||
void InvalidateVideoMemType(int type, u32 bp, u32 write_psm = PSMCT32, u32 write_fbmsk = 0, bool dirty_only = false);
|
||||
void InvalidateVideoMemSubTarget(GSTextureCache::Target* rt);
|
||||
void InvalidateVideoMem(const GSOffset& off, const GSVector4i& r, bool target = true);
|
||||
@@ -517,7 +525,7 @@ public:
|
||||
/// Removes any sources which point to the specified target.
|
||||
void InvalidateSourcesFromTarget(const Target* t);
|
||||
|
||||
/// Replaces a source's texture externally. Required for some CRC hacks.
|
||||
/// Removes any sources which point to the same address as a new target.
|
||||
void ReplaceSourceTexture(Source* s, GSTexture* new_texture, float new_scale, const GSVector2i& new_unscaled_size,
|
||||
HashCacheEntry* hc_entry, bool new_texture_is_shared);
|
||||
|
||||
@@ -551,6 +559,12 @@ public:
|
||||
|
||||
/// Invalidates a temporary source, a partial copy only created from the current RT/DS for the current draw.
|
||||
void InvalidateTemporarySource();
|
||||
void SetTemporaryZ(GSTexture* temp_z);
|
||||
GSTexture* GetTemporaryZ();
|
||||
TempZAddress GetTemporaryZInfo();
|
||||
void SetTemporaryZInfo(u32 address, u32 offset);
|
||||
/// Invalidates a temporary Z, a partial copy only created from the current DS for the current draw when Z is not offset but RT is.
|
||||
void InvalidateTemporaryZ();
|
||||
|
||||
/// Injects a texture into the hash cache, by using GSTexture::Swap(), transitively applying to all sources. Ownership of tex is transferred.
|
||||
void InjectHashCacheTexture(const HashCacheKey& key, GSTexture* tex, const std::pair<u8, u8>& alpha_minmax);
|
||||
|
||||
@@ -2114,7 +2114,7 @@ void GSDeviceMTL::MREInitHWDraw(GSHWDrawConfig& config, const Map& verts)
|
||||
|
||||
void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
|
||||
{ @autoreleasepool {
|
||||
if (config.tex && config.ds == config.tex)
|
||||
if (config.tex && (config.ds == config.tex || config.rt == config.tex))
|
||||
EndRenderPass(); // Barrier
|
||||
|
||||
size_t vertsize = config.nverts * sizeof(*config.verts);
|
||||
|
||||
@@ -826,7 +826,7 @@ struct PSMain
|
||||
else
|
||||
T = sample_color(st);
|
||||
|
||||
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)
|
||||
@@ -1134,7 +1134,7 @@ struct PSMain
|
||||
|
||||
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)
|
||||
@@ -1175,11 +1175,8 @@ struct PSMain
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -1193,7 +1190,7 @@ struct PSMain
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ps_dither(C, alpha_blend.a);
|
||||
|
||||
// Color clamp/wrap needs to be done after sw blending and dithering
|
||||
|
||||
@@ -2496,12 +2496,6 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
config.drawarea.width(), config.drawarea.height());
|
||||
CopyRect(hdr_rt ? hdr_rt : config.rt, draw_rt_clone, config.drawarea, config.drawarea.left, config.drawarea.top);
|
||||
}
|
||||
else if (config.tex && config.tex == config.ds)
|
||||
{
|
||||
// Ensure all depth writes are finished before sampling
|
||||
GL_INS("Texture barrier to flush depth before reading");
|
||||
glTextureBarrier();
|
||||
}
|
||||
|
||||
IASetVertexBuffer(config.verts, config.nverts);
|
||||
if (config.vs.expand != GSHWDrawConfig::VSExpand::None && !GLAD_GL_ARB_shader_draw_parameters)
|
||||
@@ -2563,6 +2557,15 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
|
||||
SetupPipeline(psel);
|
||||
|
||||
const bool check_barrier = !(config.require_one_barrier && !m_features.texture_barrier);
|
||||
|
||||
// Be careful of the rt already being bound and the blend using the RT without a barrier.
|
||||
if (check_barrier && ((config.tex && (config.tex == config.ds || config.tex == config.rt)) || ((psel.ps.IsFeedbackLoop() || psel.ps.blend_c == 1) && GLState::rt == config.rt)))
|
||||
{
|
||||
// Ensure all depth writes are finished before sampling
|
||||
GL_INS("Texture barrier to flush depth or rt before reading");
|
||||
glTextureBarrier();
|
||||
}
|
||||
// additional non-pipeline config stuff
|
||||
const bool point_size_enabled = config.vs.point_size;
|
||||
if (GLState::point_size != point_size_enabled)
|
||||
|
||||
@@ -5641,6 +5641,10 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
||||
PipelineSelector& pipe = m_pipeline_selector;
|
||||
UpdateHWPipelineSelector(config, pipe);
|
||||
|
||||
// If we don't have a barrier but the texture was drawn to last draw, end the pass to insert a barrier.
|
||||
if (InRenderPass() && !pipe.IsRTFeedbackLoop() && (config.tex == m_current_render_target || config.tex == m_current_depth_target))
|
||||
EndRenderPass();
|
||||
|
||||
// now blit the hdr texture back to the original target
|
||||
if (hdr_rt)
|
||||
{
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
|
||||
/// Version number for GS and other shaders. Increment whenever any of the contents of the
|
||||
/// shaders change, to invalidate the cache.
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 61;
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 62;
|
||||
|
||||
@@ -195,6 +195,7 @@
|
||||
<ClCompile Include="DEV9\Sessions\TCP_Session\TCP_Session_Out.cpp" />
|
||||
<ClCompile Include="DEV9\Win32\pcap_io_win32.cpp" />
|
||||
<ClCompile Include="DEV9\Sessions\BaseSession.cpp" />
|
||||
<ClCompile Include="DEV9\Sessions\UDP_Session\UDP_Common.cpp" />
|
||||
<ClCompile Include="DEV9\Sessions\UDP_Session\UDP_FixedPort.cpp" />
|
||||
<ClCompile Include="DEV9\Sessions\UDP_Session\UDP_Session.cpp" />
|
||||
<ClCompile Include="DEV9\smap.cpp" />
|
||||
@@ -636,6 +637,7 @@
|
||||
<ClInclude Include="DEV9\Sessions\BaseSession.h" />
|
||||
<ClInclude Include="DEV9\Sessions\ICMP_Session\ICMP_Session.h" />
|
||||
<ClInclude Include="DEV9\Sessions\TCP_Session\TCP_Session.h" />
|
||||
<ClInclude Include="DEV9\Sessions\UDP_Session\UDP_Common.h" />
|
||||
<ClInclude Include="DEV9\Sessions\UDP_Session\UDP_FixedPort.h" />
|
||||
<ClInclude Include="DEV9\Sessions\UDP_Session\UDP_BaseSession.h" />
|
||||
<ClInclude Include="DEV9\Sessions\UDP_Session\UDP_Session.h" />
|
||||
|
||||
@@ -944,6 +944,9 @@
|
||||
<ClCompile Include="DEV9\Sessions\TCP_Session\TCP_Session_Out.cpp">
|
||||
<Filter>System\Ps2\DEV9\Sessions\TCP_Session</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DEV9\Sessions\UDP_Session\UDP_Common.cpp">
|
||||
<Filter>System\Ps2\DEV9\Sessions\UDP_Session</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DEV9\Sessions\UDP_Session\UDP_FixedPort.cpp">
|
||||
<Filter>System\Ps2\DEV9\Sessions\UDP_Session</Filter>
|
||||
</ClCompile>
|
||||
@@ -1844,6 +1847,9 @@
|
||||
<ClInclude Include="DEV9\Sessions\TCP_Session\TCP_Session.h">
|
||||
<Filter>System\Ps2\DEV9\Sessions\TCP_Session</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DEV9\Sessions\UDP_Session\UDP_Common.h">
|
||||
<Filter>System\Ps2\DEV9\Sessions\UDP_Session</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DEV9\Sessions\UDP_Session\UDP_FixedPort.h">
|
||||
<Filter>System\Ps2\DEV9\Sessions\UDP_Session</Filter>
|
||||
</ClInclude>
|
||||
|
||||
Reference in New Issue
Block a user