mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-07-13 18:54:27 +02:00
Compare commits
81 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8fe4183856 | |||
| 0d52608f1d | |||
| 5df3c54b84 | |||
| b2db2e71b6 | |||
| 7978370b39 | |||
| d187c61599 | |||
| fa745a58b2 | |||
| 16592f3a6e | |||
| 2b5d3510c3 | |||
| 76f690d96e | |||
| d5f75c9e42 | |||
| 13d3491571 | |||
| 8a6d6818fb | |||
| d7c1cbbc4e | |||
| 5644ca09c4 | |||
| 863307d871 | |||
| 904a0942f0 | |||
| 7f20ff60ea | |||
| 1ce246e05d | |||
| f79461b407 | |||
| bbfe32e963 | |||
| 06c67b0319 | |||
| c68753d776 | |||
| 15172303e4 | |||
| 9017ad626d | |||
| ef18567d9f | |||
| d0c2097cd4 | |||
| b5ed65ddd6 | |||
| 673917ae66 | |||
| e31f57a02f | |||
| ee57382d6e | |||
| 6683f84da0 | |||
| d2cb0aaf63 | |||
| 51a5e10b4e | |||
| c2dfc10c18 | |||
| 6628de5262 | |||
| 37f2837a55 | |||
| 4b76157b9e | |||
| 3b2962fe1c | |||
| 20721b05fb | |||
| 75187d69c6 | |||
| 3df128d9f9 | |||
| 426d77a932 | |||
| b3b1ff0f50 | |||
| 88029a1411 | |||
| 57e46f07fe | |||
| 254d955f89 | |||
| e490685b42 | |||
| 7b0c39a20d | |||
| 059d631a6d | |||
| 7c255bd58d | |||
| bbcd5ec25e | |||
| 5369d6b38e | |||
| b3834427bc | |||
| d7002433a2 | |||
| e1291d5b7c | |||
| e1fd632ba3 | |||
| fbaba52bc2 | |||
| 224e82f33e | |||
| 8df49d7676 | |||
| 88d8c561db | |||
| 78697466e0 | |||
| 5e150cd3eb | |||
| 23dd23b468 | |||
| 7d47dab728 | |||
| 74f2f73ce6 | |||
| 1e2f60a9b8 | |||
| bf892e9ece | |||
| a44fe80caa | |||
| 093287f6bf | |||
| e0365c1d10 | |||
| 6cb2086dfc | |||
| 3f4b424200 | |||
| 051fdd55b0 | |||
| 29f4318ef8 | |||
| 30d7fed0e5 | |||
| f0177a879c | |||
| 88af1e54a4 | |||
| d3ba0542f2 | |||
| 4d25bdcabb | |||
| 02c5f8f648 |
@@ -157,4 +157,21 @@ jobs:
|
||||
with:
|
||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
||||
path: ci-artifacts
|
||||
report-error:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build_linux
|
||||
if: always() && needs.build_linux.result == 'failure' && inputs.publish == true
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Push Discord Webhook
|
||||
env:
|
||||
OWNER: PCSX2
|
||||
REPO: pcsx2
|
||||
DISCORD_BUILD_WEBHOOK: ${{ secrets.DISCORD_BUILD_WEBHOOK }}
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
cd ./.github/workflows/scripts/releases/announce-release
|
||||
npm ci
|
||||
FLATHUB_FAILURE=1 node index.js
|
||||
|
||||
@@ -20,6 +20,18 @@ jobs:
|
||||
cmakeflags: ""
|
||||
buildAppImage: true
|
||||
secrets: inherit
|
||||
build_linux_debug:
|
||||
name: "Debug"
|
||||
if: github.repository != 'PCSX2/pcsx2' || github.event_name == 'pull_request'
|
||||
uses: ./.github/workflows/linux_build_qt.yml
|
||||
with:
|
||||
jobName: "Debug Build"
|
||||
artifactPrefixName: "PCSX2-linux-Qt-x64-debug"
|
||||
compiler: clang
|
||||
cmakeflags: ""
|
||||
buildAppImage: true
|
||||
cmakeBuildType: Debug
|
||||
secrets: inherit
|
||||
build_linux_flatpak:
|
||||
name: "Flatpak"
|
||||
if: github.repository != 'PCSX2/pcsx2' || github.event_name == 'pull_request'
|
||||
|
||||
@@ -39,6 +39,10 @@ on:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
cmakeBuildType:
|
||||
required: false
|
||||
type: string
|
||||
default: Release
|
||||
|
||||
jobs:
|
||||
build_linux:
|
||||
@@ -129,7 +133,7 @@ jobs:
|
||||
ADDITIONAL_CMAKE_ARGS: ${{ inputs.cmakeflags }}
|
||||
run: |
|
||||
cmake -B build -G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_BUILD_TYPE="${{ inputs.cmakeBuildType }}" \
|
||||
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
|
||||
-DCMAKE_PREFIX_PATH="$HOME/deps" \
|
||||
-DCMAKE_C_COMPILER=clang-17 \
|
||||
|
||||
@@ -209,6 +209,7 @@ jobs:
|
||||
gh release upload "${TAG_VAL}" ${{ github.WORKSPACE }}/ci-artifacts/out/* --repo PCSX2/pcsx2 --clobber
|
||||
|
||||
- name: Publish Release
|
||||
if: github.event_name != 'workflow_dispatch' || inputs.is_prerelease == 'true'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
|
||||
@@ -27,7 +27,7 @@ LIBJPEGTURBO=3.1.4.1
|
||||
LIBPNG=1.6.58
|
||||
LIBWEBP=1.6.0
|
||||
NVENC=13.0.19.0
|
||||
SDL=SDL3-3.4.8
|
||||
SDL=SDL3-3.4.10
|
||||
LZ4=1.10.0
|
||||
VULKAN=1.4.328.1
|
||||
ZSTD=1.5.7
|
||||
@@ -60,7 +60,7 @@ b072aed6871998cce9b36e7774033105ca29e33632be5b6347f3206898e0756a ffmpeg-$FFMPEG
|
||||
ecae8008e2cc9ade2f2c1bb9d5e6d4fb73e7c433866a056bd82980741571a022 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
|
||||
28eb403f51f0f7405249132cecfe82ea5c0ef97f1b32c5a65828814ae0d34775 libpng-$LIBPNG.tar.xz
|
||||
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
|
||||
e9fff7467fb60f037e6708da18b25560649e4c63edc2a69bb871b960d9cbfbba $SDL.tar.gz
|
||||
12b34280415ec8418c864408b93d008a20a6530687ee613d60bfbd20411f2785 $SDL.tar.gz
|
||||
eee7dea22ed502868017971c86c63c4ed1e6085de0baebfdcc3d3322f00f3eb0 libpng-$LIBPNG-apng.patch.gz
|
||||
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
|
||||
13da39edb3a40ed9713ae390ca89faa2f1202c9dda869ef306a8d4383e242bee nv-codec-headers-$NVENC.tar.gz
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://libsdl.org/release/SDL3-3.4.8.tar.gz",
|
||||
"sha256": "e9fff7467fb60f037e6708da18b25560649e4c63edc2a69bb871b960d9cbfbba"
|
||||
"url": "https://libsdl.org/release/SDL3-3.4.10.tar.gz",
|
||||
"sha256": "12b34280415ec8418c864408b93d008a20a6530687ee613d60bfbd20411f2785"
|
||||
}
|
||||
],
|
||||
"cleanup": [
|
||||
|
||||
@@ -47,7 +47,7 @@ QT=6.11.1
|
||||
QTAPNG=1.3.0
|
||||
|
||||
FREETYPE=2.14.3
|
||||
SDL=SDL3-3.4.8
|
||||
SDL=SDL3-3.4.10
|
||||
HARFBUZZ=14.2.0
|
||||
ZSTD=1.5.7
|
||||
LZ4=1.10.0
|
||||
@@ -93,7 +93,7 @@ b2bf6c6845ac175ed7f819145483ba4676f617aaa6a5012c8efee63c8bbac413 qtimageformats
|
||||
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
|
||||
|
||||
36bc4f1cc413335368ee656c42afca65c5a3987e8768cc28cf11ba775e785a5f freetype-$FREETYPE.tar.xz
|
||||
e9fff7467fb60f037e6708da18b25560649e4c63edc2a69bb871b960d9cbfbba $SDL.tar.gz
|
||||
12b34280415ec8418c864408b93d008a20a6530687ee613d60bfbd20411f2785 $SDL.tar.gz
|
||||
c652d5d94971031654ab3989891a490a895d3e3f2b71171c62692b28e94b1b93 harfbuzz-$HARFBUZZ.tar.gz
|
||||
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
|
||||
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
|
||||
|
||||
@@ -24,7 +24,7 @@ QT=6.11.1
|
||||
QTAPNG=1.3.0
|
||||
|
||||
FREETYPE=2.14.3
|
||||
SDL=SDL3-3.4.8
|
||||
SDL=SDL3-3.4.10
|
||||
HARFBUZZ=14.2.0
|
||||
ZSTD=1.5.7
|
||||
LZ4=1.10.0
|
||||
@@ -69,7 +69,7 @@ b2bf6c6845ac175ed7f819145483ba4676f617aaa6a5012c8efee63c8bbac413 qtimageformats
|
||||
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
|
||||
|
||||
36bc4f1cc413335368ee656c42afca65c5a3987e8768cc28cf11ba775e785a5f freetype-$FREETYPE.tar.xz
|
||||
e9fff7467fb60f037e6708da18b25560649e4c63edc2a69bb871b960d9cbfbba $SDL.tar.gz
|
||||
12b34280415ec8418c864408b93d008a20a6530687ee613d60bfbd20411f2785 $SDL.tar.gz
|
||||
c652d5d94971031654ab3989891a490a895d3e3f2b71171c62692b28e94b1b93 harfbuzz-$HARFBUZZ.tar.gz
|
||||
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
|
||||
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
|
||||
|
||||
@@ -38,39 +38,54 @@ const octokit = new Octokit({
|
||||
}
|
||||
});
|
||||
|
||||
if (process.env.TAG_VAL === undefined || process.env.TAG_VAL === "") {
|
||||
console.log(`Not announcing - TAG_VAL not defined`);
|
||||
process.exit(1);
|
||||
let embed;
|
||||
|
||||
if (process.env.FLATHUB_FAILURE === undefined)
|
||||
{
|
||||
if (process.env.TAG_VAL === undefined || process.env.TAG_VAL === "") {
|
||||
console.log(`Not announcing - TAG_VAL not defined`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const { data: releaseInfo } = await octokit.rest.repos.getReleaseByTag({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
tag: process.env.TAG_VAL,
|
||||
});
|
||||
|
||||
if (releaseInfo === undefined) {
|
||||
console.log(`Not announcing - could not locate release with tag ${process.env.TAG_VAL}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!releaseInfo.prerelease) {
|
||||
console.log("Not announcing - release was not a pre-release (aka a Nightly)");
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Publish Webhook
|
||||
embed = new MessageEmbed()
|
||||
.setColor('#FF8000')
|
||||
.setTitle('New PCSX2 Nightly Build Available!')
|
||||
.setDescription("To download the latest or previous builds, [visit the official downloads page](https://pcsx2.net/downloads/).")
|
||||
.addFields(
|
||||
{ name: 'Version', value: releaseInfo.tag_name, inline: true },
|
||||
{ name: 'Installation Steps', value: '[See Here](https://pcsx2.net/docs/category/setup)', inline: true },
|
||||
{ name: 'Included Changes', value: releaseInfo.body, inline: false }
|
||||
);
|
||||
console.log(embed);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flathub upload failure
|
||||
|
||||
const { data: releaseInfo } = await octokit.rest.repos.getReleaseByTag({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
tag: process.env.TAG_VAL,
|
||||
});
|
||||
|
||||
if (releaseInfo === undefined) {
|
||||
console.log(`Not announcing - could not locate release with tag ${process.env.TAG_VAL}`);
|
||||
process.exit(1);
|
||||
embed = new MessageEmbed()
|
||||
.setColor('#FF0000')
|
||||
.setTitle('PCSX2 Failed to Build/Upload to FlatHub')
|
||||
.setDescription("Please check the latest Flathub build job to determine the root cause.")
|
||||
console.log(embed);
|
||||
}
|
||||
|
||||
if (!releaseInfo.prerelease) {
|
||||
console.log("Not announcing - release was not a pre-release (aka a Nightly)");
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Publish Webhook
|
||||
const embed = new MessageEmbed()
|
||||
.setColor('#FF8000')
|
||||
.setTitle('New PCSX2 Nightly Build Available!')
|
||||
.setDescription("To download the latest or previous builds, [visit the official downloads page](https://pcsx2.net/downloads/).")
|
||||
.addFields(
|
||||
{ name: 'Version', value: releaseInfo.tag_name, inline: true },
|
||||
{ name: 'Installation Steps', value: '[See Here](https://pcsx2.net/docs/category/setup)', inline: true },
|
||||
{ name: 'Included Changes', value: releaseInfo.body, inline: false }
|
||||
);
|
||||
console.log(embed);
|
||||
|
||||
// Get all webhooks, simple comma-sep string
|
||||
const webhookUrls = process.env.DISCORD_BUILD_WEBHOOK.split(",");
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ set QTAPNG=1.3.0
|
||||
|
||||
set FREETYPE=2.14.3
|
||||
set HARFBUZZ=14.2.0
|
||||
set SDL=SDL3-3.4.8
|
||||
set SDL=SDL3-3.4.10
|
||||
set LIBJPEGTURBO=3.1.4.1
|
||||
set LIBPNG=1658
|
||||
set LIBPNGLONG=1.6.58
|
||||
@@ -94,7 +94,7 @@ call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lp
|
||||
call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net/libpng-apng/libpng-%LIBPNGLONG%-apng.patch.gz eee7dea22ed502868017971c86c63c4ed1e6085de0baebfdcc3d3322f00f3eb0 || goto error
|
||||
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" ecae8008e2cc9ade2f2c1bb9d5e6d4fb73e7c433866a056bd82980741571a022 || goto error
|
||||
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 506206e02f90c1f37e048eacaf9e8a3a7dc682fd27783eb0ff15a7d2dcc9c2af || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" be8dafef3ecc956e736cfd1c242c10737f3ad589a866f25ba437b7f2f6d5ced2 || goto error
|
||||
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/refs/tags/v%LZ4%.zip" 3224b4c80f351f194984526ef396f6079bd6332dd9825c72ac0d7a37b3cdc565 || goto error
|
||||
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://github.com/madler/zlib/releases/download/v%ZLIB%/zlib%ZLIBSHORT%.zip" e8bf55f3017aa181690990cb58a994e77885da140609fc8f94abe9b65d2cae28 || goto error
|
||||
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 7897bc5d620580d9b7cd3539c44b59d78f3657d33663fe97a145e07b4ebd69a4 || goto error
|
||||
|
||||
@@ -77,7 +77,7 @@ set LIBX264=b35605ace3ddf7c1a5d67a2eb553f034aef41d55
|
||||
|
||||
set FREETYPE=2.14.3
|
||||
set HARFBUZZ=14.2.0
|
||||
set SDL=SDL3-3.4.8
|
||||
set SDL=SDL3-3.4.10
|
||||
set LIBJPEGTURBO=3.1.4.1
|
||||
set LIBPNG=1658
|
||||
set LIBPNGLONG=1.6.58
|
||||
@@ -97,6 +97,7 @@ set SHADERC_SPIRVHEADERS=58006c901d1d5c37dece6b6610e9af87fa951375
|
||||
set SHADERC_SPIRVTOOLS=6337eb62cadd7d124ac6789bf39c0f71148f0a73
|
||||
|
||||
set AGILITYSDK=1.619.2
|
||||
set DXHEADERS=1.619.1
|
||||
|
||||
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 3529cc37297a5a7aae4486843b9fd41c30df1d79a770f85e240b537dcc327ca5 || goto error
|
||||
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 37fba768f2780580dfae535ad6654cb9dc0bf2272e71b9b9781988de9ed0dac0 || goto error
|
||||
@@ -121,7 +122,7 @@ call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lp
|
||||
call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net/libpng-apng/libpng-%LIBPNGLONG%-apng.patch.gz eee7dea22ed502868017971c86c63c4ed1e6085de0baebfdcc3d3322f00f3eb0 || goto error
|
||||
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" ecae8008e2cc9ade2f2c1bb9d5e6d4fb73e7c433866a056bd82980741571a022 || goto error
|
||||
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 506206e02f90c1f37e048eacaf9e8a3a7dc682fd27783eb0ff15a7d2dcc9c2af || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" be8dafef3ecc956e736cfd1c242c10737f3ad589a866f25ba437b7f2f6d5ced2 || goto error
|
||||
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/refs/tags/v%LZ4%.zip" 3224b4c80f351f194984526ef396f6079bd6332dd9825c72ac0d7a37b3cdc565 || goto error
|
||||
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://github.com/madler/zlib/releases/download/v%ZLIB%/zlib%ZLIBSHORT%.zip" e8bf55f3017aa181690990cb58a994e77885da140609fc8f94abe9b65d2cae28 || goto error
|
||||
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 7897bc5d620580d9b7cd3539c44b59d78f3657d33663fe97a145e07b4ebd69a4 || goto error
|
||||
@@ -129,6 +130,7 @@ call :downloadfile "KDDockWidgets-%KDDOCKWIDGETS%.zip" "https://github.com/KDAB/
|
||||
call :downloadfile "plutovg-%PLUTOVG%.zip" "https://github.com/sammycage/plutovg/archive/v%PLUTOVG%.zip" 4fe4e48f28aa80171b2166d45c0976ab0f21eecedb52cd4c3ef73b5afb48fac9 || goto error
|
||||
call :downloadfile "plutosvg-%PLUTOSVG%.zip" "https://github.com/sammycage/plutosvg/archive/v%PLUTOSVG%.zip" 82dee2c57ad712bdd6d6d81d3e76249d89caa4b5a4214353660fd5adff12201a || goto error
|
||||
call :downloadfile "agility-sdk-%AGILITYSDK%.nupkg" "https://www.nuget.org/api/v2/package/Microsoft.Direct3D.D3D12/%AGILITYSDK%" eb92d90bb23b2ec23410c41d791e41dbdbec942ab946924d1fdcb31eac6f0735 || goto error
|
||||
call :downloadfile "DirectX-Headers-%DXHEADERS%.zip" "https://github.com/microsoft/DirectX-Headers/archive/v%DXHEADERS%.zip" 9eb8b102a90a42e4ea72a825f7d249d55ec90d164f030966c9b7784b93374927 || goto error
|
||||
call :downloadfile "rapidyaml-%RAPIDYAML%-src.zip" "https://github.com/biojppm/rapidyaml/releases/download/v%RAPIDYAML%/rapidyaml-%RAPIDYAML%-src.zip" 96276f55b9fa7837ac8f3f72fd52965879cbb5d5d2e6af548c69a177fb078304 || goto error
|
||||
|
||||
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" f9401cc5cb36c276cd1e072b6595dbd728148e8dba389e50f7339e2d388dbc08 || goto error
|
||||
@@ -507,6 +509,16 @@ if %DEBUG%==1 (
|
||||
)
|
||||
cd .. || goto error
|
||||
|
||||
rem DirectX Headers include a CMakeList file, which is absent in the Nuget package
|
||||
echo Unpacking DirectX Headers
|
||||
rmdir /S /Q "DirectX-Headers-%DXHEADERS%"
|
||||
%SEVENZIP% x "DirectX-Headers-%DXHEADERS%.zip" || goto error
|
||||
cd "DirectX-Headers-%DXHEADERS%" || goto error
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DDXHEADERS_BUILD_TEST=OFF -DDXHEADERS_BUILD_GOOGLE_TEST=OFF -B build -G Ninja || goto error
|
||||
cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
cd .. || goto error
|
||||
|
||||
echo Building shaderc...
|
||||
rmdir /S /Q "shaderc-%SHADERC%"
|
||||
%SEVENZIP% x "shaderc-%SHADERC%.zip" || goto error
|
||||
|
||||
+2
@@ -3,5 +3,7 @@ add_library(D3D12MemAlloc
|
||||
src/D3D12MemAlloc.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(D3D12MemAlloc PRIVATE Microsoft::DirectX-Headers)
|
||||
|
||||
target_include_directories(D3D12MemAlloc PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
disable_compiler_warnings_for_target(D3D12MemAlloc)
|
||||
|
||||
+3
-2
@@ -20,6 +20,7 @@
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="..\DefaultProjectRootDir.props" />
|
||||
<Import Project="..\3rdparty.props" />
|
||||
<Import Project="..\..\common\vsprops\DepsDir.props" />
|
||||
<Import Condition="$(Configuration.Contains(Debug))" Project="..\..\common\vsprops\CodeGen_Debug.props" />
|
||||
<Import Condition="$(Configuration.Contains(Devel))" Project="..\..\common\vsprops\CodeGen_Devel.props" />
|
||||
<Import Condition="$(Configuration.Contains(Release))" Project="..\..\common\vsprops\CodeGen_Release.props" />
|
||||
@@ -37,9 +38,9 @@
|
||||
</ItemGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>D3D12MA_USING_DIRECTX_HEADERS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)include;$(ProjectDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(DepsIncludeDir);$(ProjectDir)include;$(ProjectDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
||||
+12
-3
@@ -24,7 +24,7 @@
|
||||
|
||||
/** \mainpage D3D12 Memory Allocator
|
||||
|
||||
<b>Version 3.1.0</b> (2026-02-23)
|
||||
<b>Version 3.2.0</b> (2026-06-05)
|
||||
|
||||
Copyright (c) 2019-2026 Advanced Micro Devices, Inc. All rights reserved. \n
|
||||
License: MIT
|
||||
@@ -889,10 +889,17 @@ enum POOL_FLAGS
|
||||
*/
|
||||
POOL_FLAG_MSAA_TEXTURES_ALWAYS_COMMITTED = 0x2,
|
||||
/** Every allocation made in this pool will be created as a committed resource - will have its own memory block.
|
||||
|
||||
|
||||
There is also an equivalent flag for the entire allocator: D3D12MA::ALLOCATOR_FLAG_ALWAYS_COMMITTED.
|
||||
*/
|
||||
POOL_FLAG_ALWAYS_COMMITTED = 0x4,
|
||||
/** Disables tight resource alignment for all resources created from this pool.
|
||||
|
||||
When tight alignment is supported and enabled for the allocator, resources created from custom pools
|
||||
normally use it automatically. Specify this flag to restore pre-tight-alignment behavior for this pool:
|
||||
tight alignment won't be requested and small buffers may again be preferred as committed resources.
|
||||
*/
|
||||
POOL_FLAG_DONT_USE_TIGHT_ALIGNMENT = 0x8,
|
||||
|
||||
// Bit mask to extract only `ALGORITHM` bits from entire set of flags.
|
||||
POOL_FLAG_ALGORITHM_MASK = POOL_FLAG_ALGORITHM_LINEAR
|
||||
@@ -1114,7 +1121,8 @@ enum ALLOCATOR_FLAGS
|
||||
It can also be disabled for a single allocation by using #ALLOCATION_FLAG_STRATEGY_MIN_TIME.
|
||||
|
||||
If the tight resource alignment feature is used by the library (which happens automatically whenever supported,
|
||||
unless you use flag #ALLOCATOR_FLAG_DONT_USE_TIGHT_ALIGNMENT), then small buffers are not preferred as committed.
|
||||
unless you use flag #ALLOCATOR_FLAG_DONT_USE_TIGHT_ALIGNMENT or
|
||||
#POOL_FLAG_DONT_USE_TIGHT_ALIGNMENT on a custom pool), then small buffers are not preferred as committed.
|
||||
Long story short, you don't need to specify any of these flags.
|
||||
The library chooses the most optimal method automatically.
|
||||
*/
|
||||
@@ -2892,6 +2900,7 @@ as it is no longer needed.
|
||||
|
||||
You can check if the tight alignment it is available in the current system by calling D3D12MA::Allocator::IsTightAlignmentSupported().
|
||||
You can tell the library to not use it by specifying D3D12MA::ALLOCATOR_FLAG_DONT_USE_TIGHT_ALIGNMENT.
|
||||
Custom pools can opt out independently by specifying D3D12MA::POOL_FLAG_DONT_USE_TIGHT_ALIGNMENT.
|
||||
Typically, you don't need to do any of those.
|
||||
|
||||
The library automatically aligns all buffers to at least 256 B, even when the system supports smaller alignment.
|
||||
|
||||
+249
-57
@@ -163,6 +163,14 @@ especially to test compatibility with D3D12_RESOURCE_HEAP_TIER_1 on modern GPUs.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef D3D12MA_OPTIONS4_SUPPORTED
|
||||
#ifdef __ID3D12Device5_INTERFACE_DEFINED__
|
||||
#define D3D12MA_OPTIONS4_SUPPORTED 1
|
||||
#else
|
||||
#define D3D12MA_OPTIONS4_SUPPORTED 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef D3D12MA_DEBUG_LOG
|
||||
#define D3D12MA_DEBUG_LOG(format, ...)
|
||||
/*
|
||||
@@ -703,6 +711,13 @@ static UINT GetBitsPerPixel(DXGI_FORMAT format)
|
||||
case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
|
||||
case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
|
||||
return 32;
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
||||
case DXGI_FORMAT_B8G8R8X8_UNORM:
|
||||
case DXGI_FORMAT_B8G8R8A8_TYPELESS:
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
|
||||
case DXGI_FORMAT_B8G8R8X8_TYPELESS:
|
||||
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
|
||||
return 32;
|
||||
case DXGI_FORMAT_R8G8_TYPELESS:
|
||||
case DXGI_FORMAT_R8G8_UNORM:
|
||||
case DXGI_FORMAT_R8G8_UINT:
|
||||
@@ -717,6 +732,9 @@ static UINT GetBitsPerPixel(DXGI_FORMAT format)
|
||||
case DXGI_FORMAT_R16_SNORM:
|
||||
case DXGI_FORMAT_R16_SINT:
|
||||
return 16;
|
||||
case DXGI_FORMAT_B5G6R5_UNORM:
|
||||
case DXGI_FORMAT_B5G5R5A1_UNORM:
|
||||
return 16;
|
||||
case DXGI_FORMAT_R8_TYPELESS:
|
||||
case DXGI_FORMAT_R8_UNORM:
|
||||
case DXGI_FORMAT_R8_UINT:
|
||||
@@ -767,46 +785,175 @@ static ResourceClass ResourceDescToResourceClass(const D3D12_RESOURCE_DESC_T& re
|
||||
(resDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) != 0;
|
||||
return isRenderTargetOrDepthStencil ? ResourceClass::RT_DS_Texture : ResourceClass::Non_RT_DS_Texture;
|
||||
}
|
||||
|
||||
static bool ResourceDimensionIsTexture(D3D12_RESOURCE_DIMENSION dimension)
|
||||
{
|
||||
return dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D ||
|
||||
dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D ||
|
||||
dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D;
|
||||
}
|
||||
|
||||
static bool ResourceFlagsContainRenderTargetOrDepthStencil(D3D12_RESOURCE_FLAGS flags)
|
||||
{
|
||||
return (flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) != 0;
|
||||
}
|
||||
|
||||
// This algorithm is overly conservative.
|
||||
struct SmallAlignmentTileShape
|
||||
{
|
||||
UINT Width;
|
||||
UINT Height;
|
||||
UINT Depth;
|
||||
};
|
||||
|
||||
static bool GetSmallAlignmentTileShape(
|
||||
D3D12_RESOURCE_DIMENSION dimension,
|
||||
bool isMsaa,
|
||||
UINT bitsPerUnit,
|
||||
SmallAlignmentTileShape& outTileShape)
|
||||
{
|
||||
if (isMsaa)
|
||||
{
|
||||
if (dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D)
|
||||
return false;
|
||||
|
||||
switch (bitsPerUnit)
|
||||
{
|
||||
case 8: outTileShape = { 256, 256, 1 }; return true;
|
||||
case 16: outTileShape = { 256, 128, 1 }; return true;
|
||||
case 32: outTileShape = { 128, 128, 1 }; return true;
|
||||
case 64: outTileShape = { 128, 64, 1 }; return true;
|
||||
case 128: outTileShape = { 64, 64, 1 }; return true;
|
||||
case 256: outTileShape = { 64, 32, 1 }; return true;
|
||||
case 512: outTileShape = { 32, 32, 1 }; return true;
|
||||
case 1024: outTileShape = { 32, 16, 1 }; return true;
|
||||
case 2048: outTileShape = { 16, 16, 1 }; return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (dimension)
|
||||
{
|
||||
case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
|
||||
switch (bitsPerUnit)
|
||||
{
|
||||
case 8: outTileShape = { 4096, 1, 1 }; return true;
|
||||
case 16: outTileShape = { 2048, 1, 1 }; return true;
|
||||
case 32: outTileShape = { 1024, 1, 1 }; return true;
|
||||
case 64: outTileShape = { 512, 1, 1 }; return true;
|
||||
case 128: outTileShape = { 256, 1, 1 }; return true;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
|
||||
switch (bitsPerUnit)
|
||||
{
|
||||
case 8: outTileShape = { 64, 64, 1 }; return true;
|
||||
case 16: outTileShape = { 64, 32, 1 }; return true;
|
||||
case 32: outTileShape = { 32, 32, 1 }; return true;
|
||||
case 64: outTileShape = { 32, 16, 1 }; return true;
|
||||
case 128: outTileShape = { 16, 16, 1 }; return true;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
|
||||
// 4 KB counterparts of the documented 64 KB volume-tile shapes.
|
||||
switch (bitsPerUnit)
|
||||
{
|
||||
case 8: outTileShape = { 16, 16, 16 }; return true;
|
||||
case 16: outTileShape = { 16, 16, 8 }; return true;
|
||||
case 32: outTileShape = { 16, 8, 8 }; return true;
|
||||
case 64: outTileShape = { 8, 8, 8 }; return true;
|
||||
case 128: outTileShape = { 8, 8, 4 }; return true;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// This algorithm is overly conservative and applies only to the legacy small-alignment heuristic path.
|
||||
template<typename D3D12_RESOURCE_DESC_T>
|
||||
static bool CanUseSmallAlignment(const D3D12_RESOURCE_DESC_T& resourceDesc)
|
||||
{
|
||||
if (resourceDesc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D)
|
||||
if (resourceDesc.SampleDesc.Count == 0 ||
|
||||
resourceDesc.Layout != D3D12_TEXTURE_LAYOUT_UNKNOWN ||
|
||||
resourceDesc.Width > UINT_MAX)
|
||||
{
|
||||
return false;
|
||||
if ((resourceDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) != 0)
|
||||
}
|
||||
|
||||
const bool isMsaa = resourceDesc.SampleDesc.Count > 1;
|
||||
const bool isRtDs = ResourceFlagsContainRenderTargetOrDepthStencil(resourceDesc.Flags);
|
||||
if (isMsaa && !isRtDs)
|
||||
{
|
||||
return false;
|
||||
if (resourceDesc.SampleDesc.Count > 1)
|
||||
return false;
|
||||
if (resourceDesc.DepthOrArraySize != 1)
|
||||
}
|
||||
if (!isMsaa &&
|
||||
isRtDs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
UINT sizeX = (UINT)resourceDesc.Width;
|
||||
UINT sizeY = resourceDesc.Height;
|
||||
UINT bitsPerPixel = GetBitsPerPixel(resourceDesc.Format);
|
||||
if (bitsPerPixel == 0)
|
||||
UINT sizeY = 1;
|
||||
UINT sizeZ = 1;
|
||||
UINT bitsPerUnit = GetBitsPerPixel(resourceDesc.Format);
|
||||
if (bitsPerUnit == 0)
|
||||
return false;
|
||||
|
||||
if (IsFormatCompressed(resourceDesc.Format))
|
||||
switch (resourceDesc.Dimension)
|
||||
{
|
||||
sizeX = DivideRoundingUp(sizeX, 4u);
|
||||
sizeY = DivideRoundingUp(sizeY, 4u);
|
||||
bitsPerPixel *= 16;
|
||||
case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
|
||||
if (isMsaa)
|
||||
return false;
|
||||
// For 1D arrays, small-alignment eligibility depends on the mip0 slice size, not array size.
|
||||
if (IsFormatCompressed(resourceDesc.Format))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
|
||||
// For 2D arrays, small-alignment eligibility depends on mip0 width/height, not array size.
|
||||
sizeY = resourceDesc.Height;
|
||||
if (isMsaa && IsFormatCompressed(resourceDesc.Format))
|
||||
return false;
|
||||
if (IsFormatCompressed(resourceDesc.Format))
|
||||
{
|
||||
sizeX = DivideRoundingUp(sizeX, 4u);
|
||||
sizeY = DivideRoundingUp(sizeY, 4u);
|
||||
bitsPerUnit *= 16;
|
||||
}
|
||||
break;
|
||||
|
||||
case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
|
||||
if (isMsaa)
|
||||
return false;
|
||||
sizeY = resourceDesc.Height;
|
||||
sizeZ = resourceDesc.DepthOrArraySize;
|
||||
if (IsFormatCompressed(resourceDesc.Format))
|
||||
{
|
||||
sizeX = DivideRoundingUp(sizeX, 4u);
|
||||
sizeY = DivideRoundingUp(sizeY, 4u);
|
||||
bitsPerUnit *= 16;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
UINT tileSizeX = 0, tileSizeY = 0;
|
||||
switch (bitsPerPixel)
|
||||
{
|
||||
case 8: tileSizeX = 64; tileSizeY = 64; break;
|
||||
case 16: tileSizeX = 64; tileSizeY = 32; break;
|
||||
case 32: tileSizeX = 32; tileSizeY = 32; break;
|
||||
case 64: tileSizeX = 32; tileSizeY = 16; break;
|
||||
case 128: tileSizeX = 16; tileSizeY = 16; break;
|
||||
default: return false;
|
||||
}
|
||||
bitsPerUnit *= resourceDesc.SampleDesc.Count;
|
||||
|
||||
const UINT tileCount = DivideRoundingUp(sizeX, tileSizeX) * DivideRoundingUp(sizeY, tileSizeY);
|
||||
return tileCount <= 16;
|
||||
SmallAlignmentTileShape tileShape = {};
|
||||
if (!GetSmallAlignmentTileShape(resourceDesc.Dimension, isMsaa, bitsPerUnit, tileShape))
|
||||
return false;
|
||||
|
||||
const UINT64 tileCount =
|
||||
UINT64(DivideRoundingUp(sizeX, tileShape.Width)) *
|
||||
UINT64(DivideRoundingUp(sizeY, tileShape.Height)) *
|
||||
UINT64(DivideRoundingUp(sizeZ, tileShape.Depth));
|
||||
// Non-MSAA compares 64 KB against 4 KB tiles => 16 pages. MSAA compares 4 MB against 64 KB tiles => 64 pages.
|
||||
return tileCount <= (isMsaa ? 64 : 16);
|
||||
}
|
||||
|
||||
static bool ValidateAllocateMemoryParameters(
|
||||
@@ -5988,6 +6135,7 @@ public:
|
||||
BOOL IsCacheCoherentUMA() const { return m_D3D12Architecture.CacheCoherentUMA; }
|
||||
bool SupportsResourceHeapTier2() const { return m_D3D12Options.ResourceHeapTier >= D3D12_RESOURCE_HEAP_TIER_2; }
|
||||
bool IsGPUUploadHeapSupported() const { return m_GPUUploadHeapSupported != FALSE; }
|
||||
bool IsMsaa64KBAlignedTextureSupported() const { return m_MSAA64KBAlignedTextureSupported != FALSE; }
|
||||
bool IsTightAlignmentSupported() const { return m_TightAlignmentSupported != FALSE; }
|
||||
bool IsTightAlignmentEnabled() const { return IsTightAlignmentSupported() && m_UseTightAlignment; }
|
||||
bool UseMutex() const { return m_UseMutex; }
|
||||
@@ -6076,7 +6224,7 @@ private:
|
||||
const bool m_UseMutex;
|
||||
const bool m_AlwaysCommitted;
|
||||
const bool m_MsaaAlwaysCommitted;
|
||||
bool m_PreferSmallBuffersCommitted;
|
||||
const bool m_PreferSmallBuffersCommitted;
|
||||
const bool m_UseTightAlignment;
|
||||
bool m_DefaultPoolsNotZeroed = false;
|
||||
ID3D12Device* m_Device; // AddRef
|
||||
@@ -6105,6 +6253,7 @@ private:
|
||||
DXGI_ADAPTER_DESC m_AdapterDesc;
|
||||
D3D12_FEATURE_DATA_D3D12_OPTIONS m_D3D12Options;
|
||||
BOOL m_GPUUploadHeapSupported = FALSE;
|
||||
BOOL m_MSAA64KBAlignedTextureSupported = FALSE;
|
||||
BOOL m_TightAlignmentSupported = FALSE;
|
||||
D3D12_FEATURE_DATA_ARCHITECTURE m_D3D12Architecture;
|
||||
AllocationObjectAllocator m_AllocationObjectAllocator;
|
||||
@@ -6121,7 +6270,7 @@ private:
|
||||
*/
|
||||
template<typename D3D12_RESOURCE_DESC_T>
|
||||
bool PrefersCommittedAllocation(const D3D12_RESOURCE_DESC_T& resourceDesc,
|
||||
ALLOCATION_FLAGS strategy);
|
||||
ALLOCATION_FLAGS strategy, bool useTightAlignment) const;
|
||||
|
||||
// Allocates and registers new committed resource with implicit heap, as dedicated allocation.
|
||||
// Creates and returns Allocation object and optionally D3D12 resource.
|
||||
@@ -6141,6 +6290,7 @@ private:
|
||||
template<typename D3D12_RESOURCE_DESC_T>
|
||||
HRESULT CalcAllocationParams(const ALLOCATION_DESC& allocDesc, UINT64 allocSize,
|
||||
const D3D12_RESOURCE_DESC_T* resDesc, // Optional
|
||||
bool useTightAlignment,
|
||||
BlockVector*& outBlockVector, CommittedAllocationParameters& outCommittedAllocationParams, bool& outPreferCommitted);
|
||||
|
||||
// Returns UINT32_MAX if index cannot be calculcated.
|
||||
@@ -6174,7 +6324,10 @@ private:
|
||||
template<typename D3D12_RESOURCE_DESC_T>
|
||||
HRESULT GetResourceAllocationInfo(D3D12_RESOURCE_DESC_T& inOutResourceDesc,
|
||||
UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats,
|
||||
D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo) const;
|
||||
D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo,
|
||||
bool useTightAlignment) const;
|
||||
|
||||
bool IsTightAlignmentEnabled(const ALLOCATION_DESC& allocDesc) const;
|
||||
|
||||
bool NewAllocationWithinBudget(D3D12_HEAP_TYPE heapType, UINT64 size);
|
||||
|
||||
@@ -6277,6 +6430,17 @@ HRESULT AllocatorPimpl::Init(const ALLOCATOR_DESC& desc)
|
||||
}
|
||||
#endif // #if D3D12MA_OPTIONS16_SUPPORTED
|
||||
|
||||
#if D3D12MA_OPTIONS4_SUPPORTED
|
||||
{
|
||||
D3D12_FEATURE_DATA_D3D12_OPTIONS4 options4 = {};
|
||||
hr = m_Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS4, &options4, sizeof(options4));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
m_MSAA64KBAlignedTextureSupported = options4.MSAA64KBAlignedTextureSupported;
|
||||
}
|
||||
}
|
||||
#endif // #if D3D12MA_OPTIONS4_SUPPORTED
|
||||
|
||||
#if D3D12MA_TIGHT_ALIGNMENT_SUPPORTED
|
||||
{
|
||||
D3D12_FEATURE_DATA_TIGHT_ALIGNMENT tightAlignment = {};
|
||||
@@ -6285,13 +6449,6 @@ HRESULT AllocatorPimpl::Init(const ALLOCATOR_DESC& desc)
|
||||
{
|
||||
m_TightAlignmentSupported = tightAlignment.SupportTier >= D3D12_TIGHT_ALIGNMENT_TIER_1;
|
||||
|
||||
// If tight alignment is supported (checked by the code above) and wasn't disabled by the developer
|
||||
// (with ALLOCATOR_FLAG_DONT_USE_TIGHT_ALIGNMENT), disable the preference for creating small buffers as committed,
|
||||
// as if ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED was specified.
|
||||
if (IsTightAlignmentEnabled())
|
||||
{
|
||||
m_PreferSmallBuffersCommitted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // #if D3D12MA_TIGHT_ALIGNMENT_SUPPORTED
|
||||
@@ -6490,6 +6647,7 @@ HRESULT AllocatorPimpl::CreateResource(
|
||||
}
|
||||
|
||||
HRESULT hr = E_NOINTERFACE;
|
||||
const bool useTightAlignment = IsTightAlignmentEnabled(*pAllocDesc);
|
||||
CREATE_RESOURCE_PARAMS finalCreateParams = createParams;
|
||||
D3D12_RESOURCE_DESC finalResourceDesc;
|
||||
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||
@@ -6500,7 +6658,7 @@ HRESULT AllocatorPimpl::CreateResource(
|
||||
{
|
||||
finalResourceDesc = *createParams.GetResourceDesc();
|
||||
finalCreateParams.AccessResourceDesc() = &finalResourceDesc;
|
||||
hr = GetResourceAllocationInfo(finalResourceDesc, 0, NULL, resAllocInfo);
|
||||
hr = GetResourceAllocationInfo(finalResourceDesc, 0, NULL, resAllocInfo, useTightAlignment);
|
||||
}
|
||||
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||
else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
|
||||
@@ -6509,7 +6667,7 @@ HRESULT AllocatorPimpl::CreateResource(
|
||||
{
|
||||
finalResourceDesc1 = *createParams.GetResourceDesc1();
|
||||
finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
|
||||
hr = GetResourceAllocationInfo(finalResourceDesc1, 0, NULL, resAllocInfo);
|
||||
hr = GetResourceAllocationInfo(finalResourceDesc1, 0, NULL, resAllocInfo, useTightAlignment);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -6521,7 +6679,7 @@ HRESULT AllocatorPimpl::CreateResource(
|
||||
finalResourceDesc1 = *createParams.GetResourceDesc1();
|
||||
finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
|
||||
hr = GetResourceAllocationInfo(finalResourceDesc1,
|
||||
createParams.GetNumCastableFormats(), createParams.GetCastableFormats(), resAllocInfo);
|
||||
createParams.GetNumCastableFormats(), createParams.GetCastableFormats(), resAllocInfo, useTightAlignment);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -6547,14 +6705,14 @@ HRESULT AllocatorPimpl::CreateResource(
|
||||
if (createParams.Variant >= CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
|
||||
{
|
||||
hr = CalcAllocationParams<D3D12_RESOURCE_DESC1>(*pAllocDesc, resAllocInfo.SizeInBytes,
|
||||
createParams.GetResourceDesc1(),
|
||||
createParams.GetResourceDesc1(), useTightAlignment,
|
||||
blockVector, committedAllocationParams, preferCommitted);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
hr = CalcAllocationParams<D3D12_RESOURCE_DESC>(*pAllocDesc, resAllocInfo.SizeInBytes,
|
||||
createParams.GetResourceDesc(),
|
||||
createParams.GetResourceDesc(), useTightAlignment,
|
||||
blockVector, committedAllocationParams, preferCommitted);
|
||||
}
|
||||
if (FAILED(hr))
|
||||
@@ -6601,6 +6759,7 @@ HRESULT AllocatorPimpl::AllocateMemory(
|
||||
bool preferCommitted = false;
|
||||
HRESULT hr = CalcAllocationParams<D3D12_RESOURCE_DESC>(*pAllocDesc, pAllocInfo->SizeInBytes,
|
||||
NULL, // pResDesc
|
||||
false, // useTightAlignment - irrelevant for AllocateMemory
|
||||
blockVector, committedAllocationParams, preferCommitted);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
@@ -6649,7 +6808,7 @@ HRESULT AllocatorPimpl::CreateAliasingResource(
|
||||
{
|
||||
finalResourceDesc = *createParams.GetResourceDesc();
|
||||
finalCreateParams.AccessResourceDesc() = &finalResourceDesc;
|
||||
hr = GetResourceAllocationInfo(finalResourceDesc, 0, NULL, resAllocInfo);
|
||||
hr = GetResourceAllocationInfo(finalResourceDesc, 0, NULL, resAllocInfo, IsTightAlignmentEnabled());
|
||||
}
|
||||
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||
else if (createParams.Variant == CREATE_RESOURCE_PARAMS::VARIANT_WITH_STATE_AND_DESC1)
|
||||
@@ -6658,7 +6817,7 @@ HRESULT AllocatorPimpl::CreateAliasingResource(
|
||||
{
|
||||
finalResourceDesc1 = *createParams.GetResourceDesc1();
|
||||
finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
|
||||
hr = GetResourceAllocationInfo(finalResourceDesc1, 0, NULL, resAllocInfo);
|
||||
hr = GetResourceAllocationInfo(finalResourceDesc1, 0, NULL, resAllocInfo, IsTightAlignmentEnabled());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -6670,7 +6829,7 @@ HRESULT AllocatorPimpl::CreateAliasingResource(
|
||||
finalResourceDesc1 = *createParams.GetResourceDesc1();
|
||||
finalCreateParams.AccessResourceDesc1() = &finalResourceDesc1;
|
||||
hr = GetResourceAllocationInfo(finalResourceDesc1,
|
||||
createParams.GetNumCastableFormats(), createParams.GetCastableFormats(), resAllocInfo);
|
||||
createParams.GetNumCastableFormats(), createParams.GetCastableFormats(), resAllocInfo, IsTightAlignmentEnabled());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -7305,13 +7464,14 @@ void AllocatorPimpl::FreeStatsString(WCHAR* pStatsString)
|
||||
|
||||
template<typename D3D12_RESOURCE_DESC_T>
|
||||
bool AllocatorPimpl::PrefersCommittedAllocation(const D3D12_RESOURCE_DESC_T& resourceDesc,
|
||||
ALLOCATION_FLAGS strategy)
|
||||
ALLOCATION_FLAGS strategy, bool useTightAlignment) const
|
||||
{
|
||||
// Prefer creating small buffers <= 32 KB as committed, because drivers pack them better,
|
||||
// while placed buffers require 64 KB alignment.
|
||||
if(resourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER &&
|
||||
resourceDesc.Width <= D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT / 2 &&
|
||||
strategy != ALLOCATION_FLAG_STRATEGY_MIN_TIME && // Creating as committed would be slower.
|
||||
!useTightAlignment &&
|
||||
m_PreferSmallBuffersCommitted)
|
||||
{
|
||||
return true;
|
||||
@@ -7526,7 +7686,7 @@ HRESULT AllocatorPimpl::AllocateHeap(
|
||||
|
||||
template<typename D3D12_RESOURCE_DESC_T>
|
||||
HRESULT AllocatorPimpl::CalcAllocationParams(const ALLOCATION_DESC& allocDesc, UINT64 allocSize,
|
||||
const D3D12_RESOURCE_DESC_T* resDesc,
|
||||
const D3D12_RESOURCE_DESC_T* resDesc, bool useTightAlignment,
|
||||
BlockVector*& outBlockVector, CommittedAllocationParameters& outCommittedAllocationParams, bool& outPreferCommitted)
|
||||
{
|
||||
outBlockVector = NULL;
|
||||
@@ -7599,7 +7759,7 @@ HRESULT AllocatorPimpl::CalcAllocationParams(const ALLOCATION_DESC& allocDesc, U
|
||||
{
|
||||
if (resDesc->SampleDesc.Count > 1 && msaaAlwaysCommitted)
|
||||
outBlockVector = NULL;
|
||||
if (!outPreferCommitted && PrefersCommittedAllocation(*resDesc, allocDesc.Flags & ALLOCATION_FLAG_STRATEGY_MASK))
|
||||
if (!outPreferCommitted && PrefersCommittedAllocation(*resDesc, allocDesc.Flags & ALLOCATION_FLAG_STRATEGY_MASK, useTightAlignment))
|
||||
outPreferCommitted = true;
|
||||
}
|
||||
|
||||
@@ -7810,12 +7970,13 @@ template<typename D3D12_RESOURCE_DESC_T>
|
||||
HRESULT AllocatorPimpl::GetResourceAllocationInfo(
|
||||
D3D12_RESOURCE_DESC_T& inOutResourceDesc,
|
||||
UINT32 NumCastableFormats, const DXGI_FORMAT* pCastableFormats,
|
||||
D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo) const
|
||||
D3D12_RESOURCE_ALLOCATION_INFO& outAllocInfo,
|
||||
bool useTightAlignment) const
|
||||
{
|
||||
#ifdef __ID3D12Device1_INTERFACE_DEFINED__
|
||||
|
||||
#if D3D12MA_TIGHT_ALIGNMENT_SUPPORTED
|
||||
if (IsTightAlignmentEnabled())
|
||||
if (useTightAlignment)
|
||||
{
|
||||
// Don't allow USE_TIGHT_ALIGNMENT together with ALLOW_CROSS_ADAPTER as there is a D3D Debug Layer error:
|
||||
// D3D12 ERROR: ID3D12Device::GetResourceAllocationInfo: D3D12_RESOURCE_DESC::Flag D3D12_RESOURCE_FLAG_USE_TIGHT_ALIGNMENT will be ignored since D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER is set. [ STATE_CREATION ERROR #599: CREATERESOURCE_INVALIDMISCFLAGS]
|
||||
@@ -7839,7 +8000,7 @@ HRESULT AllocatorPimpl::GetResourceAllocationInfo(
|
||||
*/
|
||||
if (inOutResourceDesc.Alignment == 0 &&
|
||||
inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER &&
|
||||
!IsTightAlignmentEnabled())
|
||||
!useTightAlignment)
|
||||
{
|
||||
outAllocInfo = {
|
||||
AlignUp<UINT64>(inOutResourceDesc.Width, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT), // SizeInBytes
|
||||
@@ -7852,16 +8013,33 @@ HRESULT AllocatorPimpl::GetResourceAllocationInfo(
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
#if D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT
|
||||
if (inOutResourceDesc.Alignment == 0 &&
|
||||
(inOutResourceDesc.Flags & D3D12_RESOURCE_FLAG_USE_TIGHT_ALIGNMENT_COPY) == 0 &&
|
||||
(inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D ||
|
||||
inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D ||
|
||||
inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) &&
|
||||
(inOutResourceDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) == 0
|
||||
bool trySmallAlignment = false;
|
||||
|
||||
if (inOutResourceDesc.Alignment == 0
|
||||
&& (inOutResourceDesc.Flags & D3D12_RESOURCE_FLAG_USE_TIGHT_ALIGNMENT_COPY) == 0
|
||||
&& inOutResourceDesc.Layout == D3D12_TEXTURE_LAYOUT_UNKNOWN
|
||||
&& ResourceDimensionIsTexture(inOutResourceDesc.Dimension))
|
||||
{
|
||||
// MSAA texture.
|
||||
if(inOutResourceDesc.SampleDesc.Count > 1)
|
||||
{
|
||||
trySmallAlignment = IsMsaa64KBAlignedTextureSupported()
|
||||
&& ResourceFlagsContainRenderTargetOrDepthStencil(inOutResourceDesc.Flags)
|
||||
&& inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||
}
|
||||
// Non-MSAA texture.
|
||||
else
|
||||
{
|
||||
trySmallAlignment = !ResourceFlagsContainRenderTargetOrDepthStencil(inOutResourceDesc.Flags);
|
||||
}
|
||||
}
|
||||
|
||||
#if D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT == 1
|
||||
&& CanUseSmallAlignment(inOutResourceDesc)
|
||||
if(trySmallAlignment)
|
||||
trySmallAlignment = CanUseSmallAlignment(inOutResourceDesc);
|
||||
#endif
|
||||
)
|
||||
|
||||
if (trySmallAlignment)
|
||||
{
|
||||
/*
|
||||
The algorithm here is based on Microsoft sample: "Small Resources Sample"
|
||||
@@ -7886,6 +8064,20 @@ HRESULT AllocatorPimpl::GetResourceAllocationInfo(
|
||||
inOutResourceDesc, NumCastableFormats, pCastableFormats, outAllocInfo);
|
||||
}
|
||||
|
||||
bool AllocatorPimpl::IsTightAlignmentEnabled(const ALLOCATION_DESC& allocDesc) const
|
||||
{
|
||||
if (!IsTightAlignmentEnabled())
|
||||
return false;
|
||||
|
||||
if (allocDesc.CustomPool != NULL &&
|
||||
(allocDesc.CustomPool->m_Pimpl->GetDesc().Flags & POOL_FLAG_DONT_USE_TIGHT_ALIGNMENT) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AllocatorPimpl::NewAllocationWithinBudget(D3D12_HEAP_TYPE heapType, UINT64 size)
|
||||
{
|
||||
Budget budget = {};
|
||||
|
||||
@@ -1620,6 +1620,7 @@ SCAJ-20055:
|
||||
vuClampMode: 3 # Stops car from falling through track.
|
||||
gsHWFixes:
|
||||
textureInsideRT: 1 # Fixes broken splitscreen mode.
|
||||
halfPixelOffset: 4 # Fixes misaligned blur in replays.
|
||||
SCAJ-20056:
|
||||
name: "Bujingai"
|
||||
region: "NTSC-Unk"
|
||||
@@ -1971,6 +1972,8 @@ SCAJ-20110:
|
||||
halfPixelOffset: 2 # Sharpens world in far distances, aligns some bloom better.
|
||||
roundSprite: 1 # Fixes font artifacts.
|
||||
nativeScaling: 2 # Fixes background DOF blur in battles.
|
||||
cpuSpriteRenderBW: 1 # Fixes water and other sprite errors.
|
||||
cpuSpriteRenderLevel: 2 # Needed for above.
|
||||
SCAJ-20111:
|
||||
name: "Crash Bandicoot 5"
|
||||
region: "NTSC-Unk"
|
||||
@@ -4898,7 +4901,7 @@ SCES-50360:
|
||||
name: "Twisted Metal - Black"
|
||||
region: "PAL-M5"
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes menu text brightness.
|
||||
minimumBlendingLevel: 4 # Fixes menu text brightness.
|
||||
halfPixelOffset: 4 # Fixes misaligned blur during Darkside special.
|
||||
SCES-50361:
|
||||
name: "Jak and Daxter - The Precursor Legacy"
|
||||
@@ -5422,7 +5425,7 @@ SCES-51480:
|
||||
name: "Twisted Metal - Black Online"
|
||||
region: "PAL-M5"
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes menu text brightness.
|
||||
minimumBlendingLevel: 4 # Fixes menu text brightness.
|
||||
halfPixelOffset: 4 # Fixes misaligned blur during Darkside special.
|
||||
SCES-51513:
|
||||
name: "EyeToy - Play"
|
||||
@@ -11114,7 +11117,7 @@ SCUS-97101:
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes menu text brightness.
|
||||
minimumBlendingLevel: 4 # Fixes menu text brightness.
|
||||
halfPixelOffset: 4 # Fixes misaligned blur during Darkside special.
|
||||
SCUS-97102:
|
||||
name: "Gran Turismo 3 - A-Spec"
|
||||
@@ -11377,7 +11380,7 @@ SCUS-97164:
|
||||
name: "Twisted Metal - Black [Demo]"
|
||||
region: "NTSC-U"
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes menu text brightness.
|
||||
minimumBlendingLevel: 4 # Fixes menu text brightness.
|
||||
halfPixelOffset: 4 # Fixes misaligned blur during Darkside special.
|
||||
SCUS-97165:
|
||||
name: "Official U.S. PlayStation Magazine Demo Disc 051"
|
||||
@@ -11445,7 +11448,7 @@ SCUS-97179:
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes menu text brightness.
|
||||
minimumBlendingLevel: 4 # Fixes menu text brightness.
|
||||
halfPixelOffset: 4 # Fixes misaligned blur during Darkside special.
|
||||
SCUS-97181:
|
||||
name: "Official U.S. PlayStation Magazine Demo Disc 055"
|
||||
@@ -11490,14 +11493,14 @@ SCUS-97195:
|
||||
name: "Twisted Metal - Black Online"
|
||||
region: "NTSC-U"
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes menu text brightness.
|
||||
minimumBlendingLevel: 4 # Fixes menu text brightness.
|
||||
halfPixelOffset: 4 # Fixes misaligned blur during Darkside special.
|
||||
SCUS-97196:
|
||||
name: "Twisted Metal - Black Online"
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes menu text brightness.
|
||||
minimumBlendingLevel: 4 # Fixes menu text brightness.
|
||||
halfPixelOffset: 4 # Fixes misaligned blur during Darkside special.
|
||||
SCUS-97197:
|
||||
name: "War of the Monsters"
|
||||
@@ -13177,7 +13180,8 @@ SCUS-97621:
|
||||
clampModes:
|
||||
vu1ClampMode: 3 # Fixes missing textures.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes menu text brightness and smoke effects.
|
||||
minimumBlendingLevel: 4 # Fixes menu text brightness and smoke effects.
|
||||
halfPixelOffset: 4 # Fixes misaligned blur during Darkside special.
|
||||
gameFixes:
|
||||
- VUSyncHack # Fixes black doors on vehicles.
|
||||
patches:
|
||||
@@ -14432,6 +14436,8 @@ SLED-53977:
|
||||
halfPixelOffset: 2 # Sharpens world in far distances, aligns some bloom better.
|
||||
roundSprite: 1 # Fixes font artifacts.
|
||||
nativeScaling: 2 # Fixes background DOF blur in battles.
|
||||
cpuSpriteRenderBW: 1 # Fixes water and other sprite errors.
|
||||
cpuSpriteRenderLevel: 2 # Needed for above.
|
||||
SLED-53980:
|
||||
name: "Urban Chaos - Riot Response [Demo]"
|
||||
region: "PAL-E"
|
||||
@@ -14821,6 +14827,8 @@ SLES-50113:
|
||||
name: "Ring of Red"
|
||||
region: "PAL-M3"
|
||||
compat: 5
|
||||
gameFixes:
|
||||
- SoftwareRendererFMVHack # Fixes FMV lines.
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
SLES-50114:
|
||||
@@ -16220,6 +16228,7 @@ SLES-50731:
|
||||
clampModes:
|
||||
vuClampMode: 2 # White textures.
|
||||
gsHWFixes:
|
||||
drawBuffering: 1 # Reduces draws and improves performance.
|
||||
recommendedBlendingLevel: 3 # Improves road quality.
|
||||
halfPixelOffset: 2 # Fixes depth line and blur.
|
||||
SLES-50735:
|
||||
@@ -20026,6 +20035,8 @@ SLES-52275:
|
||||
name: "Way of the Samurai 2"
|
||||
region: "PAL-M3"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
roundSprite: 2 # Fixes UI lines.
|
||||
SLES-52276:
|
||||
name: "187 - Ride or Die"
|
||||
region: "PAL-M5"
|
||||
@@ -25380,6 +25391,8 @@ SLES-53974:
|
||||
halfPixelOffset: 2 # Sharpens world in far distances, aligns some bloom better.
|
||||
roundSprite: 1 # Fixes font artifacts.
|
||||
nativeScaling: 2 # Fixes background DOF blur in battles.
|
||||
cpuSpriteRenderBW: 1 # Fixes water and other sprite errors.
|
||||
cpuSpriteRenderLevel: 2 # Needed for above.
|
||||
SLES-53976:
|
||||
name: "Evolution GT"
|
||||
region: "PAL-M5"
|
||||
@@ -35535,6 +35548,8 @@ SLPM-60122:
|
||||
name-sort: "りんぐ おぶ れっど [たいけんばん]"
|
||||
name-en: "Ring of Red [Trial]"
|
||||
region: "NTSC-J"
|
||||
gameFixes:
|
||||
- SoftwareRendererFMVHack # Fixes FMV lines.
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
SLPM-60123:
|
||||
@@ -37312,6 +37327,8 @@ SLPM-62013:
|
||||
name-sort: "りんぐ おぶ れっど"
|
||||
name-en: "Ring of Red"
|
||||
region: "NTSC-J"
|
||||
gameFixes:
|
||||
- SoftwareRendererFMVHack # Fixes FMV lines.
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
SLPM-62015:
|
||||
@@ -37669,6 +37686,8 @@ SLPM-62091:
|
||||
name-sort: "りんぐ おぶ れっど [KONAMI The BEST]"
|
||||
name-en: "Ring of Red [KONAMI The BEST]"
|
||||
region: "NTSC-J"
|
||||
gameFixes:
|
||||
- SoftwareRendererFMVHack # Fixes FMV lines.
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
SLPM-62092:
|
||||
@@ -39697,6 +39716,8 @@ SLPM-62490:
|
||||
halfPixelOffset: 2 # Sharpens world in far distances, aligns some bloom better.
|
||||
roundSprite: 1 # Fixes font artifacts.
|
||||
nativeScaling: 2 # Fixes background DOF blur in battles.
|
||||
cpuSpriteRenderBW: 1 # Fixes water and other sprite errors.
|
||||
cpuSpriteRenderLevel: 2 # Needed for above.
|
||||
SLPM-62491:
|
||||
name: "ロックマン パワーバトルファイターズ"
|
||||
name-sort: "ろっくまん ぱわーばとるふぁいたーず"
|
||||
@@ -42375,7 +42396,9 @@ SLPM-65181:
|
||||
clampModes:
|
||||
vuClampMode: 2 # White textures.
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Fixes blurriness.
|
||||
drawBuffering: 1 # Reduces draws and improves performance.
|
||||
recommendedBlendingLevel: 3 # Improves road quality.
|
||||
halfPixelOffset: 2 # Fixes depth line and blur.
|
||||
SLPM-65183:
|
||||
name: "auto modellista モデムパック バージョン"
|
||||
name-sort: "おーともでりすた もでむぱっく ばーじょん"
|
||||
@@ -43566,6 +43589,8 @@ SLPM-65380:
|
||||
name-sort: "さむらいどう2 WAY OF THE SAMURAI 2"
|
||||
name-en: "Samurai Dou 2"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
roundSprite: 2 # Fixes UI lines.
|
||||
SLPM-65381:
|
||||
name: "きまぐれストロベリーカフェ"
|
||||
name-sort: "きまぐれすとろべりーかふぇ"
|
||||
@@ -43877,6 +43902,7 @@ SLPM-65434:
|
||||
vuClampMode: 3 # Stops car from falling through track.
|
||||
gsHWFixes:
|
||||
textureInsideRT: 1 # Fixes broken splitscreen mode.
|
||||
halfPixelOffset: 4 # Fixes misaligned blur in replays.
|
||||
SLPM-65435:
|
||||
name: "北へ。~Diamond Dust~"
|
||||
name-sort: "きたへ Diamond Dust"
|
||||
@@ -46487,6 +46513,8 @@ SLPM-65884:
|
||||
name-sort: "りもーとこんとろーるだんでぃSF"
|
||||
name-en: "Remote Control Dandy SF"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
minimumBlendingLevel: 4 # Fixes health bar flickering in tutorial level.
|
||||
SLPM-65885:
|
||||
name: "RUMBLE ROSES"
|
||||
name-sort: "らんぶるろーず"
|
||||
@@ -46516,6 +46544,8 @@ SLPM-65888:
|
||||
roundSprite: 1 # Fixes font artifacts.
|
||||
nativeScaling: 2 # Fixes background DOF blur in battles.
|
||||
PCRTCOverscan: 1 # Fixes offscreen image.
|
||||
cpuSpriteRenderBW: 1 # Fixes water and other sprite errors.
|
||||
cpuSpriteRenderLevel: 2 # Needed for above.
|
||||
SLPM-65889:
|
||||
name: "家族計画~心の絆~"
|
||||
name-sort: "かぞくけいかく こころのきずな"
|
||||
@@ -48885,6 +48915,8 @@ SLPM-66260:
|
||||
name-sort: "りもーとこんとろーるだんでぃSF [KONAMI The BEST]"
|
||||
name-en: "Remote Control Dandy SF [KONAMI The BEST]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
minimumBlendingLevel: 4 # Fixes health bar flickering in tutorial level.
|
||||
SLPM-66261:
|
||||
name: "OZ -オズ- [KONAMI The BEST]"
|
||||
name-sort: "おず [KONAMI The BEST]"
|
||||
@@ -50291,6 +50323,8 @@ SLPM-66481:
|
||||
halfPixelOffset: 2 # Sharpens world in far distances, aligns some bloom better.
|
||||
roundSprite: 1 # Fixes font artifacts.
|
||||
nativeScaling: 2 # Fixes background DOF blur in battles.
|
||||
cpuSpriteRenderBW: 1 # Fixes water and other sprite errors.
|
||||
cpuSpriteRenderLevel: 2 # Needed for above.
|
||||
SLPM-66482:
|
||||
name: "ときめきメモリアル Girl's Side 2nd Kiss [リピート生産版]"
|
||||
name-sort: "ときめきめもりある がーるずさいど 2nd Kiss [りぴーとせいさんばん]"
|
||||
@@ -53693,6 +53727,7 @@ SLPM-67527:
|
||||
clampModes:
|
||||
vuClampMode: 2 # White textures.
|
||||
gsHWFixes:
|
||||
drawBuffering: 1 # Reduces draws and improves performance.
|
||||
recommendedBlendingLevel: 3 # Improves road quality.
|
||||
halfPixelOffset: 2 # Fixes depth line and blur.
|
||||
SLPM-67528:
|
||||
@@ -65066,6 +65101,8 @@ SLUS-20145:
|
||||
name: "Ring of Red"
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gameFixes:
|
||||
- SoftwareRendererFMVHack # Fixes FMV lines.
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
SLUS-20146:
|
||||
@@ -66118,6 +66155,7 @@ SLUS-20362:
|
||||
clampModes:
|
||||
vuClampMode: 2 # White textures.
|
||||
gsHWFixes:
|
||||
drawBuffering: 1 # Reduces draws and improves performance.
|
||||
recommendedBlendingLevel: 3 # Improves road quality.
|
||||
halfPixelOffset: 2 # Fixes depth line and blur.
|
||||
SLUS-20363:
|
||||
@@ -69015,6 +69053,8 @@ SLUS-20893:
|
||||
name: "Way of the Samurai 2"
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
roundSprite: 2 # Fixes UI lines.
|
||||
SLUS-20894:
|
||||
name: "Worms 3D"
|
||||
region: "NTSC-U"
|
||||
@@ -70950,6 +70990,8 @@ SLUS-21207:
|
||||
halfPixelOffset: 2 # Sharpens world in far distances, aligns some bloom better.
|
||||
roundSprite: 1 # Fixes font artifacts.
|
||||
nativeScaling: 2 # Fixes background DOF blur in battles.
|
||||
cpuSpriteRenderBW: 1 # Fixes water and other sprite errors.
|
||||
cpuSpriteRenderLevel: 2 # Needed for above.
|
||||
SLUS-21208:
|
||||
name: "Tony Hawk's American Wasteland"
|
||||
region: "NTSC-U"
|
||||
@@ -71822,6 +71864,8 @@ SLUS-21327:
|
||||
name: "Atelier Iris 2 - The Azoth of Destiny"
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gameFixes:
|
||||
- SoftwareRendererFMVHack # Flickering in FMV.
|
||||
gsHWFixes:
|
||||
roundSprite: 1 # Fixes font artifacts for health and other sprites.
|
||||
texturePreloading: 0 # Improves performance and prevents it disabling itself regardless.
|
||||
@@ -76127,6 +76171,8 @@ SLUS-29157:
|
||||
halfPixelOffset: 2 # Sharpens world in far distances, aligns some bloom better.
|
||||
roundSprite: 1 # Fixes font artifacts.
|
||||
nativeScaling: 2 # Fixes background DOF blur in battles.
|
||||
cpuSpriteRenderBW: 1 # Fixes water and other sprite errors.
|
||||
cpuSpriteRenderLevel: 2 # Needed for above.
|
||||
SLUS-29159:
|
||||
name: "One Piece - Grand Battle [Demo]"
|
||||
region: "NTSC-U"
|
||||
|
||||
@@ -683,7 +683,7 @@
|
||||
03000000a306000020f6000000000000,Saitek PS2700 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000300f00001101000000000000,Saitek Rumble,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
|
||||
03000000e804000000a0000000000000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000bd12000010d1000000000000,Sanwa 4Button,a:b0,b:b1,x:b2,y:b3,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,platform:Windows,
|
||||
03000000bd12000010d1000000000000,Sanwa 4Button,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,x:b2,y:b3,platform:Windows,
|
||||
03000000c01100000252000000000000,Sanwa Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
|
||||
03000000c01100004350000000000000,Sanwa Micro Grip P3,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,x:b3,y:b2,platform:Windows,
|
||||
03000000411200004550000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a1,righty:a2,start:b9,x:b1,y:b3,platform:Windows,
|
||||
@@ -697,14 +697,14 @@
|
||||
030000004f04000028b3000000000000,Score A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000952e00002577000000000000,Scuf PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
|
||||
03000000a30c00002500000000000000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows,
|
||||
03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,leftshoulder:b6,lefttrigger:b7,back:b8,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000d804000086e6000000000000,Sega Multi Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a2,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
|
||||
0300000000050000289b000000000000,Sega Saturn Adapter,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
0300000000f000000800000000000000,Sega Saturn Controller,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,righttrigger:b3,start:b0,x:b5,y:b6,platform:Windows,
|
||||
03000000730700000601000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
|
||||
03000000b40400000a01000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
|
||||
030000003b07000004a1000000000000,SFX,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Windows,
|
||||
03000000632500002705000000000000,ShanWan Q36,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,righttrigger:b9,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000632500002705000000000000,ShanWan Gamepad,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,rightshoulder:b7,rightstick:b14,righttrigger:b9,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000f82100001900000000000000,Shogun Bros Chameleon X1,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
|
||||
03000000120c00001c1e000000000000,SnakeByte 4S PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
|
||||
03000000140300000918000000000000,SNES Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
|
||||
@@ -733,6 +733,7 @@
|
||||
03000000120c0000160e000000000000,Steel Play Metaltech PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
|
||||
03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000381000001214000000000000,SteelSeries Free,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000381000004114000000000000,SteelSeries Nimbus Cloud,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b15,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,paddle1:b5,paddle2:b2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows,
|
||||
03000000110100003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
@@ -776,6 +777,7 @@
|
||||
030000005f140000c501000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000b80500000210000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
030000005f1400002a01000000000000,Trust Predator GM1200,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,x:b3,y:b4,platform:Windows,
|
||||
03000000580400000a10000000000000,Trust Sight Fighter,a:b0,b:b1,back:b5,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b2,x:b3,y:b4,platform:Windows,
|
||||
030000004f04000087b6000000000000,TWCS Throttle,dpdown:b8,dpleft:b9,dpright:b7,dpup:b6,leftstick:b5,lefttrigger:-a5,leftx:a0,lefty:a1,righttrigger:+a5,platform:Windows,
|
||||
03000000411200000450000000000000,Twin Shock,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows,
|
||||
03000000d90400000200000000000000,TwinShock PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
|
||||
@@ -1116,6 +1118,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000381000004114000000010000,SteelSeries Nimbus Cloud,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b15,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,paddle1:b5,paddle2:b2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Mac OS X,
|
||||
05000000484944204465766963650000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
|
||||
050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
|
||||
@@ -1536,10 +1539,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000853200000706000012010000,Nacon GC100,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006b140000010c000010010000,Nacon GC400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
05000000853200000503000000010000,Nacon MGX Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
0300000085320000170d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
|
||||
0300000085320000190d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
|
||||
0300000085320000180d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
0300000085320000160d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
|
||||
0300000085320000170d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
|
||||
0300000085320000180d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
0300000085320000190d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
|
||||
030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000004f1f00000800000011010000,NeoGeo PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
0300000092120000474e000000010000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Linux,
|
||||
@@ -1751,7 +1754,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000005e0400008e02000073050000,Speedlink Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
05000000381000001214000001000000,SteelSeries Free,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a2,righttrigger:a3,platform:Linux,
|
||||
05000000381000001214000001000000,SteelSeries Free,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a3,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000381000004114000000010000,SteelSeries Nimbus Cloud,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b15,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,paddle1:b5,paddle2:b2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Linux,
|
||||
050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b10,guide:b11,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Linux,
|
||||
03000000381000003014000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000381000003114000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
@@ -1797,9 +1801,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000e00d00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
|
||||
03000000f00600000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
|
||||
030000005f140000c501000010010000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000f51000001370000000000000,Turtle Beach ReactR,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000f51000001370000000010000,Turtle Beach ReactR,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
06000000f51000000870000003010000,Turtle Beach Recon,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000f51000001370000000010000,Turtle Beach ReactR,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
|
||||
03000000f51000001370000000000000,Turtle Beach ReactR,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
|
||||
05000000f51000008f01000001000000,Turtle Beach Rematch Nintendo Switch Controller,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux,
|
||||
03000000100800000100000010010000,Twin PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000c0160000e105000010010000,Ultimate Atari Fight Stick,a:b1,b:b2,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b8,x:b0,y:b3,platform:Linux,
|
||||
03000000151900005678000010010000,Uniplay U6,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-az" viewBox="0 0 640 480">
|
||||
<path fill="#3f9c35" d="M.1 0h640v480H.1z"/>
|
||||
<path fill="#ed2939" d="M.1 0h640v320H.1z"/>
|
||||
<path fill="#00b9e4" d="M.1 0h640v160H.1z"/>
|
||||
<circle cx="304" cy="240" r="72" fill="#fff"/>
|
||||
<circle cx="320" cy="240" r="60" fill="#ed2939"/>
|
||||
<path fill="#fff" d="m384 200 7.7 21.5 20.6-9.8-9.8 20.7L424 240l-21.5 7.7 9.8 20.6-20.6-9.8L384 280l-7.7-21.5-20.6 9.8 9.8-20.6L344 240l21.5-7.7-9.8-20.6 20.6 9.8z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 501 B |
@@ -1,6 +1,8 @@
|
||||
// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#if defined(VERTEX_SHADER)
|
||||
|
||||
struct VS_INPUT
|
||||
{
|
||||
float4 p : POSITION;
|
||||
@@ -15,6 +17,21 @@ struct VS_OUTPUT
|
||||
float4 c : COLOR;
|
||||
};
|
||||
|
||||
VS_OUTPUT vs_main(VS_INPUT input)
|
||||
{
|
||||
VS_OUTPUT output;
|
||||
|
||||
output.p = input.p;
|
||||
output.t = input.t;
|
||||
output.c = input.c;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif // VERTEX_SHADER
|
||||
|
||||
#if defined(PIXEL_SHADER)
|
||||
|
||||
cbuffer cb0 : register(b0)
|
||||
{
|
||||
float4 BGColor;
|
||||
@@ -33,11 +50,22 @@ static const float3x3 rgb2yuv =
|
||||
Texture2D Texture;
|
||||
SamplerState TextureSampler;
|
||||
|
||||
#if HAS_FLOAT32_INPUT
|
||||
|
||||
float sample_c(float2 uv)
|
||||
{
|
||||
return Texture.Sample(TextureSampler, uv).r;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
float4 sample_c(float2 uv)
|
||||
{
|
||||
return Texture.Sample(TextureSampler, uv);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct PS_INPUT
|
||||
{
|
||||
float4 p : SV_Position;
|
||||
@@ -45,36 +73,117 @@ struct PS_INPUT
|
||||
float4 c : COLOR;
|
||||
};
|
||||
|
||||
#if HAS_INTEGER_OUTPUT
|
||||
#define OUTPUT_TYPE uint
|
||||
#define OUTPUT_SV SV_Target
|
||||
#elif HAS_DEPTH_OUTPUT
|
||||
#define OUTPUT_TYPE float
|
||||
#define OUTPUT_SV SV_Depth
|
||||
#elif HAS_FLOAT32_OUTPUT
|
||||
#define OUTPUT_TYPE float
|
||||
#define OUTPUT_SV SV_Target
|
||||
#else
|
||||
#define OUTPUT_TYPE float4
|
||||
#define OUTPUT_SV SV_Target
|
||||
#endif
|
||||
|
||||
struct PS_OUTPUT
|
||||
{
|
||||
float4 c : SV_Target0;
|
||||
OUTPUT_TYPE o : OUTPUT_SV;
|
||||
};
|
||||
|
||||
VS_OUTPUT vs_main(VS_INPUT input)
|
||||
uint rgba8_to_uint(float4 c)
|
||||
{
|
||||
VS_OUTPUT output;
|
||||
|
||||
output.p = input.p;
|
||||
output.t = input.t;
|
||||
output.c = input.c;
|
||||
|
||||
return output;
|
||||
uint4 i = uint4(c * 255.5f) & 0xFFu;
|
||||
return i.r | (i.g << 8) | (i.b << 16) | (i.a << 24);
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_copy(PS_INPUT input)
|
||||
uint rgb5a1_to_uint(float4 c)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
output.c = sample_c(input.t);
|
||||
|
||||
return output;
|
||||
uint4 i = uint4(c * 255.5f) & uint4(0xF8u, 0xF8u, 0xF8u, 0x80u);
|
||||
return (i.r >> 3) | (i.g << 2) | (i.b << 7) | (i.a << 8);
|
||||
}
|
||||
|
||||
float ps_depth_copy(PS_INPUT input) : SV_Depth
|
||||
uint depth_to_uint(float d)
|
||||
{
|
||||
return sample_c(input.t).r;
|
||||
return uint(d * exp2(32.0f));
|
||||
}
|
||||
|
||||
float4 uint_to_rgba8(uint i)
|
||||
{
|
||||
return float4((i & 0xFFu), ((i >> 8) & 0xFFu), ((i >> 16) & 0xFFu), ((i >> 24) & 0xFFu)) / 255.0f;
|
||||
}
|
||||
|
||||
float4 uint_to_rgb5a1(uint i)
|
||||
{
|
||||
return float4(uint4(i << 3, i >> 2, i >> 7, i >> 8) & uint4(0xF8u, 0xF8u, 0xF8u, 0x80u)) / 255.0f;
|
||||
}
|
||||
|
||||
float uint_to_depth32(uint i)
|
||||
{
|
||||
return float(i) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float uint_to_depth24(uint i)
|
||||
{
|
||||
return float(i & 0xFFFFFFu) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float uint_to_depth16(uint i)
|
||||
{
|
||||
return float(i & 0xFFFFu) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float rgba8_to_depth32(float4 val)
|
||||
{
|
||||
return uint_to_depth32(rgba8_to_uint(val));
|
||||
}
|
||||
|
||||
float rgba8_to_depth24(float4 val)
|
||||
{
|
||||
return uint_to_depth24(rgba8_to_uint(val));
|
||||
}
|
||||
|
||||
float rgba8_to_depth16(float4 val)
|
||||
{
|
||||
return uint_to_depth16(rgba8_to_uint(val));
|
||||
}
|
||||
|
||||
float rgb5a1_to_depth16(float4 val)
|
||||
{
|
||||
return uint_to_depth16(rgb5a1_to_uint(val));
|
||||
}
|
||||
|
||||
float4 depth32_to_rgba8(float d)
|
||||
{
|
||||
return uint_to_rgba8(depth_to_uint(d));
|
||||
}
|
||||
|
||||
float4 depth16_to_rgb5a1(float d)
|
||||
{
|
||||
return uint_to_rgb5a1(depth_to_uint(d));
|
||||
}
|
||||
|
||||
float depth32_to_depth24(float d)
|
||||
{
|
||||
return uint_to_depth24(depth_to_uint(d));
|
||||
}
|
||||
|
||||
#if defined(__ps_copy__)
|
||||
OUTPUT_TYPE ps_copy(PS_INPUT input) : OUTPUT_SV
|
||||
{
|
||||
return sample_c(input.t);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ps_depth_copy__)
|
||||
OUTPUT_TYPE ps_depth_copy(PS_INPUT input) : OUTPUT_SV
|
||||
{
|
||||
return sample_c(input.t);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ps_downsample_copy__)
|
||||
PS_OUTPUT ps_downsample_copy(PS_INPUT input)
|
||||
{
|
||||
int DownsampleFactor = DOFFSET;
|
||||
@@ -85,179 +194,134 @@ PS_OUTPUT ps_downsample_copy(PS_INPUT input)
|
||||
int2 coord = max(int2(input.p.xy) * DownsampleFactor, ClampMin);
|
||||
|
||||
PS_OUTPUT output;
|
||||
output.c = (float4)0;
|
||||
output.o = (float4)0;
|
||||
for (int yoff = 0; yoff < DownsampleFactor; yoff++)
|
||||
{
|
||||
for (int xoff = 0; xoff < DownsampleFactor; xoff++)
|
||||
output.c += Texture.Load(int3(coord + int2(xoff * step_multiplier, yoff * step_multiplier), 0));
|
||||
output.o += Texture.Load(int3(coord + int2(xoff * step_multiplier, yoff * step_multiplier), 0));
|
||||
}
|
||||
output.c /= Weight;
|
||||
output.o /= Weight;
|
||||
return output;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ps_filter_transparency__)
|
||||
PS_OUTPUT ps_filter_transparency(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
float4 c = sample_c(input.t);
|
||||
output.c = float4(c.rgb, 1.0);
|
||||
output.o = float4(c.rgb, 1.0);
|
||||
return output;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
|
||||
uint ps_convert_rgba8_16bits(PS_INPUT input) : SV_Target0
|
||||
#if defined(__ps_convert_rgb5a1_16bits__)
|
||||
OUTPUT_TYPE ps_convert_rgb5a1_16bits(PS_INPUT input) : OUTPUT_SV
|
||||
{
|
||||
uint4 i = sample_c(input.t) * float4(255.5f, 255.5f, 255.5f, 255.5f);
|
||||
|
||||
return ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8);
|
||||
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
|
||||
return rgb5a1_to_uint(sample_c(input.t));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ps_datm1__)
|
||||
void ps_datm1(PS_INPUT input)
|
||||
{
|
||||
clip(sample_c(input.t).a - 127.5f / 255); // >= 0x80 pass
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ps_datm0__)
|
||||
void ps_datm0(PS_INPUT input)
|
||||
{
|
||||
clip(127.5f / 255 - sample_c(input.t).a); // < 0x80 pass (== 0x80 should not pass)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ps_datm1_rta_correction__)
|
||||
void ps_datm1_rta_correction(PS_INPUT input)
|
||||
{
|
||||
clip(sample_c(input.t).a - 254.5f / 255); // >= 0x80 pass
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ps_datm0_rta_correction__)
|
||||
void ps_datm0_rta_correction(PS_INPUT input)
|
||||
{
|
||||
clip(254.5f / 255 - sample_c(input.t).a); // < 0x80 pass (== 0x80 should not pass)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ps_rta_correction__)
|
||||
PS_OUTPUT ps_rta_correction(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
float4 value = sample_c(input.t);
|
||||
output.c = float4(value.rgb, value.a / (128.25f / 255.0f));
|
||||
output.o = float4(value.rgb, value.a / (128.25f / 255.0f));
|
||||
return output;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ps_rta_decorrection__)
|
||||
PS_OUTPUT ps_rta_decorrection(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
float4 value = sample_c(input.t);
|
||||
output.c = float4(value.rgb, value.a * (128.25f / 255.0f));
|
||||
output.o = float4(value.rgb, value.a * (128.25f / 255.0f));
|
||||
return output;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ps_colclip_init__)
|
||||
PS_OUTPUT ps_colclip_init(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
float4 value = sample_c(input.t);
|
||||
output.c = float4(round(value.rgb * 255) / 65535, value.a);
|
||||
output.o = float4(round(value.rgb * 255) / 65535, value.a);
|
||||
return output;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ps_colclip_resolve__)
|
||||
PS_OUTPUT ps_colclip_resolve(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
float4 value = sample_c(input.t);
|
||||
output.c = float4(float3(uint3(value.rgb * 65535.5) & 255) / 255, value.a);
|
||||
output.o = float4(float3(uint3(value.rgb * 65535.5) & 255) / 255, value.a);
|
||||
return output;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint ps_convert_float32_32bits(PS_INPUT input) : SV_Target0
|
||||
#if defined(__ps_convert_depth32_32bits__)
|
||||
OUTPUT_TYPE ps_convert_depth32_32bits(PS_INPUT input) : OUTPUT_SV
|
||||
{
|
||||
// Convert a FLOAT32 depth texture into a 32 bits UINT texture
|
||||
return uint(exp2(32.0f) * sample_c(input.t).r);
|
||||
// Convert a depth texture into a 32 bits UINT texture
|
||||
return depth_to_uint(sample_c(input.t));
|
||||
}
|
||||
#endif
|
||||
|
||||
PS_OUTPUT ps_convert_float32_rgba8(PS_INPUT input)
|
||||
#if defined(__ps_convert_depth32_rgba8__)
|
||||
OUTPUT_TYPE ps_convert_depth32_rgba8(PS_INPUT input) : OUTPUT_SV
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
// Convert a FLOAT32 depth texture into a RGBA color texture
|
||||
uint d = uint(sample_c(input.t).r * exp2(32.0f));
|
||||
output.c = float4(uint4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24))) / 255.0f;
|
||||
|
||||
return output;
|
||||
// Convert a depth texture into a RGBA color texture
|
||||
return depth32_to_rgba8(sample_c(input.t));
|
||||
}
|
||||
#endif
|
||||
|
||||
PS_OUTPUT ps_convert_float16_rgb5a1(PS_INPUT input)
|
||||
#if defined(__ps_convert_depth16_rgb5a1__)
|
||||
OUTPUT_TYPE ps_convert_depth16_rgb5a1(PS_INPUT input) : OUTPUT_SV
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
// Convert a FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture
|
||||
uint d = uint(sample_c(input.t).r * exp2(32.0f));
|
||||
output.c = float4(uint4(d << 3, d >> 2, d >> 7, d >> 8) & uint4(0xf8, 0xf8, 0xf8, 0x80)) / 255.0f;
|
||||
return output;
|
||||
// Convert depth (only 16 lsb) into a RGB5A1 color texture
|
||||
return depth16_to_rgb5a1(sample_c(input.t));
|
||||
}
|
||||
#endif
|
||||
|
||||
float rgba8_to_depth32(float4 val)
|
||||
{
|
||||
uint4 c = uint4(val * 255.5f);
|
||||
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float rgba8_to_depth24(float4 val)
|
||||
{
|
||||
uint3 c = uint3(val.rgb * 255.5f);
|
||||
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float rgba8_to_depth16(float4 val)
|
||||
{
|
||||
uint2 c = uint2(val.rg * 255.5f);
|
||||
return float(c.r | (c.g << 8)) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float rgb5a1_to_depth16(float4 val)
|
||||
{
|
||||
uint4 c = uint4(val * 255.5f);
|
||||
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float ps_convert_float32_depth_to_color(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
return sample_c(input.t).r;
|
||||
}
|
||||
|
||||
float ps_convert_float32_color_to_depth(PS_INPUT input) : SV_Depth
|
||||
{
|
||||
return sample_c(input.t).r;
|
||||
}
|
||||
|
||||
float ps_convert_float32_float24(PS_INPUT input) : SV_Depth
|
||||
#if defined(__ps_convert_depth32_depth24__)
|
||||
OUTPUT_TYPE ps_convert_depth32_depth24(PS_INPUT input) : OUTPUT_SV
|
||||
{
|
||||
// Truncates depth value to 24bits
|
||||
uint d = uint(sample_c(input.t).r * exp2(32.0f)) & 0xFFFFFFu;
|
||||
return float(d) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float ps_convert_rgba8_float32(PS_INPUT input) : SV_Depth
|
||||
{
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
return rgba8_to_depth32(sample_c(input.t));
|
||||
}
|
||||
|
||||
float ps_convert_rgba8_float24(PS_INPUT input) : SV_Depth
|
||||
{
|
||||
// Same as above but without the alpha channel (24 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
return rgba8_to_depth24(sample_c(input.t));
|
||||
}
|
||||
|
||||
float ps_convert_rgba8_float16(PS_INPUT input) : SV_Depth
|
||||
{
|
||||
// Same as above but without the A/B channels (16 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
return rgba8_to_depth16(sample_c(input.t));
|
||||
}
|
||||
|
||||
float ps_convert_rgb5a1_float16(PS_INPUT input) : SV_Depth
|
||||
{
|
||||
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
|
||||
return rgb5a1_to_depth16(sample_c(input.t));
|
||||
return depth32_to_depth24(sample_c(input.t));
|
||||
}
|
||||
#endif
|
||||
|
||||
#define SAMPLE_RGBA_DEPTH_BILN(CONVERT_FN) \
|
||||
uint width, height; \
|
||||
@@ -272,34 +336,57 @@ float ps_convert_rgb5a1_float16(PS_INPUT input) : SV_Depth
|
||||
float depthBR = CONVERT_FN(Texture.Load(int3(coords.zw, 0))); \
|
||||
return lerp(lerp(depthTL, depthTR, mix_vals.x), lerp(depthBL, depthBR, mix_vals.x), mix_vals.y);
|
||||
|
||||
float ps_convert_rgba8_float32_biln(PS_INPUT input) : SV_Depth
|
||||
#if defined(__ps_convert_rgba8_depth32__)
|
||||
OUTPUT_TYPE ps_convert_rgba8_depth32(PS_INPUT input) : OUTPUT_SV
|
||||
{
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
#if HAS_BILN
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32);
|
||||
#else
|
||||
return rgba8_to_depth32(sample_c(input.t));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
float ps_convert_rgba8_float24_biln(PS_INPUT input) : SV_Depth
|
||||
#if defined(__ps_convert_rgba8_depth24__)
|
||||
OUTPUT_TYPE ps_convert_rgba8_depth24(PS_INPUT input) : OUTPUT_SV
|
||||
{
|
||||
// Same as above but without the alpha channel (24 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
#if HAS_BILN
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24);
|
||||
#else
|
||||
return rgba8_to_depth24(sample_c(input.t));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
float ps_convert_rgba8_float16_biln(PS_INPUT input) : SV_Depth
|
||||
#if defined(__ps_convert_rgba8_depth16__)
|
||||
OUTPUT_TYPE ps_convert_rgba8_depth16(PS_INPUT input) : OUTPUT_SV
|
||||
{
|
||||
// Same as above but without the A/B channels (16 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
#if HAS_BILN
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16);
|
||||
#else
|
||||
return rgba8_to_depth16(sample_c(input.t));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
float ps_convert_rgb5a1_float16_biln(PS_INPUT input) : SV_Depth
|
||||
#if defined(__ps_convert_rgb5a1_depth16__)
|
||||
OUTPUT_TYPE ps_convert_rgb5a1_depth16(PS_INPUT input) : OUTPUT_SV
|
||||
{
|
||||
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
|
||||
#if HAS_BILN
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16);
|
||||
#else
|
||||
return rgb5a1_to_depth16(sample_c(input.t));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ps_convert_rgb5a1_8i__)
|
||||
PS_OUTPUT ps_convert_rgb5a1_8i(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
@@ -406,7 +493,7 @@ PS_OUTPUT ps_convert_rgb5a1_8i(PS_INPUT input)
|
||||
uint red = (denorm_c.r >> 3) & 0x1Fu;
|
||||
uint green = (denorm_c.g >> 3) & 0x1Fu;
|
||||
|
||||
output.c = (float4)(((float)(((green << 5) | red) & 0xFFu)) / 255.0f);
|
||||
output.o = (float4)(((float)(((green << 5) | red) & 0xFFu)) / 255.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -414,11 +501,13 @@ PS_OUTPUT ps_convert_rgb5a1_8i(PS_INPUT input)
|
||||
uint blue = (denorm_c.b >> 3) & 0x1Fu;
|
||||
uint alpha = denorm_c.a & 0x80u;
|
||||
|
||||
output.c = (float4)(((float)((alpha | (blue << 2) | (green >> 3)) & 0xFFu)) / 255.0f);
|
||||
output.o = (float4)(((float)((alpha | (blue << 2) | (green >> 3)) & 0xFFu)) / 255.0f);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ps_convert_rgba_8i__)
|
||||
PS_OUTPUT ps_convert_rgba_8i(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
@@ -462,10 +551,12 @@ PS_OUTPUT ps_convert_rgba_8i(PS_INPUT input)
|
||||
float4 pixel = Texture.Load(int3(int2(coord), 0));
|
||||
float2 sel0 = (pos.y & 2u) == 0u ? pixel.rb : pixel.ga;
|
||||
float sel1 = (pos.x & 8u) == 0u ? sel0.x : sel0.y;
|
||||
output.c = (float4)(sel1); // Divide by something here?
|
||||
output.o = (float4)(sel1); // Divide by something here?
|
||||
return output;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ps_convert_clut_4__)
|
||||
PS_OUTPUT ps_convert_clut_4(PS_INPUT input)
|
||||
{
|
||||
// Borrowing the YUV constant buffer.
|
||||
@@ -478,10 +569,12 @@ PS_OUTPUT ps_convert_clut_4(PS_INPUT input)
|
||||
|
||||
int2 final = int2(floor(float2(offset + pos) * scale));
|
||||
PS_OUTPUT output;
|
||||
output.c = Texture.Load(int3(final, 0), 0);
|
||||
output.o = Texture.Load(int3(final, 0), 0);
|
||||
return output;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ps_convert_clut_8__)
|
||||
PS_OUTPUT ps_convert_clut_8(PS_INPUT input)
|
||||
{
|
||||
float scale = BGColor.x;
|
||||
@@ -497,10 +590,12 @@ PS_OUTPUT ps_convert_clut_8(PS_INPUT input)
|
||||
|
||||
int2 final = int2(floor(float2(offset + pos) * scale));
|
||||
PS_OUTPUT output;
|
||||
output.c = Texture.Load(int3(final, 0), 0);
|
||||
output.o = Texture.Load(int3(final, 0), 0);
|
||||
return output;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__ps_yuv__)
|
||||
PS_OUTPUT ps_yuv(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
@@ -515,41 +610,43 @@ PS_OUTPUT ps_yuv(PS_INPUT input)
|
||||
switch (EMODA)
|
||||
{
|
||||
case 0:
|
||||
output.c.a = i.a;
|
||||
output.o.a = i.a;
|
||||
break;
|
||||
case 1:
|
||||
output.c.a = Y;
|
||||
output.o.a = Y;
|
||||
break;
|
||||
case 2:
|
||||
output.c.a = Y / 2.0f;
|
||||
output.o.a = Y / 2.0f;
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
output.c.a = 0.0f;
|
||||
output.o.a = 0.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (EMODC)
|
||||
{
|
||||
case 0:
|
||||
output.c.rgb = i.rgb;
|
||||
output.o.rgb = i.rgb;
|
||||
break;
|
||||
case 1:
|
||||
output.c.rgb = float3(Y, Y, Y);
|
||||
output.o.rgb = float3(Y, Y, Y);
|
||||
break;
|
||||
case 2:
|
||||
output.c.rgb = float3(Y, Cb, Cr);
|
||||
output.o.rgb = float3(Y, Cb, Cr);
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
output.c.rgb = float3(i.a, i.a, i.a);
|
||||
output.o.rgb = float3(i.a, i.a, i.a);
|
||||
break;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
#endif
|
||||
|
||||
float ps_stencil_image_init_0(PS_INPUT input) : SV_Target
|
||||
#if defined(__ps_primid_image_init_0__)
|
||||
float ps_primid_image_init_0(PS_INPUT input) : SV_Target
|
||||
{
|
||||
float c;
|
||||
if ((127.5f / 255.0f) < sample_c(input.t).a) // < 0x80 pass (== 0x80 should not pass)
|
||||
@@ -558,8 +655,10 @@ float ps_stencil_image_init_0(PS_INPUT input) : SV_Target
|
||||
c = float(0x7FFFFFFF);
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
float ps_stencil_image_init_1(PS_INPUT input) : SV_Target
|
||||
#if defined(__ps_primid_image_init_1__)
|
||||
float ps_primid_image_init_1(PS_INPUT input) : SV_Target
|
||||
{
|
||||
float c;
|
||||
if (sample_c(input.t).a < (127.5f / 255.0f)) // >= 0x80 pass
|
||||
@@ -568,9 +667,10 @@ float ps_stencil_image_init_1(PS_INPUT input) : SV_Target
|
||||
c = float(0x7FFFFFFF);
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
float ps_stencil_image_init_2(PS_INPUT input)
|
||||
: SV_Target
|
||||
#if defined(__ps_primid_image_init_2__)
|
||||
float ps_primid_image_init_2(PS_INPUT input) : SV_Target
|
||||
{
|
||||
float c;
|
||||
if ((254.5f / 255.0f) < sample_c(input.t).a) // < 0x80 pass (== 0x80 should not pass)
|
||||
@@ -579,9 +679,10 @@ float ps_stencil_image_init_2(PS_INPUT input)
|
||||
c = float(0x7FFFFFFF);
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
float ps_stencil_image_init_3(PS_INPUT input)
|
||||
: SV_Target
|
||||
#if defined(__ps_primid_image_init_3__)
|
||||
float ps_primid_image_init_3(PS_INPUT input) : SV_Target
|
||||
{
|
||||
float c;
|
||||
if (sample_c(input.t).a < (254.5f / 255.0f)) // >= 0x80 pass
|
||||
@@ -590,3 +691,6 @@ float ps_stencil_image_init_3(PS_INPUT input)
|
||||
c = float(0x7FFFFFFF);
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // PIXEL_SHADER
|
||||
@@ -50,6 +50,12 @@
|
||||
#define PS_AA1_TRIANGLE_SW_Z 3
|
||||
#endif
|
||||
|
||||
#ifndef PS_ROV_DEPTH_NONE
|
||||
#define PS_ROV_DEPTH_NONE 0
|
||||
#define PS_ROV_DEPTH_READ_WRITE 1
|
||||
#define PS_ROV_DEPTH_READ_ONLY 2
|
||||
#endif
|
||||
|
||||
#ifndef PS_FST
|
||||
#define PS_IIP 0
|
||||
#define PS_FST 0
|
||||
@@ -111,6 +117,8 @@
|
||||
#define PS_TEX_IS_FB 0
|
||||
#define PS_AA1 0
|
||||
#define PS_ABE 0
|
||||
#define PS_ROV_COLOR 0
|
||||
#define PS_ROV_DEPTH 0
|
||||
#endif
|
||||
|
||||
#ifndef VS_EXPAND_NONE
|
||||
@@ -132,6 +140,12 @@
|
||||
#define SW_DEPTH (NEEDS_DEPTH_FOR_AFAIL || NEEDS_DEPTH_FOR_ZTST || NEEDS_DEPTH_FOR_AA1)
|
||||
#define ZWRITE (PS_ZFLOOR || PS_ZCLAMP || SW_DEPTH)
|
||||
|
||||
#define PS_RETURN_COLOR_ROV (!PS_NO_COLOR && PS_ROV_COLOR)
|
||||
#define PS_RETURN_COLOR (!PS_NO_COLOR && !PS_ROV_COLOR)
|
||||
#define PS_RETURN_DEPTH_ROV (PS_ROV_DEPTH == PS_ROV_DEPTH_READ_WRITE)
|
||||
#define PS_RETURN_DEPTH (ZWRITE && !PS_ROV_DEPTH)
|
||||
#define PS_ROV_EARLYDEPTHSTENCIL (PS_ROV_COLOR && !PS_ROV_DEPTH && !ZWRITE)
|
||||
|
||||
struct VS_INPUT
|
||||
{
|
||||
float2 st : TEXCOORD0;
|
||||
@@ -178,22 +192,27 @@ struct PS_INPUT
|
||||
|
||||
#ifdef PIXEL_SHADER
|
||||
|
||||
struct PS_OUTPUT
|
||||
struct PS_OUTPUT_REAL
|
||||
{
|
||||
#define NUM_RTS 0
|
||||
#if !PS_NO_COLOR
|
||||
#if PS_DATE == 1 || PS_DATE == 2
|
||||
float c : SV_Target;
|
||||
#else
|
||||
float4 c0 : SV_Target0;
|
||||
#undef NUM_RTS
|
||||
#define NUM_RTS 1
|
||||
#if !PS_NO_COLOR1
|
||||
float4 c1 : SV_Target1;
|
||||
|
||||
#if PS_RETURN_COLOR
|
||||
#if PS_DATE == 1 || PS_DATE == 2
|
||||
float c : SV_Target;
|
||||
#else
|
||||
|
||||
float4 c0 : SV_Target0;
|
||||
|
||||
#undef NUM_RTS
|
||||
#define NUM_RTS 1
|
||||
|
||||
#if !PS_NO_COLOR1
|
||||
float4 c1 : SV_Target1;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#if ZWRITE
|
||||
|
||||
#if PS_RETURN_DEPTH
|
||||
// In DX12 we do depth feedback loops with a color copy.
|
||||
#if SW_DEPTH && PS_NO_COLOR1 && DX12
|
||||
#if NUM_RTS > 0
|
||||
@@ -208,16 +227,45 @@ struct PS_OUTPUT
|
||||
float depth : SV_Depth;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#undef NUM_RTS
|
||||
};
|
||||
|
||||
struct PS_OUTPUT
|
||||
{
|
||||
#if !PS_NO_COLOR
|
||||
#if PS_DATE == 1 || PS_DATE == 2
|
||||
float c;
|
||||
#else
|
||||
float4 c0;
|
||||
#if !PS_NO_COLOR1
|
||||
float4 c1;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
Texture2D<float4> Texture : register(t0);
|
||||
Texture2D<float4> Palette : register(t1);
|
||||
#if !PS_ROV_COLOR
|
||||
Texture2D<float4> RtTexture : register(t2);
|
||||
#endif
|
||||
Texture2D<float> PrimMinTexture : register(t3);
|
||||
#if !PS_ROV_DEPTH
|
||||
Texture2D<float> DepthTexture : register(t4);
|
||||
#endif
|
||||
SamplerState TextureSampler : register(s0);
|
||||
|
||||
#if PS_ROV_COLOR
|
||||
RasterizerOrderedTexture2D<unorm float4> RtTextureRov : register(u0);
|
||||
static float4 rov_rt_value;
|
||||
#endif
|
||||
|
||||
#if PS_ROV_DEPTH
|
||||
RasterizerOrderedTexture2D<float> DepthTextureRov : register(u1);
|
||||
static float rov_depth_value;
|
||||
#endif
|
||||
|
||||
#ifdef DX12
|
||||
cbuffer cb1 : register(b1)
|
||||
#else
|
||||
@@ -244,6 +292,38 @@ cbuffer cb1
|
||||
float RcpScaleFactor;
|
||||
};
|
||||
|
||||
float4 RtLoad(int2 xy)
|
||||
{
|
||||
#if PS_ROV_COLOR
|
||||
return rov_rt_value;
|
||||
#else
|
||||
return RtTexture.Load(int3(int2(xy), 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
float DepthLoad(int2 xy)
|
||||
{
|
||||
#if PS_ROV_DEPTH
|
||||
return rov_depth_value;
|
||||
#else
|
||||
return DepthTexture.Load(int3(int2(xy), 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
void RtWrite(int2 xy, float4 c)
|
||||
{
|
||||
#if PS_ROV_COLOR
|
||||
RtTextureRov[xy] = c;
|
||||
#endif
|
||||
}
|
||||
|
||||
void DepthWrite(int2 xy, float d)
|
||||
{
|
||||
#if PS_ROV_DEPTH
|
||||
DepthTextureRov[xy] = d;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (PS_AUTOMATIC_LOD != 1) && (PS_MANUAL_LOD == 1)
|
||||
float manual_lod(float uv_w)
|
||||
{
|
||||
@@ -407,7 +487,7 @@ float4 sample_c_af(float2 uv, float uv_w)
|
||||
float4 sample_c(float2 uv, float uv_w, int2 xy)
|
||||
{
|
||||
#if PS_TEX_IS_FB == 1
|
||||
return RtTexture.Load(int3(int2(xy), 0));
|
||||
return RtLoad(xy);
|
||||
#elif PS_REGION_RECT == 1
|
||||
return Texture.Load(int3(int2(uv), 0));
|
||||
#else
|
||||
@@ -602,7 +682,7 @@ float4x4 sample_4p(uint4 u)
|
||||
uint fetch_raw_depth(int2 xy)
|
||||
{
|
||||
#if PS_TEX_IS_FB == 1
|
||||
float4 col = RtTexture.Load(int3(xy, 0));
|
||||
float4 col = RtLoad(xy);
|
||||
#else
|
||||
float4 col = Texture.Load(int3(xy, 0));
|
||||
#endif
|
||||
@@ -612,7 +692,7 @@ uint fetch_raw_depth(int2 xy)
|
||||
float4 fetch_raw_color(int2 xy)
|
||||
{
|
||||
#if PS_TEX_IS_FB == 1
|
||||
return RtTexture.Load(int3(xy, 0));
|
||||
return RtLoad(xy);
|
||||
#else
|
||||
return Texture.Load(int3(xy, 0));
|
||||
#endif
|
||||
@@ -621,7 +701,7 @@ float4 fetch_raw_color(int2 xy)
|
||||
float4 fetch_c(int2 uv)
|
||||
{
|
||||
#if PS_TEX_IS_FB == 1
|
||||
return RtTexture.Load(int3(uv, 0));
|
||||
return RtLoad(uv);
|
||||
#else
|
||||
return Texture.Load(int3(uv, 0));
|
||||
#endif
|
||||
@@ -707,7 +787,7 @@ float4 sample_depth(float2 st, float2 pos)
|
||||
}
|
||||
else if (PS_DEPTH_FMT == 1)
|
||||
{
|
||||
// Based on ps_convert_float32_rgba8 of convert
|
||||
// Based on ps_convert_depth32_rgba8 of convert
|
||||
|
||||
// Convert a FLOAT32 depth texture into a RGBA color texture
|
||||
uint d = uint(fetch_c(uv).r * exp2(32.0f));
|
||||
@@ -715,7 +795,7 @@ float4 sample_depth(float2 st, float2 pos)
|
||||
}
|
||||
else if (PS_DEPTH_FMT == 2)
|
||||
{
|
||||
// Based on ps_convert_float16_rgb5a1 of convert
|
||||
// Based on ps_convert_depth16_rgb5a1 of convert
|
||||
|
||||
// Convert a FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture
|
||||
uint d = uint(fetch_c(uv).r * exp2(32.0f));
|
||||
@@ -1027,7 +1107,7 @@ void ps_fbmask(inout float4 C, float2 pos_xy)
|
||||
if (PS_FBMASK)
|
||||
{
|
||||
float multi = PS_COLCLIP_HW ? 65535.0f : 255.0f;
|
||||
float4 RT = trunc(RtTexture.Load(int3(pos_xy, 0)) * multi + 0.1f);
|
||||
float4 RT = trunc(RtLoad(int2(pos_xy)) * multi + 0.1f);
|
||||
C = (float4)(((uint4)C & ~FbMask) | ((uint4)RT & FbMask));
|
||||
}
|
||||
}
|
||||
@@ -1103,7 +1183,7 @@ void ps_blend(inout float4 Color, inout float4 As_rgba, float2 pos_xy)
|
||||
As_rgba.rgb = (float3)1.0f;
|
||||
}
|
||||
|
||||
float4 RT = SW_BLEND_NEEDS_RT ? RtTexture.Load(int3(pos_xy, 0)) : (float4)0.0f;
|
||||
float4 RT = SW_BLEND_NEEDS_RT ? RtLoad(int2(pos_xy)) : (float4)0.0f;
|
||||
|
||||
if (PS_SHUFFLE && SW_BLEND_NEEDS_RT)
|
||||
{
|
||||
@@ -1236,20 +1316,49 @@ void ps_blend(inout float4 Color, inout float4 As_rgba, float2 pos_xy)
|
||||
}
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_main(PS_INPUT input)
|
||||
#if PS_ROV_EARLYDEPTHSTENCIL
|
||||
[earlydepthstencil]
|
||||
#endif
|
||||
|
||||
#if PS_ROV_COLOR || PS_ROV_DEPTH
|
||||
#define DISCARD rov_discard = true
|
||||
#else
|
||||
#define DISCARD discard
|
||||
#endif
|
||||
|
||||
#if (PS_RETURN_COLOR || PS_RETURN_DEPTH)
|
||||
PS_OUTPUT_REAL ps_main(PS_INPUT input)
|
||||
#else
|
||||
void ps_main(PS_INPUT input)
|
||||
#endif
|
||||
{
|
||||
// Must floor before depth testing.
|
||||
#if PS_ZFLOOR
|
||||
input.p.z = floor(input.p.z * exp2(32.0f)) * exp2(-32.0f);
|
||||
#endif
|
||||
|
||||
#if PS_ZTST == ZTST_GEQUAL
|
||||
if (input.p.z < DepthTexture.Load(int3(input.p.xy, 0)).r)
|
||||
discard;
|
||||
#elif PS_ZTST == ZTST_GREATER
|
||||
if (input.p.z <= DepthTexture.Load(int3(input.p.xy, 0)).r)
|
||||
discard;
|
||||
#if PS_ROV_COLOR
|
||||
rov_rt_value = RtTextureRov[input.p.xy];
|
||||
#endif
|
||||
|
||||
#if PS_ROV_DEPTH
|
||||
rov_depth_value = DepthTextureRov[input.p.xy];
|
||||
#endif
|
||||
|
||||
#if PS_ROV_COLOR || PS_ROV_DEPTH
|
||||
bool rov_discard = false;
|
||||
#endif
|
||||
|
||||
// Use ROV discard macro for since we cannot do
|
||||
// conditional discard based on value read from ROV.
|
||||
#if PS_ZTST == ZTST_GEQUAL
|
||||
if (input.p.z < DepthLoad(input.p.xy))
|
||||
DISCARD;
|
||||
#elif PS_ZTST == ZTST_GREATER
|
||||
if (input.p.z <= DepthLoad(input.p.xy))
|
||||
DISCARD;
|
||||
#endif
|
||||
|
||||
float4 C = ps_color(input);
|
||||
|
||||
#if PS_AA1
|
||||
@@ -1267,13 +1376,11 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||
|
||||
bool atst_pass = atst(C);
|
||||
|
||||
#if PS_AFAIL == AFAIL_KEEP
|
||||
#if PS_ATST != PS_ATST_NONE && PS_AFAIL == AFAIL_KEEP
|
||||
if (!atst_pass)
|
||||
discard;
|
||||
#endif
|
||||
|
||||
PS_OUTPUT output;
|
||||
|
||||
if (PS_SCANMSK & 2)
|
||||
{
|
||||
// fail depth test on prohibited lines
|
||||
@@ -1284,7 +1391,7 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||
float4 alpha_blend = (float4)0.0f;
|
||||
if (SW_AD_TO_HW)
|
||||
{
|
||||
float4 RT = PS_RTA_CORRECTION ? trunc(RtTexture.Load(int3(input.p.xy, 0)) * 128.0f + 0.1f) : trunc(RtTexture.Load(int3(input.p.xy, 0)) * 255.0f + 0.1f);
|
||||
float4 RT = PS_RTA_CORRECTION ? trunc(RtLoad(input.p.xy) * 128.0f + 0.1f) : trunc(RtLoad(input.p.xy) * 255.0f + 0.1f);
|
||||
alpha_blend = (float4)(RT.a / 128.0f);
|
||||
}
|
||||
else
|
||||
@@ -1308,9 +1415,9 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||
|
||||
#if PS_WRITE_RG == 1
|
||||
// Pseudo 16 bits access.
|
||||
float rt_a = RtTexture.Load(int3(input.p.xy, 0)).g;
|
||||
float rt_a = RtLoad(input.p.xy).g;
|
||||
#else
|
||||
float rt_a = RtTexture.Load(int3(input.p.xy, 0)).a;
|
||||
float rt_a = RtLoad(input.p.xy).a;
|
||||
#endif
|
||||
|
||||
#if (PS_DATE & 3) == 1
|
||||
@@ -1329,9 +1436,8 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (bad)
|
||||
discard;
|
||||
|
||||
if (bad)
|
||||
discard;
|
||||
#endif
|
||||
|
||||
#if PS_DATE == 3
|
||||
@@ -1342,6 +1448,8 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||
discard;
|
||||
#endif
|
||||
|
||||
PS_OUTPUT output;
|
||||
|
||||
// Get first primitive that will write a failling alpha value
|
||||
#if PS_DATE == 1
|
||||
// DATM == 0
|
||||
@@ -1427,32 +1535,32 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||
alpha_blend.a = float(atst_pass);
|
||||
#endif
|
||||
|
||||
// Output color scaling
|
||||
#if !PS_NO_COLOR
|
||||
output.c0.a = PS_RTA_CORRECTION ? C.a / 128.0f : C.a / 255.0f;
|
||||
output.c0.rgb = PS_COLCLIP_HW ? float3(C.rgb / 65535.0f) : C.rgb / 255.0f;
|
||||
#if !PS_NO_COLOR1
|
||||
output.c1 = alpha_blend;
|
||||
#endif
|
||||
#endif // !PS_NO_COLOR
|
||||
|
||||
// Alpha test with feedback
|
||||
#if PS_AFAIL == AFAIL_FB_ONLY
|
||||
if (!atst_pass)
|
||||
input.p.z = DepthTexture.Load(int3(input.p.xy, 0)).r;
|
||||
input.p.z = DepthLoad(input.p.xy);
|
||||
#elif PS_AFAIL == AFAIL_ZB_ONLY
|
||||
if (!atst_pass)
|
||||
output.c0 = RtTexture.Load(int3(input.p.xy, 0));
|
||||
output.c0 = RtLoad(input.p.xy);
|
||||
#elif PS_AFAIL == AFAIL_RGB_ONLY || PS_AFAIL == AFAIL_RGB_ONLY_SW_Z
|
||||
if (!atst_pass)
|
||||
{
|
||||
output.c0.a = RtTexture.Load(int3(input.p.xy, 0)).a;
|
||||
output.c0.a = RtLoad(input.p.xy).a;
|
||||
#if PS_AFAIL == AFAIL_RGB_ONLY_SW_Z
|
||||
input.p.z = DepthTexture.Load(int3(input.p.xy, 0)).r;
|
||||
input.p.z = DepthLoad(input.p.xy);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // !PS_NO_COLOR
|
||||
|
||||
#endif // PS_DATE != 1/2
|
||||
|
||||
#if PS_ZCLAMP
|
||||
@@ -1461,18 +1569,47 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||
|
||||
#if PS_AA1 == PS_AA1_TRIANGLE_SW_Z
|
||||
if (!bool(input.interior))
|
||||
input.p.z = DepthTexture.Load(int3(input.p.xy, 0)).r; // No depth update for triangle edges.
|
||||
input.p.z = DepthLoad(input.p.xy); // No depth update for triangle edges.
|
||||
#endif
|
||||
|
||||
#if ZWRITE
|
||||
#if SW_DEPTH && PS_NO_COLOR1 && DX12
|
||||
// Output color clone for feedback as well as real depth.
|
||||
output.depth_color = input.p.z;
|
||||
#endif
|
||||
output.depth = input.p.z;
|
||||
#if (PS_RETURN_COLOR || PS_RETURN_DEPTH)
|
||||
// Output struct with the actual system values output semantics.
|
||||
PS_OUTPUT_REAL output_real;
|
||||
#endif
|
||||
|
||||
return output;
|
||||
// Color write back
|
||||
#if PS_RETURN_COLOR
|
||||
#if PS_DATE == 1 || PS_DATE == 2
|
||||
output_real.c = output.c;
|
||||
#else
|
||||
output_real.c0 = output.c0;
|
||||
#if !PS_NO_COLOR1
|
||||
output_real.c1 = output.c1;
|
||||
#endif
|
||||
#endif
|
||||
#elif PS_RETURN_COLOR_ROV
|
||||
output.c0 = (rov_discard | (FbMask == 0xFFu)) ? RtLoad(input.p.xy) : output.c0;
|
||||
|
||||
RtWrite(input.p.xy, output.c0);
|
||||
#endif
|
||||
|
||||
// Depth write back
|
||||
#if PS_RETURN_DEPTH
|
||||
output_real.depth = input.p.z;
|
||||
#if SW_DEPTH && PS_NO_COLOR1 && DX12
|
||||
// Output color clone for feedback.
|
||||
output_real.depth_color = input.p.z;
|
||||
#endif
|
||||
#elif PS_RETURN_DEPTH_ROV
|
||||
#if SW_DEPTH
|
||||
input.p.z = rov_discard ? DepthLoad(input.p.xy) : input.p.z;
|
||||
#endif
|
||||
DepthWrite(input.p.xy, input.p.z);
|
||||
#endif
|
||||
|
||||
#if (PS_RETURN_COLOR || PS_RETURN_DEPTH)
|
||||
return output_real;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // PIXEL_SHADER
|
||||
|
||||
@@ -3,21 +3,12 @@
|
||||
|
||||
//#version 420 // Keep it for editor detection
|
||||
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
|
||||
layout(location = 0) in vec2 POSITION;
|
||||
layout(location = 1) in vec2 TEXCOORD0;
|
||||
layout(location = 7) in vec4 COLOR;
|
||||
|
||||
// FIXME set the interpolation (don't know what dx do)
|
||||
// flat means that there is no interpolation. The value given to the fragment shader is based on the provoking vertex conventions.
|
||||
//
|
||||
// noperspective means that there will be linear interpolation in window-space. This is usually not what you want, but it can have its uses.
|
||||
//
|
||||
// smooth, the default, means to do perspective-correct interpolation.
|
||||
//
|
||||
// The centroid qualifier only matters when multisampling. If this qualifier is not present, then the value is interpolated to the pixel's center, anywhere in the pixel, or to one of the pixel's samples. This sample may lie outside of the actual primitive being rendered, since a primitive can cover only part of a pixel's area. The centroid qualifier is used to prevent this; the interpolation point must fall within both the pixel's area and the primitive's area.
|
||||
out vec4 PSin_p;
|
||||
out vec2 PSin_t;
|
||||
out vec4 PSin_c;
|
||||
@@ -40,44 +31,125 @@ in vec4 PSin_c;
|
||||
|
||||
layout(binding = 0) uniform sampler2D TextureSampler;
|
||||
|
||||
// Give a different name so I remember there is a special case!
|
||||
#if defined(ps_convert_rgba8_16bits) || defined(ps_convert_float32_32bits)
|
||||
layout(location = 0) out uint SV_Target1;
|
||||
#elif defined(ps_convert_float32_depth_to_color)
|
||||
layout(location = 0) out float SV_Target0;
|
||||
#elif !defined(ps_datm1) && \
|
||||
!defined(ps_datm0) && \
|
||||
!defined(ps_datm1_rta_correction) && \
|
||||
!defined(ps_datm0_rta_correction) && \
|
||||
!defined(ps_convert_rgba8_float32) && \
|
||||
!defined(ps_convert_rgba8_float24) && \
|
||||
!defined(ps_convert_rgba8_float16) && \
|
||||
!defined(ps_convert_rgb5a1_float16) && \
|
||||
!defined(ps_convert_rgba8_float32_biln) && \
|
||||
!defined(ps_convert_rgba8_float24_biln) && \
|
||||
!defined(ps_convert_rgba8_float16_biln) && \
|
||||
!defined(ps_convert_rgb5a1_float16_biln) && \
|
||||
!defined(ps_convert_float32_float24) && \
|
||||
!defined(ps_depth_copy)
|
||||
layout(location = 0) out vec4 SV_Target0;
|
||||
#if HAS_INTEGER_OUTPUT
|
||||
layout(location = 0) out uint o_col0;
|
||||
#define OUTPUT o_col0
|
||||
#elif HAS_DEPTH_OUTPUT
|
||||
out float gl_FragDepth;
|
||||
#define OUTPUT gl_FragDepth
|
||||
#elif HAS_FLOAT32_OUTPUT
|
||||
layout(location = 0) out float o_col0;
|
||||
#define OUTPUT o_col0
|
||||
#elif HAS_STENCIL_OUTPUT
|
||||
#else
|
||||
layout(location = 0) out vec4 o_col0;
|
||||
#define OUTPUT o_col0
|
||||
#endif
|
||||
|
||||
#if HAS_FLOAT32_INPUT
|
||||
|
||||
float sample_c()
|
||||
{
|
||||
return texture(TextureSampler, PSin_t).r;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
vec4 sample_c()
|
||||
{
|
||||
return texture(TextureSampler, PSin_t);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
uint rgba8_to_uint(vec4 c)
|
||||
{
|
||||
uvec4 i = uvec4(c * 255.5f) & 0xFFu;
|
||||
return i.r | (i.g << 8) | (i.b << 16) | (i.a << 24);
|
||||
}
|
||||
|
||||
uint rgb5a1_to_uint(vec4 c)
|
||||
{
|
||||
uvec4 i = uvec4(c * 255.5f) & uvec4(0xF8u, 0xF8u, 0xF8u, 0x80u);
|
||||
return (i.r >> 3) | (i.g << 2) | (i.b << 7) | (i.a << 8);
|
||||
}
|
||||
|
||||
uint depth_to_uint(float d)
|
||||
{
|
||||
return uint(d * exp2(32.0f));
|
||||
}
|
||||
|
||||
vec4 uint_to_rgba8(uint i)
|
||||
{
|
||||
return vec4((i & 0xFFu), ((i >> 8) & 0xFFu), ((i >> 16) & 0xFFu), ((i >> 24) & 0xFFu)) / 255.0f;
|
||||
}
|
||||
|
||||
vec4 uint_to_rgb5a1(uint i)
|
||||
{
|
||||
return vec4(uvec4(i << 3, i >> 2, i >> 7, i >> 8) & uvec4(0xF8u, 0xF8u, 0xF8u, 0x80u)) / 255.0f;
|
||||
}
|
||||
|
||||
float uint_to_depth32(uint i)
|
||||
{
|
||||
return float(i) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float uint_to_depth24(uint i)
|
||||
{
|
||||
return float(i & 0xFFFFFFu) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float uint_to_depth16(uint i)
|
||||
{
|
||||
return float(i & 0xFFFFu) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float rgba8_to_depth32(vec4 val)
|
||||
{
|
||||
return uint_to_depth32(rgba8_to_uint(val));
|
||||
}
|
||||
|
||||
float rgba8_to_depth24(vec4 val)
|
||||
{
|
||||
return uint_to_depth24(rgba8_to_uint(val));
|
||||
}
|
||||
|
||||
float rgba8_to_depth16(vec4 val)
|
||||
{
|
||||
return uint_to_depth16(rgba8_to_uint(val));
|
||||
}
|
||||
|
||||
float rgb5a1_to_depth16(vec4 val)
|
||||
{
|
||||
return uint_to_depth16(rgb5a1_to_uint(val));
|
||||
}
|
||||
|
||||
vec4 depth32_to_rgba8(float d)
|
||||
{
|
||||
return uint_to_rgba8(depth_to_uint(d));
|
||||
}
|
||||
|
||||
vec4 depth16_to_rgb5a1(float d)
|
||||
{
|
||||
return uint_to_rgb5a1(depth_to_uint(d));
|
||||
}
|
||||
|
||||
float depth32_to_depth24(float d)
|
||||
{
|
||||
return uint_to_depth24(depth_to_uint(d));
|
||||
}
|
||||
|
||||
#ifdef ps_copy
|
||||
void ps_copy()
|
||||
{
|
||||
SV_Target0 = sample_c();
|
||||
OUTPUT = sample_c();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_depth_copy
|
||||
void ps_depth_copy()
|
||||
{
|
||||
gl_FragDepth = sample_c().r;
|
||||
OUTPUT = sample_c();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -96,126 +168,47 @@ void ps_downsample_copy()
|
||||
for (int xoff = 0; xoff < DownsampleFactor; xoff++)
|
||||
result += texelFetch(TextureSampler, coord + ivec2(xoff * StepMultiplier, yoff * StepMultiplier), 0);
|
||||
}
|
||||
SV_Target0 = result / Weight;
|
||||
o_col0 = result / Weight;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba8_16bits
|
||||
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
|
||||
void ps_convert_rgba8_16bits()
|
||||
#ifdef ps_convert_rgb5a1_16bits
|
||||
void ps_convert_rgb5a1_16bits()
|
||||
{
|
||||
highp uvec4 i = uvec4(sample_c() * vec4(255.5f, 255.5f, 255.5f, 255.5f));
|
||||
|
||||
SV_Target1 = ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8);
|
||||
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
|
||||
OUTPUT = rgb5a1_to_uint(sample_c());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_float32_32bits
|
||||
void ps_convert_float32_32bits()
|
||||
#ifdef ps_convert_depth32_32bits
|
||||
void ps_convert_depth32_32bits()
|
||||
{
|
||||
// Convert a GL_FLOAT32 depth texture into a 32 bits UINT texture
|
||||
SV_Target1 = uint(exp2(32.0f) * sample_c().r);
|
||||
OUTPUT = depth_to_uint(sample_c());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_float32_rgba8
|
||||
void ps_convert_float32_rgba8()
|
||||
#ifdef ps_convert_depth32_rgba8
|
||||
void ps_convert_depth32_rgba8()
|
||||
{
|
||||
// Convert a GL_FLOAT32 depth texture into a RGBA color texture
|
||||
uint d = uint(sample_c().r * exp2(32.0f));
|
||||
SV_Target0 = vec4(uvec4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24))) / vec4(255.0);
|
||||
OUTPUT = depth32_to_rgba8(sample_c());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_float16_rgb5a1
|
||||
void ps_convert_float16_rgb5a1()
|
||||
#ifdef ps_convert_depth16_rgb5a1
|
||||
void ps_convert_depth16_rgb5a1()
|
||||
{
|
||||
// Convert a GL_FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture
|
||||
uint d = uint(sample_c().r * exp2(32.0f));
|
||||
SV_Target0 = vec4(uvec4(d << 3, d >> 2, d >> 7, d >> 8) & uvec4(0xf8, 0xf8, 0xf8, 0x80)) / 255.0f;
|
||||
OUTPUT = depth16_to_rgb5a1(sample_c());
|
||||
}
|
||||
#endif
|
||||
|
||||
float rgba8_to_depth32(vec4 unorm)
|
||||
{
|
||||
uvec4 c = uvec4(unorm * vec4(255.5f));
|
||||
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float rgba8_to_depth24(vec4 unorm)
|
||||
{
|
||||
uvec3 c = uvec3(unorm.rgb * vec3(255.5f));
|
||||
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float rgba8_to_depth16(vec4 unorm)
|
||||
{
|
||||
uvec2 c = uvec2(unorm.rg * vec2(255.5f));
|
||||
return float(c.r | (c.g << 8)) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float rgb5a1_to_depth16(vec4 unorm)
|
||||
{
|
||||
uvec4 c = uvec4(unorm * vec4(255.5f));
|
||||
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
#ifdef ps_convert_float32_depth_to_color
|
||||
void ps_convert_float32_depth_to_color()
|
||||
{
|
||||
SV_Target0 = sample_c().r;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_float32_color_to_depth
|
||||
void ps_convert_float32_color_to_depth()
|
||||
{
|
||||
gl_FragDepth = sample_c().r;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_float32_float24
|
||||
void ps_convert_float32_float24()
|
||||
#ifdef ps_convert_depth32_depth24
|
||||
void ps_convert_depth32_depth24()
|
||||
{
|
||||
// Truncates depth value to 24bits
|
||||
uint d = uint(sample_c().r * exp2(32.0f)) & 0xFFFFFFu;
|
||||
gl_FragDepth = float(d) * exp2(-32.0f);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba8_float32
|
||||
void ps_convert_rgba8_float32()
|
||||
{
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
gl_FragDepth = rgba8_to_depth32(sample_c());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba8_float24
|
||||
void ps_convert_rgba8_float24()
|
||||
{
|
||||
// Same as above but without the alpha channel (24 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
gl_FragDepth = rgba8_to_depth24(sample_c());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba8_float16
|
||||
void ps_convert_rgba8_float16()
|
||||
{
|
||||
// Same as above but without the A/B channels (16 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
gl_FragDepth = rgba8_to_depth16(sample_c());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgb5a1_float16
|
||||
void ps_convert_rgb5a1_float16()
|
||||
{
|
||||
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
|
||||
gl_FragDepth = rgb5a1_to_depth16(sample_c());
|
||||
OUTPUT = depth32_to_depth24(sample_c());
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -229,41 +222,55 @@ void ps_convert_rgb5a1_float16()
|
||||
float depthTR = CONVERT_FN(texelFetch(TextureSampler, coords.zy, 0)); \
|
||||
float depthBL = CONVERT_FN(texelFetch(TextureSampler, coords.xw, 0)); \
|
||||
float depthBR = CONVERT_FN(texelFetch(TextureSampler, coords.zw, 0)); \
|
||||
gl_FragDepth = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y);
|
||||
OUTPUT = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y);
|
||||
|
||||
#ifdef ps_convert_rgba8_float32_biln
|
||||
void ps_convert_rgba8_float32_biln()
|
||||
#ifdef ps_convert_rgba8_depth32
|
||||
void ps_convert_rgba8_depth32()
|
||||
{
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
#if HAS_BILN
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32);
|
||||
#else
|
||||
OUTPUT = rgba8_to_depth32(sample_c());
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba8_float24_biln
|
||||
void ps_convert_rgba8_float24_biln()
|
||||
#ifdef ps_convert_rgba8_depth24
|
||||
void ps_convert_rgba8_depth24()
|
||||
{
|
||||
// Same as above but without the alpha channel (24 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
#if HAS_BILN
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24);
|
||||
#else
|
||||
OUTPUT = rgba8_to_depth24(sample_c());
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba8_float16_biln
|
||||
void ps_convert_rgba8_float16_biln()
|
||||
#ifdef ps_convert_rgba8_depth16
|
||||
void ps_convert_rgba8_depth16()
|
||||
{
|
||||
// Same as above but without the A/B channels (16 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
#if HAS_BILN
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16);
|
||||
#else
|
||||
OUTPUT = rgba8_to_depth16(sample_c());
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgb5a1_float16_biln
|
||||
void ps_convert_rgb5a1_float16_biln()
|
||||
#ifdef ps_convert_rgb5a1_depth16
|
||||
void ps_convert_rgb5a1_depth16()
|
||||
{
|
||||
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
|
||||
#if HAS_BILN
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16);
|
||||
#else
|
||||
OUTPUT = rgb5a1_to_depth16(sample_c());
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -373,7 +380,7 @@ void ps_convert_rgb5a1_8i()
|
||||
uint red = (denorm_c.r >> 3) & 0x1Fu;
|
||||
uint green = (denorm_c.g >> 3) & 0x1Fu;
|
||||
|
||||
SV_Target0 = vec4(float(((green << 5) | red) & 0xFFu) / 255.0f);
|
||||
o_col0 = vec4(float(((green << 5) | red) & 0xFFu) / 255.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -381,7 +388,7 @@ void ps_convert_rgb5a1_8i()
|
||||
uint blue = (denorm_c.b >> 3) & 0x1Fu;
|
||||
uint alpha = denorm_c.a & 0x80u;
|
||||
|
||||
SV_Target0 = vec4(float((alpha | (blue << 2) | (green >> 3)) & 0xFFu) / 255.0f);
|
||||
o_col0 = vec4(float((alpha | (blue << 2) | (green >> 3)) & 0xFFu) / 255.0f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -430,7 +437,7 @@ void ps_convert_rgba_8i()
|
||||
vec4 pixel = texelFetch(TextureSampler, ivec2(coord), 0);
|
||||
vec2 sel0 = (pos.y & 2u) == 0u ? pixel.rb : pixel.ga;
|
||||
float sel1 = (pos.x & 8u) == 0u ? sel0.x : sel0.y;
|
||||
SV_Target0 = vec4(sel1);
|
||||
o_col0 = vec4(sel1);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -438,7 +445,7 @@ void ps_convert_rgba_8i()
|
||||
void ps_filter_transparency()
|
||||
{
|
||||
vec4 c = sample_c();
|
||||
SV_Target0 = vec4(c.rgb, 1.0);
|
||||
o_col0 = vec4(c.rgb, 1.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -486,7 +493,7 @@ void ps_datm0_rta_correction()
|
||||
void ps_rta_correction()
|
||||
{
|
||||
vec4 value = sample_c();
|
||||
SV_Target0 = vec4(value.rgb, value.a / (128.25f / 255.0f));
|
||||
o_col0 = vec4(value.rgb, value.a / (128.25f / 255.0f));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -494,7 +501,7 @@ void ps_rta_correction()
|
||||
void ps_rta_decorrection()
|
||||
{
|
||||
vec4 value = sample_c();
|
||||
SV_Target0 = vec4(value.rgb, value.a * (128.25f / 255.0f));
|
||||
o_col0 = vec4(value.rgb, value.a * (128.25f / 255.0f));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -502,7 +509,7 @@ void ps_rta_decorrection()
|
||||
void ps_colclip_init()
|
||||
{
|
||||
vec4 value = sample_c();
|
||||
SV_Target0 = vec4(round(value.rgb * 255.0f) / 65535.0f, value.a);
|
||||
o_col0 = vec4(round(value.rgb * 255.0f) / 65535.0f, value.a);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -510,7 +517,7 @@ void ps_colclip_init()
|
||||
void ps_colclip_resolve()
|
||||
{
|
||||
vec4 value = sample_c();
|
||||
SV_Target0 = vec4(vec3(uvec3(value.rgb * 65535.0f) & 255u) / 255.0f, value.a);
|
||||
o_col0 = vec4(vec3(uvec3(value.rgb * 65535.0f) & 255u) / 255.0f, value.a);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -525,7 +532,7 @@ void ps_convert_clut_4()
|
||||
uvec2 pos = uvec2(index % 8u, index / 8u);
|
||||
|
||||
ivec2 final = ivec2(floor(vec2(offset.xy + pos) * vec2(scale)));
|
||||
SV_Target0 = texelFetch(TextureSampler, final, 0);
|
||||
o_col0 = texelFetch(TextureSampler, final, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -545,7 +552,7 @@ void ps_convert_clut_8()
|
||||
pos.y = ((index / 32u) * 2u) + (subgroup % 2u);
|
||||
|
||||
ivec2 final = ivec2(floor(vec2(offset.xy + pos) * vec2(scale)));
|
||||
SV_Target0 = texelFetch(TextureSampler, final, 0);
|
||||
o_col0 = texelFetch(TextureSampler, final, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -600,31 +607,31 @@ void ps_yuv()
|
||||
break;
|
||||
}
|
||||
|
||||
SV_Target0 = o;
|
||||
o_col0 = o;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(ps_stencil_image_init_0) || defined(ps_stencil_image_init_1) || defined(ps_stencil_image_init_2) || defined(ps_stencil_image_init_3)
|
||||
#if defined(ps_primid_image_init_0) || defined(ps_primid_image_init_1) || defined(ps_primid_image_init_2) || defined(ps_primid_image_init_3)
|
||||
|
||||
void main()
|
||||
{
|
||||
SV_Target0 = vec4(0x7FFFFFFF);
|
||||
o_col0 = vec4(0x7FFFFFFF);
|
||||
|
||||
#ifdef ps_stencil_image_init_0
|
||||
#ifdef ps_primid_image_init_0
|
||||
if((127.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass)
|
||||
SV_Target0 = vec4(-1);
|
||||
o_col0 = vec4(-1);
|
||||
#endif
|
||||
#ifdef ps_stencil_image_init_1
|
||||
#ifdef ps_primid_image_init_1
|
||||
if(sample_c().a < (127.5f / 255.0f)) // >= 0x80 pass
|
||||
SV_Target0 = vec4(-1);
|
||||
o_col0 = vec4(-1);
|
||||
#endif
|
||||
#ifdef ps_stencil_image_init_2
|
||||
#ifdef ps_primid_image_init_2
|
||||
if((254.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass)
|
||||
SV_Target0 = vec4(-1);
|
||||
o_col0 = vec4(-1);
|
||||
#endif
|
||||
#ifdef ps_stencil_image_init_3
|
||||
#ifdef ps_primid_image_init_3
|
||||
if(sample_c().a < (254.5f / 255.0f)) // >= 0x80 pass
|
||||
SV_Target0 = vec4(-1);
|
||||
o_col0 = vec4(-1);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
#define NEEDS_DEPTH_FOR_ZTST (PS_ZTST == ZTST_GEQUAL || PS_ZTST == ZTST_GREATER)
|
||||
#define NEEDS_DEPTH_FOR_AA1 (PS_AA1 == PS_AA1_TRIANGLE_SW_Z)
|
||||
|
||||
#define NEEDS_RT (NEEDS_RT_EARLY || NEEDS_RT_FOR_AFAIL || (!PS_PRIMID_INIT && (PS_FBMASK || SW_BLEND_NEEDS_RT || SW_AD_TO_HW)) || PS_COLOR_FEEDBACK)
|
||||
#define NEEDS_RT (NEEDS_RT_EARLY || NEEDS_RT_FOR_AFAIL || (!PS_PRIMID_INIT && (PS_FBMASK || SW_BLEND_NEEDS_RT || SW_AD_TO_HW)))
|
||||
#define NEEDS_TEX (PS_TFX != 4)
|
||||
#define SW_DEPTH (NEEDS_DEPTH_FOR_AFAIL || NEEDS_DEPTH_FOR_ZTST || NEEDS_DEPTH_FOR_AA1)
|
||||
#define ZWRITE (SW_DEPTH || PS_ZCLAMP || PS_ZFLOOR)
|
||||
@@ -121,7 +121,7 @@ in SHADER
|
||||
#if defined(GL_EXT_shader_framebuffer_fetch)
|
||||
#undef TARGET_0_QUALIFIER
|
||||
#define TARGET_0_QUALIFIER inout
|
||||
#define LAST_FRAG_COLOR SV_Target0
|
||||
#define LAST_FRAG_COLOR o_col0
|
||||
#elif defined(GL_ARM_shader_framebuffer_fetch)
|
||||
#define LAST_FRAG_COLOR gl_LastFragColorARM
|
||||
#endif
|
||||
@@ -129,20 +129,20 @@ in SHADER
|
||||
|
||||
#if !PS_NO_COLOR && !PS_NO_COLOR1
|
||||
// Same buffer but 2 colors for dual source blending
|
||||
layout(location = 0, index = 0) TARGET_0_QUALIFIER vec4 SV_Target0;
|
||||
layout(location = 0, index = 1) out vec4 SV_Target1;
|
||||
layout(location = 0, index = 0) TARGET_0_QUALIFIER vec4 o_col0;
|
||||
layout(location = 0, index = 1) out vec4 o_col1;
|
||||
#elif !PS_NO_COLOR
|
||||
layout(location = 0) TARGET_0_QUALIFIER vec4 SV_Target0;
|
||||
layout(location = 0) TARGET_0_QUALIFIER vec4 o_col0;
|
||||
#endif
|
||||
|
||||
// Depth feedback mode 2 is for depth as color.
|
||||
// Use FB fetch for the feedback if it's available.
|
||||
#if SW_DEPTH && PS_NO_COLOR1 && (DEPTH_FEEDBACK_SUPPORT == 2)
|
||||
#if HAS_FRAMEBUFFER_FETCH
|
||||
layout(location = 1) inout float SV_Target1;
|
||||
#else
|
||||
layout(location = 1) out float SV_Target1;
|
||||
#endif
|
||||
#if HAS_FRAMEBUFFER_FETCH
|
||||
layout(location = 1) inout float o_col1;
|
||||
#else
|
||||
layout(location = 1) out float o_col1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if NEEDS_TEX
|
||||
@@ -180,14 +180,14 @@ vec4 sample_from_rt()
|
||||
#endif
|
||||
}
|
||||
|
||||
vec4 sample_from_depth()
|
||||
float sample_from_depth()
|
||||
{
|
||||
#if !SW_DEPTH
|
||||
return vec4(0.0);
|
||||
return 0.0f;
|
||||
#elif HAS_FRAMEBUFFER_FETCH && (DEPTH_FEEDBACK_SUPPORT == 2)
|
||||
return SV_Target1;
|
||||
return o_col1;
|
||||
#else
|
||||
return texelFetch(DepthSampler, ivec2(gl_FragCoord.xy), 0);
|
||||
return texelFetch(DepthSampler, ivec2(gl_FragCoord.xy), 0).r;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -621,13 +621,13 @@ vec4 sample_depth(vec2 st)
|
||||
|
||||
|
||||
#elif PS_DEPTH_FMT == 1
|
||||
// Based on ps_convert_float32_rgba8 of convert
|
||||
// Based on ps_convert_depth32_rgba8 of convert
|
||||
// Convert a GL_FLOAT32 depth texture into a RGBA color texture
|
||||
uint d = uint(fetch_c(uv).r * exp2(32.0f));
|
||||
t = vec4(uvec4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24)));
|
||||
|
||||
#elif PS_DEPTH_FMT == 2
|
||||
// Based on ps_convert_float16_rgb5a1 of convert
|
||||
// Based on ps_convert_depth16_rgb5a1 of convert
|
||||
// Convert a GL_FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture
|
||||
uint d = uint(fetch_c(uv).r * exp2(32.0f));
|
||||
t = vec4(uvec4((d & 0x1Fu), ((d >> 5) & 0x1Fu), ((d >> 10) & 0x1Fu), (d >> 15) & 0x01u)) * vec4(8.0f, 8.0f, 8.0f, 128.0f);
|
||||
@@ -1193,10 +1193,10 @@ void ps_main()
|
||||
#endif
|
||||
|
||||
#if PS_ZTST == ZTST_GEQUAL
|
||||
if (input_z < sample_from_depth().r)
|
||||
if (input_z < sample_from_depth())
|
||||
discard;
|
||||
#elif PS_ZTST == ZTST_GREATER
|
||||
if (input_z <= sample_from_depth().r)
|
||||
if (input_z <= sample_from_depth())
|
||||
discard;
|
||||
#endif
|
||||
|
||||
@@ -1264,7 +1264,7 @@ void ps_main()
|
||||
|
||||
bool atst_pass = atst(C);
|
||||
|
||||
#if PS_AFAIL == AFAIL_KEEP
|
||||
#if PS_ATST != PS_ATST_NONE && PS_AFAIL == AFAIL_KEEP
|
||||
if (!atst_pass)
|
||||
discard;
|
||||
#endif
|
||||
@@ -1293,12 +1293,12 @@ void ps_main()
|
||||
#if PS_DATE == 1
|
||||
// DATM == 0
|
||||
// Pixel with alpha equal to 1 will failed (128-255)
|
||||
SV_Target0 = (C.a > 127.5f) ? vec4(gl_PrimitiveID) : vec4(0x7FFFFFFF);
|
||||
o_col0 = (C.a > 127.5f) ? vec4(gl_PrimitiveID) : vec4(0x7FFFFFFF);
|
||||
return;
|
||||
#elif PS_DATE == 2
|
||||
// DATM == 1
|
||||
// Pixel with alpha equal to 0 will failed (0-127)
|
||||
SV_Target0 = (C.a < 127.5f) ? vec4(gl_PrimitiveID) : vec4(0x7FFFFFFF);
|
||||
o_col0 = (C.a < 127.5f) ? vec4(gl_PrimitiveID) : vec4(0x7FFFFFFF);
|
||||
return;
|
||||
#endif
|
||||
|
||||
@@ -1372,7 +1372,7 @@ void ps_main()
|
||||
// Alpha test with feedback
|
||||
#if PS_AFAIL == AFAIL_FB_ONLY
|
||||
if (!atst_pass)
|
||||
input_z = sample_from_depth().r;
|
||||
input_z = sample_from_depth();
|
||||
#elif PS_AFAIL == AFAIL_ZB_ONLY
|
||||
if (!atst_pass)
|
||||
C = sample_from_rt();
|
||||
@@ -1381,17 +1381,17 @@ void ps_main()
|
||||
{
|
||||
C.a = sample_from_rt().a;
|
||||
#if PS_AFAIL == AFAIL_RGB_ONLY_SW_Z
|
||||
input_z = sample_from_depth().r;
|
||||
input_z = sample_from_depth();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// Warning: do not write SV_Target0 until the end since the value might be needed for
|
||||
// Warning: do not write o_col0 until the end since the value might be needed for
|
||||
// FB fetch in sample_from_rt().
|
||||
SV_Target0 = C;
|
||||
o_col0 = C;
|
||||
|
||||
#if !PS_NO_COLOR1
|
||||
SV_Target1 = alpha_blend;
|
||||
o_col1 = alpha_blend;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1401,16 +1401,17 @@ void ps_main()
|
||||
|
||||
#if PS_AA1 == PS_AA1_TRIANGLE_SW_Z
|
||||
if (!bool(PSin.interior))
|
||||
input_z = sample_from_depth().r; // No depth update for triangle edges.
|
||||
input_z = sample_from_depth(); // No depth update for triangle edges.
|
||||
#endif
|
||||
|
||||
// Writing back depth
|
||||
#if ZWRITE
|
||||
#if SW_DEPTH && PS_NO_COLOR1 && (DEPTH_FEEDBACK_SUPPORT == 2)
|
||||
// Depth as color write. For depth as color feedback we write to both
|
||||
// color copy and real depth to avoid having to copy back to real depth.
|
||||
// Warning: do not write SV_Target1 until the end since the value might
|
||||
// Warning: do not write o_col1 until the end since the value might
|
||||
// be needed for FB fetch in sample_from_depth().
|
||||
SV_Target1 = input_z;
|
||||
o_col1 = input_z;
|
||||
#endif
|
||||
// Standard depth write.
|
||||
gl_FragDepth = input_z;
|
||||
|
||||
@@ -83,7 +83,13 @@ void vs_main()
|
||||
// example: 133.0625 (133 + 1/16) should start from line 134, ceil(133.0625 - 0.05) still above 133
|
||||
gl_Position.xy = vec2(i_p) - vec2(0.05f, 0.05f);
|
||||
gl_Position.xy = gl_Position.xy * VertexScale - VertexOffset;
|
||||
gl_Position.z = float(z) * exp_min32;
|
||||
|
||||
#if HAS_CLIP_CONTROL
|
||||
gl_Position.z = float(z) * exp_min32;
|
||||
#else
|
||||
gl_Position.z = (float(z) * exp_min32) * 2.0f - 1.0f;
|
||||
#endif
|
||||
|
||||
gl_Position.w = 1.0f;
|
||||
|
||||
texture_coord();
|
||||
@@ -160,7 +166,13 @@ ProcessedVertex load_vertex(uint index)
|
||||
uint z = min(i_z, MaxDepth);
|
||||
vtx.p.xy = vec2(i_p) - vec2(0.05f, 0.05f);
|
||||
vtx.p.xy = vtx.p.xy * VertexScale - VertexOffset;
|
||||
vtx.p.z = float(z) * exp_min32;
|
||||
|
||||
#if HAS_CLIP_CONTROL
|
||||
vtx.p.z = float(z) * exp_min32;
|
||||
#else
|
||||
vtx.p.z = (float(z) * exp_min32) * 2.0f - 1.0f;
|
||||
#endif
|
||||
|
||||
vtx.p.w = 1.0f;
|
||||
|
||||
vec2 uv = vec2(i_uv) - TextureOffset;
|
||||
|
||||
@@ -20,45 +20,127 @@ void main()
|
||||
|
||||
layout(location = 0) in vec2 v_tex;
|
||||
|
||||
#if defined(ps_convert_rgba8_16bits) || defined(ps_convert_float32_32bits)
|
||||
layout(location = 0) out uint o_col0;
|
||||
#elif defined(ps_convert_float32_depth_to_color)
|
||||
layout(location = 0) out float o_col0;
|
||||
#elif !defined(ps_datm1) && \
|
||||
!defined(ps_datm0) && \
|
||||
!defined(ps_datm1_rta_correction) && \
|
||||
!defined(ps_datm0_rta_correction) && \
|
||||
!defined(ps_convert_rgba8_float32) && \
|
||||
!defined(ps_convert_rgba8_float24) && \
|
||||
!defined(ps_convert_rgba8_float16) && \
|
||||
!defined(ps_convert_rgb5a1_float16) && \
|
||||
!defined(ps_convert_rgba8_float32_biln) && \
|
||||
!defined(ps_convert_rgba8_float24_biln) && \
|
||||
!defined(ps_convert_rgba8_float16_biln) && \
|
||||
!defined(ps_convert_rgb5a1_float16_biln) && \
|
||||
!defined(ps_convert_float32_float24) && \
|
||||
!defined(ps_depth_copy)
|
||||
layout(location = 0) out vec4 o_col0;
|
||||
#if HAS_INTEGER_OUTPUT
|
||||
layout(location = 0) out uint o_col0;
|
||||
#define OUTPUT o_col0
|
||||
#elif HAS_DEPTH_OUTPUT
|
||||
out float gl_FragDepth;
|
||||
#define OUTPUT gl_FragDepth
|
||||
#elif HAS_FLOAT32_OUTPUT
|
||||
layout(location = 0) out float o_col0;
|
||||
#define OUTPUT o_col0
|
||||
#elif HAS_STENCIL_OUTPUT
|
||||
#else
|
||||
layout(location = 0) out vec4 o_col0;
|
||||
#define OUTPUT o_col0
|
||||
#endif
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D samp0;
|
||||
|
||||
#if HAS_FLOAT32_INPUT
|
||||
|
||||
float sample_c(vec2 uv)
|
||||
{
|
||||
return texture(samp0, uv).r;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
vec4 sample_c(vec2 uv)
|
||||
{
|
||||
return texture(samp0, uv);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
uint rgba8_to_uint(vec4 c)
|
||||
{
|
||||
uvec4 i = uvec4(c * 255.5f) & 0xFFu;
|
||||
return i.r | (i.g << 8) | (i.b << 16) | (i.a << 24);
|
||||
}
|
||||
|
||||
uint rgb5a1_to_uint(vec4 c)
|
||||
{
|
||||
uvec4 i = uvec4(c * 255.5f) & uvec4(0xF8u, 0xF8u, 0xF8u, 0x80u);
|
||||
return (i.r >> 3) | (i.g << 2) | (i.b << 7) | (i.a << 8);
|
||||
}
|
||||
|
||||
uint depth_to_uint(float d)
|
||||
{
|
||||
return uint(d * exp2(32.0f));
|
||||
}
|
||||
|
||||
vec4 uint_to_rgba8(uint i)
|
||||
{
|
||||
return vec4((i & 0xFFu), ((i >> 8) & 0xFFu), ((i >> 16) & 0xFFu), ((i >> 24) & 0xFFu)) / 255.0f;
|
||||
}
|
||||
|
||||
vec4 uint_to_rgb5a1(uint i)
|
||||
{
|
||||
return vec4(uvec4(i << 3, i >> 2, i >> 7, i >> 8) & uvec4(0xF8u, 0xF8u, 0xF8u, 0x80u)) / 255.0f;
|
||||
}
|
||||
|
||||
float uint_to_depth32(uint i)
|
||||
{
|
||||
return float(i) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float uint_to_depth24(uint i)
|
||||
{
|
||||
return float(i & 0xFFFFFFu) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float uint_to_depth16(uint i)
|
||||
{
|
||||
return float(i & 0xFFFFu) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float rgba8_to_depth32(vec4 val)
|
||||
{
|
||||
return uint_to_depth32(rgba8_to_uint(val));
|
||||
}
|
||||
|
||||
float rgba8_to_depth24(vec4 val)
|
||||
{
|
||||
return uint_to_depth24(rgba8_to_uint(val));
|
||||
}
|
||||
|
||||
float rgba8_to_depth16(vec4 val)
|
||||
{
|
||||
return uint_to_depth16(rgba8_to_uint(val));
|
||||
}
|
||||
|
||||
float rgb5a1_to_depth16(vec4 val)
|
||||
{
|
||||
return uint_to_depth16(rgb5a1_to_uint(val));
|
||||
}
|
||||
|
||||
vec4 depth32_to_rgba8(float d)
|
||||
{
|
||||
return uint_to_rgba8(depth_to_uint(d));
|
||||
}
|
||||
|
||||
vec4 depth16_to_rgb5a1(float d)
|
||||
{
|
||||
return uint_to_rgb5a1(depth_to_uint(d));
|
||||
}
|
||||
|
||||
float depth32_to_depth24(float d)
|
||||
{
|
||||
return uint_to_depth24(depth_to_uint(d));
|
||||
}
|
||||
|
||||
#ifdef ps_copy
|
||||
void ps_copy()
|
||||
{
|
||||
o_col0 = sample_c(v_tex);
|
||||
OUTPUT = sample_c(v_tex);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_depth_copy
|
||||
void ps_depth_copy()
|
||||
{
|
||||
gl_FragDepth = sample_c(v_tex).r;
|
||||
OUTPUT = sample_c(v_tex);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -83,7 +165,7 @@ void ps_downsample_copy()
|
||||
result += texelFetch(samp0, coord + ivec2(xoff * step_multiplier, yoff * step_multiplier), 0);
|
||||
}
|
||||
}
|
||||
o_col0 = result / Weight;
|
||||
OUTPUT = result / Weight;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -91,17 +173,15 @@ void ps_downsample_copy()
|
||||
void ps_filter_transparency()
|
||||
{
|
||||
vec4 c = sample_c(v_tex);
|
||||
o_col0 = vec4(c.rgb, 1.0);
|
||||
OUTPUT = vec4(c.rgb, 1.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba8_16bits
|
||||
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
|
||||
void ps_convert_rgba8_16bits()
|
||||
#ifdef ps_convert_rgb5a1_16bits
|
||||
void ps_convert_rgb5a1_16bits()
|
||||
{
|
||||
uvec4 i = uvec4(sample_c(v_tex) * vec4(255.5f, 255.5f, 255.5f, 255.5f));
|
||||
|
||||
o_col0 = ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8);
|
||||
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
|
||||
OUTPUT = rgb5a1_to_uint(sample_c(v_tex));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -141,7 +221,7 @@ void ps_datm0_rta_correction()
|
||||
void ps_rta_correction()
|
||||
{
|
||||
vec4 value = sample_c(v_tex);
|
||||
o_col0 = vec4(value.rgb, value.a / (128.25f / 255.0f));
|
||||
OUTPUT = vec4(value.rgb, value.a / (128.25f / 255.0f));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -149,7 +229,7 @@ void ps_rta_correction()
|
||||
void ps_rta_decorrection()
|
||||
{
|
||||
vec4 value = sample_c(v_tex);
|
||||
o_col0 = vec4(value.rgb, value.a * (128.25f / 255.0f));
|
||||
OUTPUT = vec4(value.rgb, value.a * (128.25f / 255.0f));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -157,7 +237,7 @@ void ps_rta_decorrection()
|
||||
void ps_colclip_init()
|
||||
{
|
||||
vec4 value = sample_c(v_tex);
|
||||
o_col0 = vec4(roundEven(value.rgb * 255.0f) / 65535.0f, value.a);
|
||||
OUTPUT = vec4(roundEven(value.rgb * 255.0f) / 65535.0f, value.a);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -165,116 +245,39 @@ void ps_colclip_init()
|
||||
void ps_colclip_resolve()
|
||||
{
|
||||
vec4 value = sample_c(v_tex);
|
||||
o_col0 = vec4(vec3(uvec3(value.rgb * 65535.5f) & 255u) / 255.0f, value.a);
|
||||
OUTPUT = vec4(vec3(uvec3(value.rgb * 65535.5f) & 255u) / 255.0f, value.a);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_float32_depth_to_color
|
||||
void ps_convert_float32_depth_to_color()
|
||||
{
|
||||
o_col0 = sample_c(v_tex).r;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_float32_color_to_depth
|
||||
void ps_convert_float32_color_to_depth()
|
||||
{
|
||||
gl_FragDepth = sample_c(v_tex).r;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_float32_32bits
|
||||
void ps_convert_float32_32bits()
|
||||
#ifdef ps_convert_depth32_32bits
|
||||
void ps_convert_depth32_32bits()
|
||||
{
|
||||
// Convert a vec32 depth texture into a 32 bits UINT texture
|
||||
o_col0 = uint(exp2(32.0f) * sample_c(v_tex).r);
|
||||
OUTPUT = depth_to_uint(sample_c(v_tex));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_float32_rgba8
|
||||
void ps_convert_float32_rgba8()
|
||||
#ifdef ps_convert_depth32_rgba8
|
||||
void ps_convert_depth32_rgba8()
|
||||
{
|
||||
// Convert a vec32 depth texture into a RGBA color texture
|
||||
uint d = uint(sample_c(v_tex).r * exp2(32.0f));
|
||||
o_col0 = vec4(uvec4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24))) / vec4(255.0);
|
||||
OUTPUT = depth32_to_rgba8(sample_c(v_tex));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_float16_rgb5a1
|
||||
void ps_convert_float16_rgb5a1()
|
||||
#ifdef ps_convert_depth16_rgb5a1
|
||||
void ps_convert_depth16_rgb5a1()
|
||||
{
|
||||
// Convert a vec32 (only 16 lsb) depth into a RGB5A1 color texture
|
||||
uint d = uint(sample_c(v_tex).r * exp2(32.0f));
|
||||
o_col0 = vec4(uvec4(d << 3, d >> 2, d >> 7, d >> 8) & uvec4(0xf8, 0xf8, 0xf8, 0x80)) / 255.0f;
|
||||
OUTPUT = depth16_to_rgb5a1(sample_c(v_tex));
|
||||
}
|
||||
#endif
|
||||
|
||||
float rgba8_to_depth32(vec4 unorm)
|
||||
{
|
||||
uvec4 c = uvec4(unorm * vec4(255.5f));
|
||||
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float rgba8_to_depth24(vec4 unorm)
|
||||
{
|
||||
uvec3 c = uvec3(unorm.rgb * vec3(255.5f));
|
||||
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float rgba8_to_depth16(vec4 unorm)
|
||||
{
|
||||
uvec2 c = uvec2(unorm.rg * vec2(255.5f));
|
||||
return float(c.r | (c.g << 8)) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
float rgb5a1_to_depth16(vec4 unorm)
|
||||
{
|
||||
uvec4 c = uvec4(unorm * vec4(255.5f));
|
||||
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
#ifdef ps_convert_float32_float24
|
||||
void ps_convert_float32_float24()
|
||||
#ifdef ps_convert_depth32_depth24
|
||||
void ps_convert_depth32_depth24()
|
||||
{
|
||||
// Truncates depth value to 24bits
|
||||
uint d = uint(sample_c(v_tex).r * exp2(32.0f)) & 0xFFFFFFu;
|
||||
gl_FragDepth = float(d) * exp2(-32.0f);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba8_float32
|
||||
void ps_convert_rgba8_float32()
|
||||
{
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
gl_FragDepth = rgba8_to_depth32(sample_c(v_tex));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba8_float24
|
||||
void ps_convert_rgba8_float24()
|
||||
{
|
||||
// Same as above but without the alpha channel (24 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
gl_FragDepth = rgba8_to_depth24(sample_c(v_tex));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba8_float16
|
||||
void ps_convert_rgba8_float16()
|
||||
{
|
||||
// Same as above but without the A/B channels (16 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
gl_FragDepth = rgba8_to_depth16(sample_c(v_tex));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgb5a1_float16
|
||||
void ps_convert_rgb5a1_float16()
|
||||
{
|
||||
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
|
||||
gl_FragDepth = rgb5a1_to_depth16(sample_c(v_tex));
|
||||
OUTPUT = depth32_to_depth24(sample_c(v_tex));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -288,41 +291,53 @@ void ps_convert_rgb5a1_float16()
|
||||
float depthTR = CONVERT_FN(texelFetch(samp0, coords.zy, 0)); \
|
||||
float depthBL = CONVERT_FN(texelFetch(samp0, coords.xw, 0)); \
|
||||
float depthBR = CONVERT_FN(texelFetch(samp0, coords.zw, 0)); \
|
||||
gl_FragDepth = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y);
|
||||
OUTPUT = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y);
|
||||
|
||||
#ifdef ps_convert_rgba8_float32_biln
|
||||
void ps_convert_rgba8_float32_biln()
|
||||
#ifdef ps_convert_rgba8_depth32
|
||||
void ps_convert_rgba8_depth32()
|
||||
{
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
#if HAS_BILN
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32);
|
||||
#else
|
||||
OUTPUT = rgba8_to_depth32(sample_c(v_tex));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba8_float24_biln
|
||||
void ps_convert_rgba8_float24_biln()
|
||||
#ifdef ps_convert_rgba8_depth24
|
||||
void ps_convert_rgba8_depth24()
|
||||
{
|
||||
// Same as above but without the alpha channel (24 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
#if HAS_BILN
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24);
|
||||
#else
|
||||
OUTPUT = rgba8_to_depth24(sample_c(v_tex));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba8_float16_biln
|
||||
void ps_convert_rgba8_float16_biln()
|
||||
#ifdef ps_convert_rgba8_depth16
|
||||
void ps_convert_rgba8_depth16()
|
||||
{
|
||||
// Same as above but without the A/B channels (16 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
#if HAS_BILN
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16);
|
||||
#else
|
||||
OUTPUT = rgba8_to_depth16(sample_c(v_tex));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgb5a1_float16_biln
|
||||
void ps_convert_rgb5a1_float16_biln()
|
||||
#ifdef ps_convert_rgb5a1_depth16
|
||||
void ps_convert_rgb5a1_depth16()
|
||||
{
|
||||
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
|
||||
#if HAS_BILN
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16);
|
||||
#else
|
||||
OUTPUT = rgb5a1_to_depth16(sample_c(v_tex));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -609,25 +624,25 @@ void ps_yuv()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(ps_stencil_image_init_0) || defined(ps_stencil_image_init_1) || defined(ps_stencil_image_init_2) || defined(ps_stencil_image_init_3)
|
||||
#if defined(ps_primid_image_init_0) || defined(ps_primid_image_init_1) || defined(ps_primid_image_init_2) || defined(ps_primid_image_init_3)
|
||||
|
||||
void main()
|
||||
{
|
||||
o_col0 = vec4(0x7FFFFFFF);
|
||||
|
||||
#ifdef ps_stencil_image_init_0
|
||||
#ifdef ps_primid_image_init_0
|
||||
if((127.5f / 255.0f) < sample_c(v_tex).a) // < 0x80 pass (== 0x80 should not pass)
|
||||
o_col0 = vec4(-1);
|
||||
#endif
|
||||
#ifdef ps_stencil_image_init_1
|
||||
#ifdef ps_primid_image_init_1
|
||||
if(sample_c(v_tex).a < (127.5f / 255.0f)) // >= 0x80 pass
|
||||
o_col0 = vec4(-1);
|
||||
#endif
|
||||
#ifdef ps_stencil_image_init_2
|
||||
#ifdef ps_primid_image_init_2
|
||||
if((254.5f / 255.0f) < sample_c(v_tex).a) // < 0x80 pass (== 0x80 should not pass)
|
||||
o_col0 = vec4(-1);
|
||||
#endif
|
||||
#ifdef ps_stencil_image_init_3
|
||||
#ifdef ps_primid_image_init_3
|
||||
if(sample_c(v_tex).a < (254.5f / 255.0f)) // >= 0x80 pass
|
||||
o_col0 = vec4(-1);
|
||||
#endif
|
||||
|
||||
@@ -522,6 +522,12 @@ void main()
|
||||
#define PS_AA1_TRIANGLE_SW_Z 3
|
||||
#endif
|
||||
|
||||
#ifndef PS_ROV_DEPTH_NONE
|
||||
#define PS_ROV_DEPTH_NONE 0
|
||||
#define PS_ROV_DEPTH_READ_WRITE 1
|
||||
#define PS_ROV_DEPTH_READ_ONLY 2
|
||||
#endif
|
||||
|
||||
#ifndef PS_FST
|
||||
#define PS_FST 0
|
||||
#define PS_WMS 0
|
||||
@@ -574,6 +580,8 @@ void main()
|
||||
#define PS_NO_COLOR1 0
|
||||
#define PS_DATE 0
|
||||
#define PS_TEX_IS_FB 0
|
||||
#define PS_ROV_COLOR 0
|
||||
#define PS_ROV_DEPTH 0
|
||||
#endif
|
||||
|
||||
#define SW_BLEND (PS_BLEND_A || PS_BLEND_B || PS_BLEND_D)
|
||||
@@ -586,7 +594,13 @@ void main()
|
||||
|
||||
#define PS_FEEDBACK_LOOP_IS_NEEDED_RT (PS_TEX_IS_FB == 1 || AFAIL_NEEDS_RT || PS_FBMASK || SW_BLEND_NEEDS_RT || SW_AD_TO_HW || (PS_DATE >= 5))
|
||||
#define PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH (AFAIL_NEEDS_DEPTH || ZTST_NEEDS_DEPTH || AA1_NEEDS_DEPTH)
|
||||
#define ZWRITE (PS_ZCLAMP || PS_ZFLOOR || PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH)
|
||||
#define ZWRITE (PS_ZCLAMP || PS_ZFLOOR || SW_DEPTH || PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH)
|
||||
|
||||
#define PS_RETURN_COLOR_ROV (!PS_NO_COLOR && PS_ROV_COLOR)
|
||||
#define PS_RETURN_COLOR (!PS_NO_COLOR && !PS_ROV_COLOR)
|
||||
#define PS_RETURN_DEPTH_ROV (PS_ROV_DEPTH == PS_ROV_DEPTH_READ_WRITE)
|
||||
#define PS_RETURN_DEPTH (ZWRITE && !PS_ROV_DEPTH)
|
||||
#define PS_ROV_EARLYDEPTHSTENCIL (PS_ROV_COLOR && !PS_ROV_DEPTH && !ZWRITE)
|
||||
|
||||
#define NEEDS_TEX (PS_TFX != 4)
|
||||
|
||||
@@ -625,11 +639,27 @@ layout(location = 0) in VSOutput
|
||||
flat uint interior; // 1 for triangle interior; 0 for edge;
|
||||
} vsIn;
|
||||
|
||||
#if !PS_NO_COLOR && !PS_NO_COLOR1
|
||||
layout(location = 0, index = 0) out vec4 o_col0;
|
||||
layout(location = 0, index = 1) out vec4 o_col1;
|
||||
#elif !PS_NO_COLOR
|
||||
layout(location = 0) out vec4 o_col0;
|
||||
#if PS_RETURN_COLOR
|
||||
#if !PS_NO_COLOR1
|
||||
layout(location = 0, index = 0) out vec4 o_col0;
|
||||
layout(location = 0, index = 1) out vec4 o_col1;
|
||||
#elif !PS_NO_COLOR
|
||||
layout(location = 0) out vec4 o_col0;
|
||||
#endif
|
||||
#elif PS_RETURN_COLOR_ROV
|
||||
vec4 o_col0;
|
||||
#endif
|
||||
|
||||
#if PS_ROV_COLOR
|
||||
layout(set = 1, binding = 5, rgba8) uniform restrict coherent image2D RtImageRov;
|
||||
vec4 rov_rt_value;
|
||||
vec4 sample_from_rt() { return rov_rt_value; }
|
||||
#endif
|
||||
|
||||
#if PS_ROV_DEPTH
|
||||
layout(set = 1, binding = 6, r32f) uniform restrict coherent image2D DepthImageRov;
|
||||
float rov_depth_value;
|
||||
float sample_from_depth() { return rov_depth_value; }
|
||||
#endif
|
||||
|
||||
#if NEEDS_TEX
|
||||
@@ -639,27 +669,27 @@ layout(set = 1, binding = 1) uniform texture2D Palette;
|
||||
|
||||
#if PS_FEEDBACK_LOOP_IS_NEEDED_RT || PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH
|
||||
#if defined(DISABLE_TEXTURE_BARRIER) || defined(HAS_FEEDBACK_LOOP_LAYOUT)
|
||||
#if PS_FEEDBACK_LOOP_IS_NEEDED_RT
|
||||
#if (PS_FEEDBACK_LOOP_IS_NEEDED_RT && !PS_ROV_COLOR)
|
||||
layout(set = 1, binding = 2) uniform texture2D RtSampler;
|
||||
vec4 sample_from_rt() { return texelFetch(RtSampler, ivec2(gl_FragCoord.xy), 0); }
|
||||
#endif
|
||||
#if PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH
|
||||
#if (PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH && !PS_ROV_DEPTH)
|
||||
layout(set = 1, binding = 4) uniform texture2D DepthSampler;
|
||||
vec4 sample_from_depth() { return texelFetch(DepthSampler, ivec2(gl_FragCoord.xy), 0); }
|
||||
float sample_from_depth() { return texelFetch(DepthSampler, ivec2(gl_FragCoord.xy), 0).r; }
|
||||
#endif
|
||||
#else
|
||||
// Must consider each case separately since the input attachment indices must be consecutive.
|
||||
#if PS_FEEDBACK_LOOP_IS_NEEDED_RT && PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH
|
||||
#if (PS_FEEDBACK_LOOP_IS_NEEDED_RT && !PS_ROV_COLOR) && (PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH && !PS_ROV_DEPTH)
|
||||
layout(input_attachment_index = 0, set = 1, binding = 2) uniform subpassInput RtSampler;
|
||||
layout(input_attachment_index = 1, set = 1, binding = 4) uniform subpassInput DepthSampler;
|
||||
vec4 sample_from_rt() { return subpassLoad(RtSampler); }
|
||||
vec4 sample_from_depth() { return subpassLoad(DepthSampler); }
|
||||
#elif PS_FEEDBACK_LOOP_IS_NEEDED_RT
|
||||
float sample_from_depth() { return subpassLoad(DepthSampler).r; }
|
||||
#elif (PS_FEEDBACK_LOOP_IS_NEEDED_RT && !PS_ROV_COLOR)
|
||||
layout(input_attachment_index = 0, set = 1, binding = 2) uniform subpassInput RtSampler;
|
||||
vec4 sample_from_rt() { return subpassLoad(RtSampler); }
|
||||
#elif PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH
|
||||
#elif (PS_FEEDBACK_LOOP_IS_NEEDED_DEPTH && !PS_ROV_DEPTH)
|
||||
layout(input_attachment_index = 0, set = 1, binding = 4) uniform subpassInput DepthSampler;
|
||||
vec4 sample_from_depth() { return subpassLoad(DepthSampler); }
|
||||
float sample_from_depth() { return subpassLoad(DepthSampler).r; }
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
@@ -1114,7 +1144,7 @@ vec4 sample_depth(vec2 st, ivec2 pos)
|
||||
}
|
||||
#elif (PS_DEPTH_FMT == 1)
|
||||
{
|
||||
// Based on ps_convert_float32_rgba8 of convert
|
||||
// Based on ps_convert_depth32_rgba8 of convert
|
||||
|
||||
// Convert a vec32 depth texture into a RGBA color texture
|
||||
uint d = uint(fetch_c(uv).r * exp2(32.0f));
|
||||
@@ -1122,7 +1152,7 @@ vec4 sample_depth(vec2 st, ivec2 pos)
|
||||
}
|
||||
#elif (PS_DEPTH_FMT == 2)
|
||||
{
|
||||
// Based on ps_convert_float16_rgb5a1 of convert
|
||||
// Based on ps_convert_depth16_rgb5a1 of convert
|
||||
|
||||
// Convert a vec32 (only 16 lsb) depth into a RGB5A1 color texture
|
||||
uint d = uint(fetch_c(uv).r * exp2(32.0f));
|
||||
@@ -1604,7 +1634,7 @@ void ps_blend(inout vec4 Color, inout vec4 As_rgba)
|
||||
#elif PS_BLEND_MIX == 1
|
||||
Color.rgb = ((A - B) * C_clamped + D) - (124.0f/256.0f);
|
||||
#else
|
||||
Color.rgb = trunc((A - B) * C + D);
|
||||
Color.rgb = trunc((A - B) * C + D);
|
||||
#endif
|
||||
|
||||
#if PS_BLEND_HW == 1
|
||||
@@ -1678,6 +1708,20 @@ void ps_blend(inout vec4 Color, inout vec4 As_rgba)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PS_ROV_COLOR || PS_ROV_DEPTH
|
||||
layout(pixel_interlock_ordered) in;
|
||||
#endif
|
||||
|
||||
#if PS_ROV_EARLYDEPTHSTENCIL
|
||||
layout(early_fragment_tests) in;
|
||||
#endif
|
||||
|
||||
#if PS_ROV_COLOR || PS_ROV_DEPTH
|
||||
#define DISCARD rov_discard = true
|
||||
#else
|
||||
#define DISCARD discard
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
float input_z = gl_FragCoord.z;
|
||||
@@ -1687,18 +1731,34 @@ void main()
|
||||
input_z = floor(input_z * exp2(32.0f)) * exp2(-32.0f);
|
||||
#endif
|
||||
|
||||
#if PS_ROV_COLOR || PS_ROV_DEPTH
|
||||
beginInvocationInterlockARB();
|
||||
#endif
|
||||
|
||||
#if PS_ROV_COLOR
|
||||
rov_rt_value = imageLoad(RtImageRov, ivec2(gl_FragCoord.xy));
|
||||
#endif
|
||||
|
||||
#if PS_ROV_DEPTH
|
||||
rov_depth_value = imageLoad(DepthImageRov, ivec2(gl_FragCoord.xy)).r;
|
||||
#endif
|
||||
|
||||
#if PS_ROV_COLOR || PS_ROV_DEPTH
|
||||
bool rov_discard = gl_HelperInvocation;
|
||||
#endif
|
||||
|
||||
#if PS_ZTST == ZTST_GEQUAL
|
||||
if (input_z < sample_from_depth().r)
|
||||
discard;
|
||||
if (input_z < sample_from_depth())
|
||||
DISCARD;
|
||||
#elif PS_ZTST == ZTST_GREATER
|
||||
if (input_z <= sample_from_depth().r)
|
||||
discard;
|
||||
if (input_z <= sample_from_depth())
|
||||
DISCARD;
|
||||
#endif
|
||||
|
||||
#if PS_SCANMSK & 2
|
||||
// fail depth test on prohibited lines
|
||||
if ((int(gl_FragCoord.y) & 1) == (PS_SCANMSK & 1))
|
||||
discard;
|
||||
DISCARD;
|
||||
#endif
|
||||
#if PS_DATE >= 5
|
||||
|
||||
@@ -1726,7 +1786,7 @@ void main()
|
||||
#endif
|
||||
|
||||
if (bad) {
|
||||
discard;
|
||||
DISCARD;
|
||||
}
|
||||
|
||||
#endif // PS_DATE >= 5
|
||||
@@ -1737,7 +1797,7 @@ void main()
|
||||
// the bad alpha value so we must keep it.
|
||||
|
||||
if (gl_PrimitiveID > stencil_ceil) {
|
||||
discard;
|
||||
DISCARD;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1758,9 +1818,10 @@ void main()
|
||||
|
||||
bool atst_pass = atst(C);
|
||||
|
||||
#if PS_AFAIL == AFAIL_KEEP
|
||||
if (!atst_pass)
|
||||
discard;
|
||||
#if PS_ATST != PS_ATST_NONE && PS_AFAIL == AFAIL_KEEP
|
||||
if (!atst_pass) {
|
||||
DISCARD;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SW_AD_TO_HW
|
||||
@@ -1852,6 +1913,7 @@ void main()
|
||||
alpha_blend.a = float(atst_pass);
|
||||
#endif
|
||||
|
||||
// Output color scaling
|
||||
#if !PS_NO_COLOR
|
||||
#if PS_RTA_CORRECTION
|
||||
o_col0.a = C.a / 128.0f;
|
||||
@@ -1870,7 +1932,7 @@ void main()
|
||||
// Alpha test with feedback
|
||||
#if PS_AFAIL == AFAIL_FB_ONLY
|
||||
if (!atst_pass)
|
||||
input_z = sample_from_depth().r;
|
||||
input_z = sample_from_depth();
|
||||
#elif PS_AFAIL == AFAIL_ZB_ONLY
|
||||
if (!atst_pass)
|
||||
o_col0 = sample_from_rt();
|
||||
@@ -1879,7 +1941,7 @@ void main()
|
||||
{
|
||||
o_col0.a = sample_from_rt().a;
|
||||
#if PS_AFAIL == AFAIL_RGB_ONLY_SW_Z
|
||||
input_z = sample_from_depth().r;
|
||||
input_z = sample_from_depth();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@@ -1891,11 +1953,28 @@ void main()
|
||||
|
||||
#if PS_AA1 == PS_AA1_TRIANGLE_SW_Z
|
||||
if (!bool(vsIn.interior))
|
||||
input_z = sample_from_depth().r; // No depth update for triangle edges.
|
||||
input_z = sample_from_depth(); // No depth update for triangle edges.
|
||||
#endif
|
||||
|
||||
#if ZWRITE
|
||||
// Writing back color (result already written to o_col0 for non-ROV)
|
||||
#if PS_RETURN_COLOR_ROV
|
||||
bvec4 discard_channels = bvec4(uvec4(rov_discard) | uvec4(equal(FbMask, uvec4(0xFFu))));
|
||||
o_col0 = mix(o_col0, sample_from_rt(), discard_channels);
|
||||
|
||||
imageStore(RtImageRov, ivec2(gl_FragCoord.xy), o_col0);
|
||||
#endif
|
||||
|
||||
// Writing back depth
|
||||
#if PS_RETURN_DEPTH
|
||||
gl_FragDepth = input_z;
|
||||
#elif PS_RETURN_DEPTH_ROV
|
||||
input_z = rov_discard ? sample_from_depth() : input_z;
|
||||
|
||||
imageStore(DepthImageRov, ivec2(gl_FragCoord.xy), vec4(input_z, 0, 0, 1.0f));
|
||||
#endif
|
||||
|
||||
#if PS_ROV_COLOR || PS_ROV_DEPTH
|
||||
endInvocationInterlockARB();
|
||||
#endif
|
||||
#endif // PS_DATE
|
||||
}
|
||||
|
||||
@@ -300,8 +300,8 @@ else()
|
||||
if(CMAKE_INTERPROCEDURAL_OPTIMIZATION)
|
||||
message(WARNING
|
||||
"The CMAKE_INTERPROCEDURAL_OPTIMIZATION option is enabled but the "
|
||||
"CMAKE_POSITION_INDEPENDENT_CODE option is disabled. This has been "
|
||||
"found to result in broken builds on certain platforms.")
|
||||
"POSITION_INDEPENDENT_CODE option is disabled. This has been found "
|
||||
"to result in broken builds on certain platforms.")
|
||||
endif()
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE OFF)
|
||||
|
||||
@@ -22,6 +22,9 @@ find_package(Freetype 2.10 REQUIRED) # 2.10 is the first with COLRv0 support, wh
|
||||
find_package(plutovg 1.1.0 REQUIRED)
|
||||
find_package(plutosvg 0.0.7 REQUIRED)
|
||||
find_package(ryml REQUIRED)
|
||||
if (WIN32)
|
||||
find_package(DirectX-Headers 1.618.1 REQUIRED)
|
||||
endif()
|
||||
|
||||
if(USE_VULKAN)
|
||||
find_package(Shaderc REQUIRED)
|
||||
|
||||
+13
-3
@@ -98,14 +98,25 @@ __ri void Log::WriteToConsole(LOGLEVEL level, ConsoleColors color, std::string_v
|
||||
|
||||
static constexpr size_t BUFFER_SIZE = 512;
|
||||
|
||||
#ifdef _WIN32
|
||||
constexpr bool supports_color_codes = true;
|
||||
#else
|
||||
const int fd = (level <= LOGLEVEL_WARNING) ? STDERR_FILENO : STDOUT_FILENO;
|
||||
const bool supports_color_codes = static_cast<bool>(isatty(fd));
|
||||
#endif
|
||||
|
||||
SmallStackString<BUFFER_SIZE> buffer;
|
||||
buffer.reserve(static_cast<u32>(32 + message.length()));
|
||||
buffer.append(s_ansi_color_codes[color]);
|
||||
if (supports_color_codes)
|
||||
buffer.append(s_ansi_color_codes[color]);
|
||||
|
||||
if (s_log_timestamps)
|
||||
buffer.append_format(TIMESTAMP_FORMAT_STRING, Log::GetCurrentMessageTime());
|
||||
|
||||
buffer.append(message);
|
||||
|
||||
if (supports_color_codes)
|
||||
buffer.append(s_ansi_color_codes[Color_Default]);
|
||||
buffer.append('\n');
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -134,7 +145,6 @@ cleanup:
|
||||
if (wmessage_buf != wbuf)
|
||||
std::free(wmessage_buf);
|
||||
#else
|
||||
const int fd = (level <= LOGLEVEL_WARNING) ? STDERR_FILENO : STDOUT_FILENO;
|
||||
write(fd, buffer.data(), buffer.length());
|
||||
#endif
|
||||
}
|
||||
@@ -157,7 +167,7 @@ void Log::SetConsoleOutputLevel(LOGLEVEL level)
|
||||
if (was_enabled == now_enabled)
|
||||
return;
|
||||
|
||||
// Worst that happens here is we write to a bad handle..
|
||||
// Worst that happens here is we write to a bad handle..
|
||||
|
||||
#if defined(_WIN32)
|
||||
static constexpr auto enable_virtual_terminal_processing = [](HANDLE hConsole) {
|
||||
|
||||
@@ -30,8 +30,6 @@ namespace x86Emitter
|
||||
extern void EmitRex(SIMDInstructionInfo info, const xRegisterBase& reg1, const xRegisterBase& reg2);
|
||||
extern void EmitRex(SIMDInstructionInfo info, const xRegisterBase& reg1, const xIndirectVoid& sib);
|
||||
|
||||
extern void _xMovRtoR(const xRegisterInt& to, const xRegisterInt& from);
|
||||
|
||||
template <typename T>
|
||||
inline void xWrite(T val)
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
void _xMovRtoR(const xRegisterInt& to, const xRegisterInt& from)
|
||||
void xImpl_Mov::operator()(const xRegisterInt& to, const xRegisterInt& from) const
|
||||
{
|
||||
pxAssert(to.GetOperandSize() == from.GetOperandSize());
|
||||
|
||||
@@ -32,12 +32,6 @@ namespace x86Emitter
|
||||
xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from, to);
|
||||
}
|
||||
|
||||
void xImpl_Mov::operator()(const xRegisterInt& to, const xRegisterInt& from) const
|
||||
{
|
||||
// FIXME WTF?
|
||||
_xMovRtoR(to, from);
|
||||
}
|
||||
|
||||
void xImpl_Mov::operator()(const xIndirectVoid& dest, const xRegisterInt& from) const
|
||||
{
|
||||
// mov eax has a special from when writing directly to a DISP32 address
|
||||
|
||||
@@ -1045,7 +1045,7 @@ const xRegister32
|
||||
}
|
||||
else if (displacement_size == 0)
|
||||
{
|
||||
_xMovRtoR(to, src.Index.MatchSizeTo(to));
|
||||
xMOV(to, src.Index.MatchSizeTo(to));
|
||||
return;
|
||||
}
|
||||
else if (!preserve_flags)
|
||||
@@ -1053,7 +1053,7 @@ const xRegister32
|
||||
// encode as MOV and ADD combo. Make sure to use the immediate on the
|
||||
// ADD since it can encode as an 8-bit sign-extended value.
|
||||
|
||||
_xMovRtoR(to, src.Index.MatchSizeTo(to));
|
||||
xMOV(to, src.Index.MatchSizeTo(to));
|
||||
xADD(to, src.Displacement);
|
||||
return;
|
||||
}
|
||||
@@ -1071,7 +1071,7 @@ const xRegister32
|
||||
// (this does not apply to older model P4s with the broken barrel shifter,
|
||||
// but we currently aren't optimizing for that target anyway).
|
||||
|
||||
_xMovRtoR(to, src.Index);
|
||||
xMOV(to, src.Index);
|
||||
xSHL(to, src.Scale);
|
||||
return;
|
||||
}
|
||||
@@ -1085,14 +1085,14 @@ const xRegister32
|
||||
if (src.Index == rsp)
|
||||
{
|
||||
// ESP is not encodable as an index (ix86 ignores it), thus:
|
||||
_xMovRtoR(to, src.Base.MatchSizeTo(to)); // will do the trick!
|
||||
xMOV(to, src.Base.MatchSizeTo(to)); // will do the trick!
|
||||
if (src.Displacement)
|
||||
xADD(to, src.Displacement);
|
||||
return;
|
||||
}
|
||||
else if (src.Displacement == 0)
|
||||
{
|
||||
_xMovRtoR(to, src.Base.MatchSizeTo(to));
|
||||
xMOV(to, src.Base.MatchSizeTo(to));
|
||||
xADD(to, src.Index.MatchSizeTo(to));
|
||||
return;
|
||||
}
|
||||
@@ -1102,7 +1102,7 @@ const xRegister32
|
||||
// special case handling of ESP as Index, which is replaceable with
|
||||
// a single MOV even when preserve_flags is set! :D
|
||||
|
||||
_xMovRtoR(to, src.Base.MatchSizeTo(to));
|
||||
xMOV(to, src.Base.MatchSizeTo(to));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<DepsRootDir Condition="'$(Platform)'=='x64'">$(SolutionDir)deps\</DepsRootDir>
|
||||
<DepsRootDir Condition="'$(Platform)'=='ARM64'">$(SolutionDir)deps-arm64\</DepsRootDir>
|
||||
<DepsBinDir>$(DepsRootDir)bin\</DepsBinDir>
|
||||
<DepsLibDir>$(DepsRootDir)lib\</DepsLibDir>
|
||||
<DepsIncludeDir>$(DepsRootDir)include\</DepsIncludeDir>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,5 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="DepsDir.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<SSEString />
|
||||
<SSEString Condition="$(Configuration.Contains(AVX2))">-avx2</SSEString>
|
||||
@@ -15,11 +18,6 @@
|
||||
<PropertyGroup>
|
||||
<OutDir>$(SolutionDir)build\lib-$(PlatformName)-$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)build\obj-$(ProjectName)-$(PlatformName)-$(Configuration)\</IntDir>
|
||||
<DepsRootDir Condition="'$(Platform)'=='x64'">$(SolutionDir)deps\</DepsRootDir>
|
||||
<DepsRootDir Condition="'$(Platform)'=='ARM64'">$(SolutionDir)deps-arm64\</DepsRootDir>
|
||||
<DepsBinDir>$(DepsRootDir)bin\</DepsBinDir>
|
||||
<DepsLibDir>$(DepsRootDir)lib\</DepsLibDir>
|
||||
<DepsIncludeDir>$(DepsRootDir)include\</DepsIncludeDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
|
||||
+17
-10
@@ -91,6 +91,9 @@ static double s_last_barriers = 0;
|
||||
static double s_last_copies = 0;
|
||||
static double s_last_uploads = 0;
|
||||
static double s_last_readbacks = 0;
|
||||
static double s_last_depth_copies_rov = 0;
|
||||
static double s_last_draws_rov = 0;
|
||||
static double s_last_barriers_rov = 0;
|
||||
static u64 s_total_internal_draws = 0;
|
||||
static u64 s_total_draws = 0;
|
||||
static u64 s_total_render_passes = 0;
|
||||
@@ -98,6 +101,9 @@ static u64 s_total_barriers = 0;
|
||||
static u64 s_total_copies = 0;
|
||||
static u64 s_total_uploads = 0;
|
||||
static u64 s_total_readbacks = 0;
|
||||
static u64 s_total_depth_copies_rov = 0;
|
||||
static u64 s_total_draws_rov = 0;
|
||||
static u64 s_total_barriers_rov = 0;
|
||||
static u32 s_total_frames = 0;
|
||||
static u32 s_total_drawn_frames = 0;
|
||||
|
||||
@@ -216,6 +222,11 @@ bool Host::CopyTextToClipboard(const std::string_view text)
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Host::GetTextFromClipboard()
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
|
||||
void Host::BeginTextInput()
|
||||
{
|
||||
// noop
|
||||
@@ -287,6 +298,9 @@ void Host::BeginPresentFrame()
|
||||
update_stat(GSPerfMon::TextureCopies, s_total_copies, s_last_copies);
|
||||
update_stat(GSPerfMon::TextureUploads, s_total_uploads, s_last_uploads);
|
||||
update_stat(GSPerfMon::Readbacks, s_total_readbacks, s_last_readbacks);
|
||||
update_stat(GSPerfMon::DepthCopiesROV, s_total_depth_copies_rov, s_last_depth_copies_rov);
|
||||
update_stat(GSPerfMon::DrawCallsROV, s_total_draws_rov, s_last_draws_rov);
|
||||
update_stat(GSPerfMon::BarriersROV, s_total_barriers_rov, s_last_barriers_rov);
|
||||
|
||||
const bool idle_frame = s_total_frames && (last_draws == s_total_internal_draws && last_uploads == s_total_uploads);
|
||||
|
||||
@@ -419,16 +433,6 @@ void Host::OnAchievementsRefreshed()
|
||||
// noop
|
||||
}
|
||||
|
||||
void Host::OnCoverDownloaderOpenRequested()
|
||||
{
|
||||
// noop
|
||||
}
|
||||
|
||||
void Host::OnCreateMemoryCardOpenRequested()
|
||||
{
|
||||
// noop
|
||||
}
|
||||
|
||||
bool Host::InBatchMode()
|
||||
{
|
||||
return false;
|
||||
@@ -913,6 +917,9 @@ void GSRunner::DumpStats()
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Copies: {} (avg {})", s_total_copies, static_cast<u64>(std::ceil(s_total_copies / static_cast<double>(s_total_drawn_frames)))));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Uploads: {} (avg {})", s_total_uploads, static_cast<u64>(std::ceil(s_total_uploads / static_cast<double>(s_total_drawn_frames)))));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Readbacks: {} (avg {})", s_total_readbacks, static_cast<u64>(std::ceil(s_total_readbacks / static_cast<double>(s_total_drawn_frames)))));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Depth Copies (ROV): {} (avg {})", s_total_depth_copies_rov, static_cast<u64>(std::ceil(s_total_depth_copies_rov / static_cast<double>(s_total_drawn_frames)))));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Draws Calls (ROV): {} (avg {})", s_total_draws_rov, static_cast<u64>(std::ceil(s_total_draws_rov / static_cast<double>(s_total_drawn_frames)))));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Barriers (ROV): {} (avg {})", s_total_barriers_rov, static_cast<u64>(std::ceil(s_total_barriers_rov / static_cast<double>(s_total_drawn_frames)))));
|
||||
if (s_perf_enable)
|
||||
{
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Minimum Frame Time: {:.3f} ms ({:.3f} FPS)", PerformanceMetrics::GetMinimumFrameTime(), 1000.0f / PerformanceMetrics::GetMinimumFrameTime()));
|
||||
|
||||
@@ -654,6 +654,9 @@ void GameListWidget::refreshGridCovers()
|
||||
|
||||
void GameListWidget::showGameList()
|
||||
{
|
||||
Host::SetBaseBoolSettingValue("UI", "GameListGridView", false);
|
||||
Host::CommitBaseSettingChanges();
|
||||
|
||||
if (m_ui.stack->currentIndex() == 0 || m_model->rowCount() == 0)
|
||||
{
|
||||
// We can click the toolbar multiple times, so keep it correct.
|
||||
@@ -661,8 +664,6 @@ void GameListWidget::showGameList()
|
||||
return;
|
||||
}
|
||||
|
||||
Host::SetBaseBoolSettingValue("UI", "GameListGridView", false);
|
||||
Host::CommitBaseSettingChanges();
|
||||
m_ui.stack->setCurrentIndex(0);
|
||||
setFocusProxy(m_ui.stack->currentWidget());
|
||||
resizeTableViewColumnsToFit();
|
||||
@@ -672,6 +673,9 @@ void GameListWidget::showGameList()
|
||||
|
||||
void GameListWidget::showGameGrid()
|
||||
{
|
||||
Host::SetBaseBoolSettingValue("UI", "GameListGridView", true);
|
||||
Host::CommitBaseSettingChanges();
|
||||
|
||||
if (m_ui.stack->currentIndex() == 1 || m_model->rowCount() == 0)
|
||||
{
|
||||
// We can click the toolbar multiple times, so keep it correct.
|
||||
@@ -679,8 +683,6 @@ void GameListWidget::showGameGrid()
|
||||
return;
|
||||
}
|
||||
|
||||
Host::SetBaseBoolSettingValue("UI", "GameListGridView", true);
|
||||
Host::CommitBaseSettingChanges();
|
||||
m_ui.stack->setCurrentIndex(1);
|
||||
setFocusProxy(m_ui.stack->currentWidget());
|
||||
updateToolbar();
|
||||
@@ -703,7 +705,7 @@ void GameListWidget::setShowCoverTitles(bool enabled)
|
||||
|
||||
void GameListWidget::updateToolbar()
|
||||
{
|
||||
const bool grid_view = isShowingGameGrid();
|
||||
const bool grid_view = Host::GetBaseBoolSettingValue("UI", "GameListGridView", false);
|
||||
{
|
||||
QSignalBlocker sb(m_ui.viewGameGrid);
|
||||
m_ui.viewGameGrid->setChecked(grid_view);
|
||||
|
||||
@@ -454,8 +454,6 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread)
|
||||
connect(thread, &EmuThread::onCaptureStopped, this, &MainWindow::onCaptureStopped);
|
||||
connect(thread, &EmuThread::onAchievementsLoginRequested, this, &MainWindow::onAchievementsLoginRequested);
|
||||
connect(thread, &EmuThread::onAchievementsHardcoreModeChanged, this, &MainWindow::onAchievementsHardcoreModeChanged);
|
||||
connect(thread, &EmuThread::onCoverDownloaderOpenRequested, this, &MainWindow::onToolsCoverDownloaderTriggered);
|
||||
connect(thread, &EmuThread::onCreateMemoryCardOpenRequested, this, &MainWindow::onCreateMemoryCardOpenRequested);
|
||||
|
||||
connect(m_ui.actionReset, &QAction::triggered, this, &MainWindow::requestReset);
|
||||
connect(m_ui.actionPause, &QAction::toggled, thread, &EmuThread::setVMPaused);
|
||||
|
||||
+31
-10
@@ -77,6 +77,7 @@ namespace QtHost
|
||||
static void SaveSettings();
|
||||
static void HookSignals();
|
||||
static void RegisterTypes();
|
||||
static void InitializeClipboard();
|
||||
static bool RunSetupWizard();
|
||||
std::optional<bool> DownloadFile(QWidget* parent, const QString& title, std::string url, std::vector<u8>* data);
|
||||
} // namespace QtHost
|
||||
@@ -96,6 +97,8 @@ static bool s_run_setup_wizard = false;
|
||||
static bool s_cleanup_after_update = false;
|
||||
static bool s_boot_and_debug = false;
|
||||
static std::atomic_int s_vm_locked_with_dialog = 0;
|
||||
static std::string s_clipboard_cache;
|
||||
static std::mutex s_clipboard_cache_mutex;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// CPU Thread
|
||||
@@ -1131,16 +1134,6 @@ void Host::OnAchievementsHardcoreModeChanged(bool enabled)
|
||||
emit g_emu_thread->onAchievementsHardcoreModeChanged(enabled);
|
||||
}
|
||||
|
||||
void Host::OnCoverDownloaderOpenRequested()
|
||||
{
|
||||
emit g_emu_thread->onCoverDownloaderOpenRequested();
|
||||
}
|
||||
|
||||
void Host::OnCreateMemoryCardOpenRequested()
|
||||
{
|
||||
emit g_emu_thread->onCreateMemoryCardOpenRequested();
|
||||
}
|
||||
|
||||
bool Host::ShouldPreferHostFileSelector()
|
||||
{
|
||||
#ifdef __linux__
|
||||
@@ -1676,6 +1669,12 @@ bool Host::CopyTextToClipboard(const std::string_view text)
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Host::GetTextFromClipboard()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_clipboard_cache_mutex);
|
||||
return s_clipboard_cache;
|
||||
}
|
||||
|
||||
void Host::BeginTextInput()
|
||||
{
|
||||
QInputMethod* method = qApp->inputMethod();
|
||||
@@ -2361,6 +2360,26 @@ void QtHost::RegisterTypes()
|
||||
qRegisterMetaType<Achievements::LoginRequestReason>();
|
||||
}
|
||||
|
||||
void QtHost::InitializeClipboard()
|
||||
{
|
||||
QClipboard* clipboard = QGuiApplication::clipboard();
|
||||
if (clipboard)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_clipboard_cache_mutex);
|
||||
s_clipboard_cache = clipboard->text().toStdString();
|
||||
}
|
||||
QObject::connect(clipboard, &QClipboard::dataChanged, []() {
|
||||
QClipboard* cb = QGuiApplication::clipboard();
|
||||
if (cb)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_clipboard_cache_mutex);
|
||||
s_clipboard_cache = cb->text().toStdString();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool QtHost::RunSetupWizard()
|
||||
{
|
||||
SetupWizardDialog dialog;
|
||||
@@ -2409,6 +2428,8 @@ int main(int argc, char* argv[])
|
||||
|
||||
PCSX2MainApplication app(argc, argv);
|
||||
|
||||
QtHost::InitializeClipboard();
|
||||
|
||||
#ifndef _WIN32
|
||||
if (!PerformEarlyHardwareChecks())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
@@ -165,10 +165,6 @@ Q_SIGNALS:
|
||||
/// Called when hardcore mode is enabled or disabled.
|
||||
void onAchievementsHardcoreModeChanged(bool enabled);
|
||||
|
||||
/// Big Picture UI requests.
|
||||
void onCoverDownloaderOpenRequested();
|
||||
void onCreateMemoryCardOpenRequested();
|
||||
|
||||
/// Called when video capture starts/stops.
|
||||
void onCaptureStarted(const QString& filename);
|
||||
void onCaptureStopped();
|
||||
|
||||
@@ -590,6 +590,12 @@ u32 QtUtils::KeyEventToCode(const QKeyEvent* ev)
|
||||
modifiers &= ~Qt::KeypadModifier;
|
||||
}
|
||||
}
|
||||
|
||||
// Undo Qt's swapping of Control and Command on macOS.
|
||||
if (key == Qt::Key_Control)
|
||||
key = Qt::Key_Meta;
|
||||
else if (key == Qt::Key_Meta)
|
||||
key = Qt::Key_Control;
|
||||
#endif
|
||||
|
||||
return static_cast<u32>(key) | (static_cast<u32>(modifiers) & static_cast<u32>(Qt::KeypadModifier));
|
||||
|
||||
+1
-1
@@ -180,7 +180,7 @@ namespace QtUtils
|
||||
}
|
||||
|
||||
wi.surface_refresh_rate = surface_refresh_rate.value();
|
||||
INFO_LOG("Surface refresh rate: {} hz", wi.surface_refresh_rate);
|
||||
INFO_LOG("Surface refresh rate: {} Hz", wi.surface_refresh_rate);
|
||||
|
||||
return wi;
|
||||
}
|
||||
|
||||
@@ -474,7 +474,7 @@
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Deflate64</string>
|
||||
<string>Deflate</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
@@ -482,11 +482,6 @@
|
||||
<string>Zstandard</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>LZMA2</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QScrollArea>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include "common/Console.h"
|
||||
@@ -14,6 +15,7 @@
|
||||
|
||||
#include "pcsx2/Host.h"
|
||||
#include "pcsx2/SIO/Pad/Pad.h"
|
||||
#include "pcsx2/SIO/Sio.h"
|
||||
|
||||
#include "Settings/ControllerBindingWidget.h"
|
||||
#include "Settings/ControllerSettingsWindow.h"
|
||||
@@ -41,7 +43,18 @@ ControllerBindingWidget::ControllerBindingWidget(QWidget* parent, ControllerSett
|
||||
, m_port_number(port)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
m_ui.groupBox->setTitle(tr("Controller Port %1").arg(port + 1));
|
||||
|
||||
const auto [pad_port, pad_slot] = sioConvertPadToPortAndSlot(port);
|
||||
const bool mtap_enabled = m_dialog->getBoolValue("Pad", (pad_port == 0) ? "MultitapPort1" : "MultitapPort2", false);
|
||||
if (mtap_enabled)
|
||||
{
|
||||
static constexpr const std::array<char, 4> s_mtap_slot_names = {{'A', 'B', 'C', 'D'}};
|
||||
m_ui.groupBox->setTitle(tr("Controller Port %1%2").arg(pad_port + 1).arg(s_mtap_slot_names[pad_slot]));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.groupBox->setTitle(tr("Controller Port %1").arg(pad_port + 1));
|
||||
}
|
||||
|
||||
populateControllerTypes();
|
||||
onTypeChanged();
|
||||
@@ -294,7 +307,20 @@ ControllerMacroWidget::ControllerMacroWidget(ControllerBindingWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
setWindowTitle(tr("Controller Port %1 Macros").arg(parent->getPortNumber() + 1u));
|
||||
|
||||
const u32 port = parent->getPortNumber();
|
||||
const auto [pad_port, pad_slot] = sioConvertPadToPortAndSlot(port);
|
||||
const bool mtap_enabled = parent->getDialog()->getBoolValue("Pad", (pad_port == 0) ? "MultitapPort1" : "MultitapPort2", false);
|
||||
if (mtap_enabled)
|
||||
{
|
||||
static constexpr const std::array<char, 4> s_mtap_slot_names = {{'A', 'B', 'C', 'D'}};
|
||||
setWindowTitle(tr("Controller Port %1%2 Macros").arg(pad_port + 1).arg(s_mtap_slot_names[pad_slot]));
|
||||
}
|
||||
else
|
||||
{
|
||||
setWindowTitle(tr("Controller Port %1 Macros").arg(pad_port + 1));
|
||||
}
|
||||
|
||||
createWidgets(parent);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsWindow* settings_dialog
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.vsync, "EmuCore/GS", "VsyncEnable", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.syncToHostRefreshRate, "EmuCore/GS", "SyncToHostRefreshRate", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.useVSyncForTiming, "EmuCore/GS", "UseVSyncForTiming", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.skipPresentingDuplicateFrames, "EmuCore/GS", "SkipDuplicateFrames", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.skipPresentingDuplicateFrames, "EmuCore/GS", "SkipDuplicateFrames", true);
|
||||
connect(m_ui.optimalFramePacing, &QCheckBox::checkStateChanged, this, &EmulationSettingsWidget::onOptimalFramePacingChanged);
|
||||
connect(m_ui.vsync, &QCheckBox::checkStateChanged, this, &EmulationSettingsWidget::updateUseVSyncForTimingEnabled);
|
||||
connect(m_ui.syncToHostRefreshRate, &QCheckBox::checkStateChanged, this, &EmulationSettingsWidget::updateUseVSyncForTimingEnabled);
|
||||
@@ -150,7 +150,7 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsWindow* settings_dialog
|
||||
dialog()->registerWidgetHelp(m_ui.useVSyncForTiming, tr("Use Host VSync Timing"), tr("Unchecked"),
|
||||
tr("When synchronizing with the host refresh rate, this option disables PCSX2's internal frame timing and uses the host instead. "
|
||||
"Can result in smoother frame pacing, <strong>but at the cost of increased input latency</strong>."));
|
||||
dialog()->registerWidgetHelp(m_ui.skipPresentingDuplicateFrames, tr("Skip Presenting Duplicate Frames"), tr("Unchecked"),
|
||||
dialog()->registerWidgetHelp(m_ui.skipPresentingDuplicateFrames, tr("Skip Presenting Duplicate Frames"), tr("Checked"),
|
||||
tr("Detects when idle frames are being presented in 25/30fps games, and skips presenting those frames. The frame is still "
|
||||
"rendered, it just means the GPU has more time to complete it (this is NOT frame skipping). Can smooth out frame time "
|
||||
"fluctuations when the CPU/GPU are near maximum utilization, but makes frame pacing more inconsistent and can increase "
|
||||
|
||||
@@ -43,6 +43,11 @@
|
||||
<string>Accurate (Recommended)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Accurate Force Full (Can Reduce Readbacks)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Disable Readbacks (Synchronize GS Thread)</string>
|
||||
@@ -91,27 +96,6 @@
|
||||
</item>
|
||||
<item row="10" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="advancedLayout">
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="extendedUpscales">
|
||||
<property name="text">
|
||||
<string>Extended Upscaling Multipliers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="disableMailboxPresentation">
|
||||
<property name="text">
|
||||
<string extracomment="Mailbox Presentation: a type of graphics-rendering technique that has not been exposed to the public that often, so chances are you will need to keep the word mailbox in English. It does not have anything to do with postal mailboxes or email inboxes/outboxes.">Disable Mailbox Presentation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="useBlitSwapChain">
|
||||
<property name="text">
|
||||
<string extracomment="Blit = a data operation. You might want to write it as-is, but fully uppercased. More information: https://en.wikipedia.org/wiki/Bit_blit \nSwap chain: see Microsoft's Terminology Portal.">Use Blit Swap Chain</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="spinCPUDuringReadbacks">
|
||||
<property name="text">
|
||||
@@ -119,13 +103,48 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="spinGPUDuringReadbacks">
|
||||
<property name="text">
|
||||
<string>Spin GPU During Readbacks</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="useBlitSwapChain">
|
||||
<property name="text">
|
||||
<string extracomment="Blit = a data operation. You might want to write it as-is, but fully uppercased. More information: https://en.wikipedia.org/wiki/Bit_blit \nSwap chain: see Microsoft's Terminology Portal.">Use Blit Swap Chain</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="rov">
|
||||
<property name="text">
|
||||
<string>Rasterizer Ordered View</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="disableMailboxPresentation">
|
||||
<property name="text">
|
||||
<string extracomment="Mailbox Presentation: a type of graphics-rendering technique that has not been exposed to the public that often, so chances are you will need to keep the word mailbox in English. It does not have anything to do with postal mailboxes or email inboxes/outboxes.">Disable Mailbox Presentation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="extendedUpscales">
|
||||
<property name="text">
|
||||
<string>Extended Upscaling Multipliers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="rovBarriersVK">
|
||||
<property name="text">
|
||||
<string>ROV Barriers Vulkan</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
@@ -353,19 +372,21 @@
|
||||
<tabstop>gsDumpCompression</tabstop>
|
||||
<tabstop>texturePreloading</tabstop>
|
||||
<tabstop>exclusiveFullscreenControl</tabstop>
|
||||
<tabstop>useBlitSwapChain</tabstop>
|
||||
<tabstop>rov</tabstop>
|
||||
<tabstop>extendedUpscales</tabstop>
|
||||
<tabstop>disableMailboxPresentation</tabstop>
|
||||
<tabstop>spinCPUDuringReadbacks</tabstop>
|
||||
<tabstop>spinGPUDuringReadbacks</tabstop>
|
||||
<tabstop>spinCPUDuringReadbacks</tabstop>
|
||||
<tabstop>useBlitSwapChain</tabstop>
|
||||
<tabstop>disableMailboxPresentation</tabstop>
|
||||
<tabstop>rovBarriersVK</tabstop>
|
||||
<tabstop>ntscFrameRate</tabstop>
|
||||
<tabstop>palFrameRate</tabstop>
|
||||
<tabstop>overrideTextureBarriers</tabstop>
|
||||
<tabstop>useDebugDevice</tabstop>
|
||||
<tabstop>useDebugBlend</tabstop>
|
||||
<tabstop>disableFramebufferFetch</tabstop>
|
||||
<tabstop>disableShaderCache</tabstop>
|
||||
<tabstop>disableVertexShaderExpand</tabstop>
|
||||
<tabstop>useDebugBlend</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
@@ -223,6 +223,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Advanced Settings
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_advanced.rov, "EmuCore/GS", "HWROV", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_advanced.useBlitSwapChain, "EmuCore/GS", "UseBlitSwapChain", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_advanced.useDebugDevice, "EmuCore/GS", "UseDebugDevice", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_advanced.useDebugBlend, "EmuCore/GS", "UseDebugBlend", false);
|
||||
@@ -239,6 +240,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
|
||||
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_advanced.palFrameRate, "EmuCore/GS", "FrameRatePAL", 50.00f);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_advanced.spinCPUDuringReadbacks, "EmuCore/GS", "HWSpinCPUForReadbacks", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_advanced.spinGPUDuringReadbacks, "EmuCore/GS", "HWSpinGPUForReadbacks", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_advanced.rovBarriersVK, "EmuCore/GS", "HWROVBarriersVK", false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_advanced.texturePreloading, "EmuCore/GS", "texture_preloading", static_cast<int>(TexturePreloadingLevel::Off));
|
||||
|
||||
setTabVisible(m_advanced_tab, QtHost::ShouldShowAdvancedSettings());
|
||||
@@ -757,6 +759,12 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
|
||||
tr("Overrides the driver's heuristics for enabling exclusive fullscreen, or direct flip/scanout.<br>"
|
||||
"Disallowing exclusive fullscreen may enable smoother task switching and overlays, but increase input latency."));
|
||||
|
||||
dialog()->registerWidgetHelp(
|
||||
m_advanced.rov, tr("Rasterizer Ordered View"), tr("Checked"), tr("Enables Rasterizer Ordered View (ROV), which allows feedback loops to be executed with fewer draw calls. Can improve performance in feedback heavy games with higher accuracy settings."));
|
||||
|
||||
dialog()->registerWidgetHelp(m_advanced.rovBarriersVK, tr("ROV Barriers Vulkan"), tr("Unchecked"),
|
||||
tr("Forces extra barriers when using ROV with Vulkan to fix graphical issues present in some games and hardware configurations."));
|
||||
|
||||
dialog()->registerWidgetHelp(m_advanced.disableMailboxPresentation, tr("Disable Mailbox Presentation"), tr("Unchecked"),
|
||||
tr("Forces the use of FIFO over Mailbox presentation, i.e. double buffering instead of triple buffering. "
|
||||
"Usually results in worse frame pacing."));
|
||||
@@ -1002,6 +1010,7 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
||||
const bool is_software = (type == GSRendererType::SW);
|
||||
const bool is_auto = (type == GSRendererType::Auto);
|
||||
const bool is_vk = (type == GSRendererType::VK);
|
||||
const bool is_ogl = (type == GSRendererType::OGL);
|
||||
const bool is_disable_barriers = (type == GSRendererType::Metal || type == GSRendererType::SW);
|
||||
const bool hw_fixes = (is_hardware && m_hw.enableHWFixes && m_hw.enableHWFixes->checkState() == Qt::Checked);
|
||||
|
||||
@@ -1044,6 +1053,9 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
||||
if (m_advanced.exclusiveFullscreenControl)
|
||||
m_advanced.exclusiveFullscreenControl->setEnabled(is_auto || is_vk);
|
||||
|
||||
if (m_advanced.rov)
|
||||
m_advanced.rov->setDisabled(!is_hardware || is_ogl);
|
||||
|
||||
// populate adapters
|
||||
std::vector<GSAdapterInfo> adapters = GSGetAdapterInfo(type);
|
||||
const GSAdapterInfo* current_adapter_info = nullptr;
|
||||
|
||||
@@ -250,6 +250,7 @@ std::vector<std::pair<QString, QString>> QtHost::GetAvailableLanguageList()
|
||||
{QCoreApplication::translate("InterfaceSettingsWidget", "System Language [Default]"), QStringLiteral("system")},
|
||||
{QStringLiteral("Afrikaans (af-ZA)"), QStringLiteral("af-ZA")},
|
||||
{QStringLiteral("عربي (ar-SA)"), QStringLiteral("ar-SA")},
|
||||
{QStringLiteral("Azərbaycanca (az-AZ)"), QStringLiteral("az-AZ")},
|
||||
{QStringLiteral("Català (ca-ES)"), QStringLiteral("ca-ES")},
|
||||
{QStringLiteral("Čeština (cs-CZ)"), QStringLiteral("cs-CZ")},
|
||||
{QStringLiteral("Dansk (da-DK)"), QStringLiteral("da-DK")},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+2673
-2567
File diff suppressed because it is too large
Load Diff
@@ -1338,7 +1338,7 @@ function(setup_main_executable target)
|
||||
endforeach()
|
||||
|
||||
get_target_property(WINDEPLOYQT_EXE Qt6::windeployqt IMPORTED_LOCATION)
|
||||
install(CODE "execute_process(COMMAND \"${WINDEPLOYQT_EXE}\" \"${CMAKE_SOURCE_DIR}/bin/$<TARGET_FILE_NAME:${target}>\" --plugindir \"${CMAKE_SOURCE_DIR}/bin/QtPlugins\" --pdb --no-compiler-runtime --no-system-d3d-compiler --no-system-dxc-compiler --no-translations COMMAND_ERROR_IS_FATAL ANY)")
|
||||
install(CODE "execute_process(COMMAND \"${WINDEPLOYQT_EXE}\" \"${CMAKE_SOURCE_DIR}/bin/$<TARGET_FILE_NAME:${target}>\" --plugindir \"${CMAKE_SOURCE_DIR}/bin/QtPlugins\" --pdb --no-compiler-runtime --no-system-d3d-compiler --no-system-dxc-compiler --no-translations --no-network COMMAND_ERROR_IS_FATAL ANY)")
|
||||
install(CODE "file(WRITE \"${CMAKE_SOURCE_DIR}/bin/qt.conf\" \"[Paths]\\nPlugins = ./QtPlugins\")")
|
||||
endif()
|
||||
|
||||
|
||||
+2
-2
@@ -6,8 +6,8 @@
|
||||
#include "common/Pcsx2Defs.h"
|
||||
|
||||
static const u32 BIAS = 2; // Bus is half of the actual ps2 speed
|
||||
static const u32 PS2CLK = 294912000; //hz /* 294.912 mhz */
|
||||
extern u32 PSXCLK; /* 36.864 Mhz */
|
||||
static const u32 PS2CLK = 294912000; //Hz /* 294.912 MHz */
|
||||
extern u32 PSXCLK; /* 36.864 MHz */
|
||||
|
||||
|
||||
#include "Memory.h"
|
||||
|
||||
+6
-3
@@ -384,9 +384,8 @@ enum class GSDumpCompressionMethod : u8
|
||||
enum class SavestateCompressionMethod : u8
|
||||
{
|
||||
Uncompressed = 0,
|
||||
Deflate64 = 1,
|
||||
Zstandard = 2,
|
||||
LZMA2 = 3
|
||||
Deflate = 1,
|
||||
Zstandard = 2
|
||||
};
|
||||
|
||||
enum class SavestateCompressionLevel : u8
|
||||
@@ -400,6 +399,7 @@ enum class SavestateCompressionLevel : u8
|
||||
enum class GSHardwareDownloadMode : u8
|
||||
{
|
||||
Enabled,
|
||||
EnabledForceFull,
|
||||
NoReadbacks,
|
||||
Unsynchronized,
|
||||
Disabled
|
||||
@@ -794,6 +794,9 @@ struct Pcsx2Config
|
||||
HWMipmap : 1,
|
||||
HWAccurateAlphaTest : 1,
|
||||
HWAA1 : 1,
|
||||
HWROV : 1,
|
||||
HWROVLogging : 1,
|
||||
HWROVBarriersVK : 1,
|
||||
ManualUserHacks : 1,
|
||||
UserHacks_AlignSpriteX : 1,
|
||||
UserHacks_CPUFBConversion : 1,
|
||||
|
||||
+30
-10
@@ -701,16 +701,36 @@ void GSgetStats(SmallStringBase& info)
|
||||
}
|
||||
else
|
||||
{
|
||||
info.format("{} HW | {} PRIM | {} DRW | {} DRWC | {} BAR | {} RP | {} RB | {} TC | {} TU",
|
||||
api_name,
|
||||
(int)pm.Get(GSPerfMon::Prim),
|
||||
(int)pm.Get(GSPerfMon::Draw),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::DrawCalls)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::Barriers)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::RenderPasses)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::Readbacks)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::TextureCopies)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::TextureUploads)));
|
||||
if (!GSConfig.HWROV)
|
||||
{
|
||||
info.format("{} HW | {} PRIM | {} DRW | {} DRWC | {} BAR | {} RP | {} RB | {} TC | {} TU",
|
||||
api_name,
|
||||
(int)pm.Get(GSPerfMon::Prim),
|
||||
(int)pm.Get(GSPerfMon::Draw),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::DrawCalls)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::Barriers)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::RenderPasses)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::Readbacks)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::TextureCopies)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::TextureUploads)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add ROV stats along standard stats.
|
||||
info.format("{} HW | {} PRIM | {} DRW | {}/{} DRWC | {}/{} BAR | {} RP | {} RB | {}/{} TC | {} TU",
|
||||
api_name,
|
||||
(int)pm.Get(GSPerfMon::Prim),
|
||||
(int)pm.Get(GSPerfMon::Draw),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::DrawCalls)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::DrawCallsROV)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::Barriers)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::BarriersROV)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::RenderPasses)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::Readbacks)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::TextureCopies)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::DepthCopiesROV)),
|
||||
(int)std::ceil(pm.Get(GSPerfMon::TextureUploads)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,10 +46,15 @@
|
||||
#define GL_POP() g_gs_device->PopDebugGroup()
|
||||
#define GL_INS(...) g_gs_device->InsertDebugMessage(GSDevice::DebugMessageCategory::Message, __VA_ARGS__)
|
||||
#define GL_PERF(...) g_gs_device->InsertDebugMessage(GSDevice::DebugMessageCategory::Performance, __VA_ARGS__)
|
||||
#define GL_ROV(...) \
|
||||
if (GSConfig.HWROVLogging) \
|
||||
Console.Warning(__VA_ARGS__); \
|
||||
g_gs_device->InsertDebugMessage(GSDevice::DebugMessageCategory::Message, __VA_ARGS__);
|
||||
#else
|
||||
#define GL_PUSH_(...) (void)(0)
|
||||
#define GL_PUSH(...) (void)(0)
|
||||
#define GL_POP() (void)(0)
|
||||
#define GL_INS(...) (void)(0)
|
||||
#define GL_PERF(...) (void)(0)
|
||||
#define GL_ROV(...) (void)(0)
|
||||
#endif
|
||||
|
||||
@@ -23,6 +23,9 @@ public:
|
||||
SyncPoint,
|
||||
Barriers,
|
||||
RenderPasses,
|
||||
DepthCopiesROV, // Overlaps with regular texture copies.
|
||||
DrawCallsROV, // Overlaps with regular draw calls.
|
||||
BarriersROV, // Overlaps with regular barriers.
|
||||
CounterLast,
|
||||
|
||||
// Reused counters for HW.
|
||||
|
||||
+2
-2
@@ -203,8 +203,8 @@ enum GS_AFAIL
|
||||
|
||||
enum GS_ALPHA_BITS
|
||||
{
|
||||
ALPHA_ABC_CS = 0,
|
||||
ALPHA_ABC_CD = 1,
|
||||
ALPHA_ABD_CS = 0,
|
||||
ALPHA_ABD_CD = 1,
|
||||
ALPHA_C_AS = 0,
|
||||
ALPHA_C_AD = 1,
|
||||
ALPHA_C_FIX = 2,
|
||||
|
||||
+76
-52
@@ -355,11 +355,15 @@ void GSState::ResetDrawBufferIdx()
|
||||
m_vertex = &m_vertex_buffers[m_current_buffer_idx];
|
||||
|
||||
if (m_index->tail == 0)
|
||||
{
|
||||
m_backed_up_ctx = -1;
|
||||
|
||||
m_dirty_gs_regs = 0;
|
||||
|
||||
//DevCon.Warning("New round of draws buffer %d vertex tail %d index tail %d TME %d TBP0 0x%x draw %d", m_current_buffer_idx, m_vertex->tail, m_index->tail, m_env.PRIM.TME, m_env.CTXT[m_env.PRIM.CTXT].TEX0.TBP0, s_n);
|
||||
m_dirty_gs_regs = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dirty_gs_regs = m_env_buffers[m_current_buffer_idx].m_dirty_regs;
|
||||
temp_draw_rect = m_env_buffers[m_current_buffer_idx].draw_rect;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -385,7 +389,7 @@ void GSState::ResetDrawBuffers()
|
||||
// exclude_current is used if there is a flush for a reason other than the normal context change.
|
||||
void GSState::FlushBuffers(bool flush_base_only, bool use_flush_reason, GSFlushReason flush_reason)
|
||||
{
|
||||
const u32 current_idx = m_current_buffer_idx;
|
||||
const int current_idx = m_current_buffer_idx;
|
||||
bool restore_env = false;
|
||||
|
||||
if (m_used_buffers_idx > 0)
|
||||
@@ -398,8 +402,7 @@ void GSState::FlushBuffers(bool flush_base_only, bool use_flush_reason, GSFlushR
|
||||
else if (m_index_buffers[0].tail == 0)
|
||||
return;
|
||||
|
||||
int max_flushes = flush_base_only ? 1 : m_used_buffers_idx;
|
||||
//DevCon.Warning("Flushing %d draw buffers from draw %d", m_used_buffers_idx, s_n);
|
||||
const int max_flushes = flush_base_only ? 1 : m_used_buffers_idx;
|
||||
for (int i = 0; i < max_flushes; i++)
|
||||
{
|
||||
m_current_buffer_idx = i;
|
||||
@@ -431,7 +434,7 @@ void GSState::FlushBuffers(bool flush_base_only, bool use_flush_reason, GSFlushR
|
||||
}
|
||||
else if (restore_env)
|
||||
memcpy(&m_env, &m_temp_env, sizeof(m_env));
|
||||
//DevCon.Warning("Flushing position %d ABE is %d TME %d TEX0 TBP %x", i, m_prev_env.PRIM.ABE, m_prev_env.PRIM.TME, m_prev_env.CTXT[m_prev_env.PRIM.CTXT].TEX0.TBP0);
|
||||
|
||||
if (use_flush_reason && (i == current_idx || flush_reason == VSYNC))
|
||||
FlushDraw(flush_reason);
|
||||
else
|
||||
@@ -443,7 +446,6 @@ void GSState::FlushBuffers(bool flush_base_only, bool use_flush_reason, GSFlushR
|
||||
m_current_buffer_idx = current_idx;
|
||||
m_index = &m_index_buffers[m_current_buffer_idx];
|
||||
m_vertex = &m_vertex_buffers[m_current_buffer_idx];
|
||||
m_dirty_gs_regs = 0;
|
||||
|
||||
const int ctx = m_env_buffers[m_current_buffer_idx].m_backed_up_ctx;
|
||||
std::memcpy(&m_prev_env, &m_env_buffers[m_current_buffer_idx].m_env, 88);
|
||||
@@ -451,8 +453,6 @@ void GSState::FlushBuffers(bool flush_base_only, bool use_flush_reason, GSFlushR
|
||||
std::memcpy(&m_prev_env.CTXT[1], &m_env_buffers[m_current_buffer_idx].m_env.CTXT[1], 96);
|
||||
std::memcpy(&m_prev_env.CTXT[ctx].offset, &m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].offset, sizeof(m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].offset));
|
||||
std::memcpy(&m_prev_env.CTXT[ctx].scissor, &m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].scissor, sizeof(m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].scissor));
|
||||
//DevCon.Warning("Flush complete, draw now %d", s_n);
|
||||
//UpdateContext();
|
||||
}
|
||||
|
||||
void GSState::PushBuffer()
|
||||
@@ -460,7 +460,6 @@ void GSState::PushBuffer()
|
||||
// Just in case it tries to overflow.
|
||||
if (m_used_buffers_idx >= MAX_DRAW_BUFFERS)
|
||||
{
|
||||
//DevCon.Warning("Attempted to add a draw to buffer when full. Flushing");
|
||||
FlushBuffers(false, false);
|
||||
ResetDrawBufferIdx();
|
||||
return;
|
||||
@@ -487,15 +486,11 @@ void GSState::PushBuffer()
|
||||
{
|
||||
for (u32 i = 0; i < copy_amt; i++)
|
||||
{
|
||||
GSVector4i* RESTRICT vert_ptr = (GSVector4i*)&m_vertex->buff[m_vertex->head + i];
|
||||
GSVector4i v = vert_ptr[1];
|
||||
v = v.xxxx().u16to32().sub32(m_xyof);
|
||||
v = v.blend32<12>(v.sra32<4>());
|
||||
m_vertex->xy[i & 3] = v;
|
||||
m_vertex->xy_tail = std::min(copy_amt, 2U);
|
||||
m_vertex->xy[i & 3] = m_vertex_buffers[m_current_buffer_idx].xy[((m_vertex_buffers[m_current_buffer_idx].xy_tail - copy_amt) + i) & 3];
|
||||
m_vertex->xy_tail++;
|
||||
|
||||
if (i == 0)
|
||||
m_vertex->xyhead = v;
|
||||
m_vertex->xyhead = m_vertex_buffers[m_current_buffer_idx].xyhead;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -506,7 +501,6 @@ void GSState::PushBuffer()
|
||||
m_dirty_gs_regs = 0;
|
||||
m_used_buffers_idx++;
|
||||
m_recent_buffer_switch = true;
|
||||
//DevCon.Warning("Pushing new buffer %d vertex tail %d index tail %d TME %d TBP0 0x%x draw %d", m_current_buffer_idx, m_vertex->tail, m_index->tail, m_env.PRIM.TME, m_env.CTXT[m_env.PRIM.CTXT].TEX0.TBP0, s_n);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -520,10 +514,11 @@ bool GSState::CanBufferNewDraw()
|
||||
|
||||
// If the base draw isn't writing to the Z buffer, but following draws do, we can't use it.
|
||||
// Also the base draw needs to be solid, not an alpha blend.
|
||||
if (base_context.ZBUF.ZMSK || cur_context.FRAME.FBP != base_context.FRAME.FBP || cur_context.ZBUF.ZBP != base_context.ZBUF.ZBP || (m_env_buffers[0].m_env.PRIM.TME && base_context.TEX0.TFX > TFX_DECAL) ||
|
||||
if (base_context.ZBUF.ZMSK || cur_context.FRAME.FBP != base_context.FRAME.FBP || cur_context.ZBUF.ZBP != base_context.ZBUF.ZBP || (m_env_buffers[0].m_env.PRIM.TME &&
|
||||
(base_context.TEX0.TFX > TFX_DECAL || (m_env_buffers[0].m_env.PRIM.ABE && !base_context.TEX0.TCC && m_v.RGBAQ.A != 128))) ||
|
||||
((base_context.TEST.ATE && base_context.TEST.ATST > ATST_ALWAYS && base_context.TEST.AREF != 0) && (base_context.TEST.AFAIL & AFAIL_FB_ONLY) == AFAIL_KEEP))
|
||||
{
|
||||
//DevCon.Warning("Flushing, cannot buffer draw due to incompatible base");
|
||||
// Incompatible base.
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -542,6 +537,8 @@ bool GSState::CanBufferNewDraw()
|
||||
if (!std::memcmp(&m_env_buffers[i].m_env, &m_env, 88))
|
||||
{
|
||||
GSDrawingEnvironment& buffered_ctx = m_env_buffers[i].m_env;
|
||||
if (m_index_buffers[i].tail > m_index_buffers[0].tail)
|
||||
return false;
|
||||
|
||||
if (buffered_ctx.CTXT[ctx].SCISSOR.U64 ^ cur_context.SCISSOR.U64)
|
||||
continue;
|
||||
@@ -565,6 +562,9 @@ bool GSState::CanBufferNewDraw()
|
||||
continue;
|
||||
if (buffered_ctx.CTXT[ctx].TEX1.U32[0] ^ cur_context.TEX1.U32[0])
|
||||
continue;
|
||||
if (buffered_ctx.CTXT[ctx].TEX1.MXL != cur_context.TEX1.MXL)
|
||||
continue;
|
||||
|
||||
if (cur_context.TEX1.MXL)
|
||||
{
|
||||
if (buffered_ctx.CTXT[ctx].TEX1.U32[1] ^ cur_context.TEX1.U32[1])
|
||||
@@ -600,27 +600,32 @@ bool GSState::CanBufferNewDraw()
|
||||
if (i == 1 && !m_env_buffers[i].draw_rect.eq(m_env_buffers[0].draw_rect))
|
||||
{
|
||||
FlushWrite();
|
||||
|
||||
FlushBuffers(true, false);
|
||||
const bool base_only = m_env_buffers[i].draw_rect.rintersect(m_env_buffers[0].draw_rect).rempty();
|
||||
FlushBuffers(base_only, false);
|
||||
ResetDrawBufferIdx();
|
||||
i = -1;
|
||||
continue;
|
||||
if (!base_only)
|
||||
break;
|
||||
else
|
||||
{
|
||||
i = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/*if (i != (m_current_buffer_idx + 1) && i != 0)
|
||||
return false;*/
|
||||
// We found a matching draw
|
||||
//DevCon.Warning("Matching buffered draw detected in index %d, using", i);
|
||||
m_index = &m_index_buffers[i];
|
||||
m_vertex = &m_vertex_buffers[i];
|
||||
|
||||
const u32 copy_amt = m_vertex_buffers[m_current_buffer_idx].tail - m_vertex_buffers[m_current_buffer_idx].head;
|
||||
|
||||
m_recent_buffer_switch = m_vertex->tail == m_vertex->head;
|
||||
m_vertex->tail = m_index->buff[m_index->tail - 1] + 1;
|
||||
if (m_index->tail)
|
||||
m_vertex->tail = m_index->buff[m_index->tail - 1] + 1;
|
||||
else
|
||||
m_vertex->tail = 0;
|
||||
|
||||
if (copy_amt)
|
||||
memcpy(&m_vertex->buff[m_vertex->tail], &m_vertex_buffers[m_current_buffer_idx].buff[m_vertex_buffers[m_current_buffer_idx].head], sizeof(GSVertex) * copy_amt);
|
||||
@@ -641,18 +646,13 @@ bool GSState::CanBufferNewDraw()
|
||||
|
||||
if (copy_amt)
|
||||
{
|
||||
for (u32 j = 0; j < copy_amt; j++)
|
||||
for (u32 i = 0; i < copy_amt; i++)
|
||||
{
|
||||
GSVector4i* RESTRICT vert_ptr = (GSVector4i*)&m_vertex->buff[m_vertex->head + j];
|
||||
GSVector4i v = vert_ptr[1];
|
||||
v = v.xxxx().u16to32().sub32(m_xyof);
|
||||
v = v.blend32<12>(v.sra32<4>());
|
||||
m_vertex->xy[j & 3] = v;
|
||||
m_vertex->xy[m_vertex->xy_tail & 3] = m_vertex_buffers[m_current_buffer_idx].xy[((m_vertex_buffers[m_current_buffer_idx].xy_tail - copy_amt) + i) & 3];
|
||||
m_vertex->xy_tail++;
|
||||
|
||||
if (j == 0)
|
||||
m_vertex->xyhead = v;
|
||||
|
||||
m_vertex->xy_tail = copy_amt;
|
||||
if (i == 0)
|
||||
m_vertex->xyhead = m_vertex_buffers[m_current_buffer_idx].xyhead;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -663,7 +663,7 @@ bool GSState::CanBufferNewDraw()
|
||||
}
|
||||
|
||||
m_dirty_gs_regs = 0;
|
||||
//DevCon.Warning("Picking buffer %d vertex tail %d index tail %d TME %d TBP0 0x%x dirty %x draw %d", m_current_buffer_idx, m_vertex->tail, m_index->tail, m_env.PRIM.TME, m_env.CTXT[m_env.PRIM.CTXT].TEX0.TBP0, m_dirty_gs_regs, s_n);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -688,7 +688,6 @@ bool GSState::CanBufferNewDraw()
|
||||
return false;
|
||||
|
||||
PushBuffer();
|
||||
//DevCon.Warning("Buffering new draw! now buffering %d", m_used_buffers_idx);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -4234,7 +4233,7 @@ bool GSState::TrianglesAreQuads(bool shuffle_check)
|
||||
}
|
||||
|
||||
template<u32 primclass>
|
||||
GSState::PRIM_OVERLAP GSState::GetPrimitiveOverlapDrawlistImpl(bool save_drawlist, bool save_bbox, float bbox_scale)
|
||||
GSState::PRIM_OVERLAP GSState::GetPrimitiveOverlapDrawlistImpl(bool save_drawlist, bool save_bbox, float bbox_scale, u32* max_size)
|
||||
{
|
||||
const GSVector4i xyof = m_context->scissor.xyof.xyxy();
|
||||
|
||||
@@ -4282,7 +4281,14 @@ GSState::PRIM_OVERLAP GSState::GetPrimitiveOverlapDrawlistImpl(bool save_drawlis
|
||||
if (primclass == GS_TRIANGLE_CLASS && m_quad_check_valid && m_are_quads && !using_aa1)
|
||||
{
|
||||
// The triangles-are-quads check already ensures that there is no overlap.
|
||||
m_drawlist.push_back(m_index->tail / n);
|
||||
if (save_drawlist)
|
||||
{
|
||||
m_drawlist.push_back(m_index->tail / n);
|
||||
}
|
||||
else if (max_size)
|
||||
{
|
||||
*max_size = 1;
|
||||
}
|
||||
if (save_bbox)
|
||||
{
|
||||
const GSVector4i draw_area = GSVector4i(m_vt.m_min.p.upld(m_vt.m_max.p) * GSVector4(16.0f)) + xyof;
|
||||
@@ -4294,6 +4300,7 @@ GSState::PRIM_OVERLAP GSState::GetPrimitiveOverlapDrawlistImpl(bool save_drawlis
|
||||
PRIM_OVERLAP overlap = PRIM_OVERLAP_NO;
|
||||
bool check_quads = (primclass == GS_TRIANGLE_CLASS) && !using_aa1;
|
||||
|
||||
u32 drawlist_size = 0;
|
||||
u32 i = 0;
|
||||
u32 skip = 0; // Number of indices to skip if we have the bbox from the previous iteration.
|
||||
|
||||
@@ -4691,6 +4698,17 @@ GSState::PRIM_OVERLAP GSState::GetPrimitiveOverlapDrawlistImpl(bool save_drawlis
|
||||
{
|
||||
m_drawlist.push_back((j - i) / n); // Prim count
|
||||
}
|
||||
else if (max_size)
|
||||
{
|
||||
// If the max size pointer is passed it means we just want to peek at
|
||||
// the drawlist size up to the given limit to avoid unecessary work.
|
||||
drawlist_size++;
|
||||
if (drawlist_size >= *max_size)
|
||||
{
|
||||
*max_size = drawlist_size;
|
||||
return drawlist_size > 0 ? PRIM_OVERLAP_YES : PRIM_OVERLAP_UNKNOW;
|
||||
}
|
||||
}
|
||||
else if (j < count)
|
||||
{
|
||||
return PRIM_OVERLAP_YES; // Early exit if not saving drawlist.
|
||||
@@ -4704,21 +4722,27 @@ GSState::PRIM_OVERLAP GSState::GetPrimitiveOverlapDrawlistImpl(bool save_drawlis
|
||||
all = bbox;
|
||||
i = j;
|
||||
}
|
||||
|
||||
if (max_size)
|
||||
{
|
||||
*max_size = drawlist_size;
|
||||
}
|
||||
|
||||
return overlap;
|
||||
}
|
||||
|
||||
GSState::PRIM_OVERLAP GSState::GetPrimitiveOverlapDrawlist(bool save_drawlist, bool save_bbox, float bbox_scale)
|
||||
GSState::PRIM_OVERLAP GSState::GetPrimitiveOverlapDrawlist(bool save_drawlist, bool save_bbox, float bbox_scale, u32* max_size)
|
||||
{
|
||||
switch (m_vt.m_primclass)
|
||||
{
|
||||
case GS_POINT_CLASS:
|
||||
return GetPrimitiveOverlapDrawlistImpl<GS_POINT_CLASS>(save_drawlist, save_bbox, bbox_scale);
|
||||
return GetPrimitiveOverlapDrawlistImpl<GS_POINT_CLASS>(save_drawlist, save_bbox, bbox_scale, max_size);
|
||||
case GS_LINE_CLASS:
|
||||
return GetPrimitiveOverlapDrawlistImpl<GS_LINE_CLASS>(save_drawlist, save_bbox, bbox_scale);
|
||||
return GetPrimitiveOverlapDrawlistImpl<GS_LINE_CLASS>(save_drawlist, save_bbox, bbox_scale, max_size);
|
||||
case GS_TRIANGLE_CLASS:
|
||||
return GetPrimitiveOverlapDrawlistImpl<GS_TRIANGLE_CLASS>(save_drawlist, save_bbox, bbox_scale);
|
||||
return GetPrimitiveOverlapDrawlistImpl<GS_TRIANGLE_CLASS>(save_drawlist, save_bbox, bbox_scale, max_size);
|
||||
case GS_SPRITE_CLASS:
|
||||
return GetPrimitiveOverlapDrawlistImpl<GS_SPRITE_CLASS>(save_drawlist, save_bbox, bbox_scale);
|
||||
return GetPrimitiveOverlapDrawlistImpl<GS_SPRITE_CLASS>(save_drawlist, save_bbox, bbox_scale, max_size);
|
||||
default:
|
||||
pxFail("Invalid primclass."); // Impossible.
|
||||
return PRIM_OVERLAP_UNKNOW;
|
||||
@@ -5753,10 +5777,10 @@ bool GSState::CheckOverlapVerts(u32 n)
|
||||
|
||||
if (m_index->tail > 0)
|
||||
{
|
||||
int matching_verts = 0;
|
||||
u32 matching_verts = 0;
|
||||
for (u32 i = 0; i < n; i++)
|
||||
{
|
||||
const int pos = m_index->buff[(m_index->tail - n) + i];
|
||||
const u32 pos = m_index->buff[(m_index->tail - n) + i];
|
||||
const GSVector2i prev_vert = GSVector2i(v[pos].XYZ.X - m_context->XYOFFSET.OFX, v[pos].XYZ.Y - m_context->XYOFFSET.OFY);
|
||||
|
||||
for (u32 j = 0; j < n; j++)
|
||||
@@ -6081,7 +6105,7 @@ __forceinline void GSState::VertexKick(u32 skip)
|
||||
|
||||
// Update rectangle for the current draw. Needs exclusive endpoints.
|
||||
const GSVector4i draw_rect = bbox.sra32<4>() + GSVector4i(0, 0, 1, 1);
|
||||
if (m_vertex->tail != n)
|
||||
if (m_index->tail != n)
|
||||
temp_draw_rect = temp_draw_rect.runion(draw_rect);
|
||||
else
|
||||
temp_draw_rect = draw_rect;
|
||||
|
||||
+4
-2
@@ -532,8 +532,10 @@ public:
|
||||
bool TrianglesAreQuadsImpl();
|
||||
bool TrianglesAreQuads(bool shuffle_check = false);
|
||||
template <u32 primclass>
|
||||
PRIM_OVERLAP GetPrimitiveOverlapDrawlistImpl(bool save_drawlist = false, bool save_bbox = false, float bbox_scale = 1.0f);
|
||||
PRIM_OVERLAP GetPrimitiveOverlapDrawlist(bool save_drawlist = false, bool save_bbox = false, float bbox_scale = 1.0f);
|
||||
PRIM_OVERLAP GetPrimitiveOverlapDrawlistImpl(bool save_drawlist = false, bool save_bbox = false,
|
||||
float bbox_scale = 1.0f, u32* max_size = nullptr);
|
||||
PRIM_OVERLAP GetPrimitiveOverlapDrawlist(bool save_drawlist = false, bool save_bbox = false,
|
||||
float bbox_scale = 1.0f, u32* max_size = nullptr);
|
||||
PRIM_OVERLAP PrimitiveOverlap(bool save_drawlist = false);
|
||||
bool SpriteDrawWithoutGaps();
|
||||
void CalculatePrimitiveCoversWithoutGaps();
|
||||
|
||||
@@ -22,29 +22,13 @@
|
||||
#include <ostream>
|
||||
#include <fstream>
|
||||
|
||||
int SetDATMShader(SetDATM datm)
|
||||
{
|
||||
switch (datm)
|
||||
{
|
||||
case SetDATM::DATM1_RTA_CORRECTION:
|
||||
return static_cast<int>(ShaderConvert::DATM_1_RTA_CORRECTION);
|
||||
case SetDATM::DATM0_RTA_CORRECTION:
|
||||
return static_cast<int>(ShaderConvert::DATM_0_RTA_CORRECTION);
|
||||
case SetDATM::DATM1:
|
||||
return static_cast<int>(ShaderConvert::DATM_1);
|
||||
case SetDATM::DATM0:
|
||||
default:
|
||||
return static_cast<int>(ShaderConvert::DATM_0);
|
||||
}
|
||||
}
|
||||
|
||||
const char* shaderName(ShaderConvert value)
|
||||
const char* ShaderEntryPoint(ShaderConvert value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
// clang-format off
|
||||
// clang-format off
|
||||
case ShaderConvert::COPY: return "ps_copy";
|
||||
case ShaderConvert::RGBA8_TO_16_BITS: return "ps_convert_rgba8_16bits";
|
||||
case ShaderConvert::RGB5A1_TO_16_BITS: return "ps_convert_rgb5a1_16bits";
|
||||
case ShaderConvert::DATM_1: return "ps_datm1";
|
||||
case ShaderConvert::DATM_0: return "ps_datm0";
|
||||
case ShaderConvert::DATM_1_RTA_CORRECTION: return "ps_datm1_rta_correction";
|
||||
@@ -54,22 +38,16 @@ const char* shaderName(ShaderConvert value)
|
||||
case ShaderConvert::RTA_CORRECTION: return "ps_rta_correction";
|
||||
case ShaderConvert::RTA_DECORRECTION: return "ps_rta_decorrection";
|
||||
case ShaderConvert::TRANSPARENCY_FILTER: return "ps_filter_transparency";
|
||||
case ShaderConvert::FLOAT32_TO_16_BITS: return "ps_convert_float32_32bits";
|
||||
case ShaderConvert::FLOAT32_TO_32_BITS: return "ps_convert_float32_32bits";
|
||||
case ShaderConvert::FLOAT32_TO_RGBA8: return "ps_convert_float32_rgba8";
|
||||
case ShaderConvert::FLOAT32_TO_RGB8: return "ps_convert_float32_rgba8";
|
||||
case ShaderConvert::FLOAT16_TO_RGB5A1: return "ps_convert_float16_rgb5a1";
|
||||
case ShaderConvert::RGBA8_TO_FLOAT32: return "ps_convert_rgba8_float32";
|
||||
case ShaderConvert::RGBA8_TO_FLOAT24: return "ps_convert_rgba8_float24";
|
||||
case ShaderConvert::RGBA8_TO_FLOAT16: return "ps_convert_rgba8_float16";
|
||||
case ShaderConvert::RGB5A1_TO_FLOAT16: return "ps_convert_rgb5a1_float16";
|
||||
case ShaderConvert::RGBA8_TO_FLOAT32_BILN: return "ps_convert_rgba8_float32_biln";
|
||||
case ShaderConvert::RGBA8_TO_FLOAT24_BILN: return "ps_convert_rgba8_float24_biln";
|
||||
case ShaderConvert::RGBA8_TO_FLOAT16_BILN: return "ps_convert_rgba8_float16_biln";
|
||||
case ShaderConvert::RGB5A1_TO_FLOAT16_BILN: return "ps_convert_rgb5a1_float16_biln";
|
||||
case ShaderConvert::FLOAT32_DEPTH_TO_COLOR: return "ps_convert_float32_depth_to_color";
|
||||
case ShaderConvert::FLOAT32_COLOR_TO_DEPTH: return "ps_convert_float32_color_to_depth";
|
||||
case ShaderConvert::FLOAT32_TO_FLOAT24: return "ps_convert_float32_float24";
|
||||
case ShaderConvert::DEPTH32_TO_16_BITS: return "ps_convert_depth32_32bits";
|
||||
case ShaderConvert::DEPTH32_TO_32_BITS: return "ps_convert_depth32_32bits";
|
||||
case ShaderConvert::DEPTH32_TO_RGBA8: return "ps_convert_depth32_rgba8";
|
||||
case ShaderConvert::DEPTH32_TO_RGB8: return "ps_convert_depth32_rgba8";
|
||||
case ShaderConvert::DEPTH16_TO_RGB5A1: return "ps_convert_depth16_rgb5a1";
|
||||
case ShaderConvert::RGBA8_TO_DEPTH32: return "ps_convert_rgba8_depth32";
|
||||
case ShaderConvert::RGBA8_TO_DEPTH24: return "ps_convert_rgba8_depth24";
|
||||
case ShaderConvert::RGBA8_TO_DEPTH16: return "ps_convert_rgba8_depth16";
|
||||
case ShaderConvert::RGB5A1_TO_DEPTH16: return "ps_convert_rgb5a1_depth16";
|
||||
case ShaderConvert::DEPTH32_TO_DEPTH24: return "ps_convert_depth32_depth24";
|
||||
case ShaderConvert::DEPTH_COPY: return "ps_depth_copy";
|
||||
case ShaderConvert::DOWNSAMPLE_COPY: return "ps_downsample_copy";
|
||||
case ShaderConvert::RGBA_TO_8I: return "ps_convert_rgba_8i";
|
||||
@@ -77,18 +55,18 @@ const char* shaderName(ShaderConvert value)
|
||||
case ShaderConvert::CLUT_4: return "ps_convert_clut_4";
|
||||
case ShaderConvert::CLUT_8: return "ps_convert_clut_8";
|
||||
case ShaderConvert::YUV: return "ps_yuv";
|
||||
// clang-format on
|
||||
// clang-format on
|
||||
default:
|
||||
pxAssert(0);
|
||||
return "ShaderConvertUnknownShader";
|
||||
}
|
||||
}
|
||||
|
||||
const char* shaderName(PresentShader value)
|
||||
const char* ShaderEntryPoint(PresentShader value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
// clang-format off
|
||||
// clang-format off
|
||||
case PresentShader::COPY: return "ps_copy";
|
||||
case PresentShader::SCANLINE: return "ps_filter_scanlines";
|
||||
case PresentShader::DIAGONAL_FILTER: return "ps_filter_diagonal";
|
||||
@@ -97,13 +75,53 @@ const char* shaderName(PresentShader value)
|
||||
case PresentShader::LOTTES_FILTER: return "ps_filter_lottes";
|
||||
case PresentShader::SUPERSAMPLE_4xRGSS: return "ps_4x_rgss";
|
||||
case PresentShader::SUPERSAMPLE_AUTO: return "ps_automagical_supersampling";
|
||||
// clang-format on
|
||||
// clang-format on
|
||||
default:
|
||||
pxAssert(0);
|
||||
return "DisplayShaderUnknownShader";
|
||||
}
|
||||
}
|
||||
|
||||
const char* ShaderConvertName(ShaderConvert shader)
|
||||
{
|
||||
#define ENTRY(x) case ShaderConvert::x: return #x
|
||||
switch (shader)
|
||||
{
|
||||
ENTRY(COPY);
|
||||
ENTRY(DEPTH_COPY);
|
||||
ENTRY(RGB5A1_TO_16_BITS);
|
||||
ENTRY(DATM_1);
|
||||
ENTRY(DATM_0);
|
||||
ENTRY(DATM_1_RTA_CORRECTION);
|
||||
ENTRY(DATM_0_RTA_CORRECTION);
|
||||
ENTRY(COLCLIP_INIT);
|
||||
ENTRY(COLCLIP_RESOLVE);
|
||||
ENTRY(RTA_CORRECTION);
|
||||
ENTRY(RTA_DECORRECTION);
|
||||
ENTRY(TRANSPARENCY_FILTER);
|
||||
ENTRY(DEPTH32_TO_16_BITS);
|
||||
ENTRY(DEPTH32_TO_32_BITS);
|
||||
ENTRY(DEPTH32_TO_RGBA8);
|
||||
ENTRY(DEPTH32_TO_RGB8);
|
||||
ENTRY(DEPTH16_TO_RGB5A1);
|
||||
ENTRY(RGBA8_TO_DEPTH32);
|
||||
ENTRY(RGBA8_TO_DEPTH24);
|
||||
ENTRY(RGBA8_TO_DEPTH16);
|
||||
ENTRY(RGB5A1_TO_DEPTH16);
|
||||
ENTRY(DEPTH32_TO_DEPTH24);
|
||||
ENTRY(DOWNSAMPLE_COPY);
|
||||
ENTRY(RGBA_TO_8I);
|
||||
ENTRY(RGB5A1_TO_8I);
|
||||
ENTRY(CLUT_4);
|
||||
ENTRY(CLUT_8);
|
||||
ENTRY(YUV);
|
||||
case ShaderConvert::Count: break;
|
||||
}
|
||||
#undef ENTRY
|
||||
pxAssert(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
|
||||
enum class TextureLabel
|
||||
@@ -297,7 +315,7 @@ bool GSDevice::GetRequestedExclusiveFullscreenMode(u32* width, u32* height, floa
|
||||
|
||||
std::string GSDevice::GetFullscreenModeString(u32 width, u32 height, float refresh_rate)
|
||||
{
|
||||
return StringUtil::StdStringFromFormat("%u x %u @ %f hz", width, height, refresh_rate);
|
||||
return StringUtil::StdStringFromFormat("%u x %u @ %f Hz", width, height, refresh_rate);
|
||||
}
|
||||
|
||||
void GSDevice::GenerateExpansionIndexBuffer(void* buffer)
|
||||
@@ -675,6 +693,12 @@ void GSDevice::Recycle(GSTexture* t)
|
||||
|
||||
t->SetLastFrameUsed(m_frame);
|
||||
|
||||
t->ClearUnorderedAccess();
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
t->SetDebugName("");
|
||||
#endif
|
||||
|
||||
FastList<GSTexture*>& pool = m_pool[!t->IsTexture()];
|
||||
pool.push_front(t);
|
||||
m_pool_memory_usage += t->GetMemUsage();
|
||||
@@ -741,9 +765,33 @@ GSTexture* GSDevice::CreateRenderTarget(int w, int h, GSTexture::Format format,
|
||||
return FetchSurface(GSTexture::Type::RenderTarget, w, h, 1, format, clear, !prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateDepthStencil(int w, int h, GSTexture::Format format, bool clear, bool prefer_reuse)
|
||||
GSTexture* GSDevice::CreateRenderTarget(const GSVector2i& size, GSTexture::Format format, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return FetchSurface(GSTexture::Type::DepthStencil, w, h, 1, format, clear, !prefer_reuse);
|
||||
return FetchSurface(GSTexture::Type::RenderTarget, size.x, size.y, 1, format, clear, !prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateDepthStencil(int w, int h, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return FetchSurface(GSTexture::Type::DepthStencil, w, h, 1, GSTexture::Format::DepthStencil,
|
||||
clear, !prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateDepthStencil(const GSVector2i& size, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return FetchSurface(GSTexture::Type::DepthStencil, size.x, size.y, 1, GSTexture::Format::DepthStencil,
|
||||
clear, !prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateDepthColor(int w, int h, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return FetchSurface(GSTexture::Type::RenderTarget, w, h, 1, GSTexture::Format::DepthColor,
|
||||
clear, !prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateDepthColor(const GSVector2i& size, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return FetchSurface(GSTexture::Type::RenderTarget, size.x, size.y, 1, GSTexture::Format::DepthColor,
|
||||
clear, !prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateTexture(int w, int h, int mipmap_levels, GSTexture::Format format, bool prefer_reuse /* = false */)
|
||||
@@ -753,60 +801,102 @@ GSTexture* GSDevice::CreateTexture(int w, int h, int mipmap_levels, GSTexture::F
|
||||
return FetchSurface(GSTexture::Type::Texture, w, h, levels, format, false, m_features.prefer_new_textures && !prefer_reuse);
|
||||
}
|
||||
|
||||
void GSDevice::DoStretchRectWithAssertions(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear)
|
||||
GSTexture* GSDevice::CreateTexture(const GSVector2i& size, int mipmap_levels, GSTexture::Format format, bool prefer_reuse /* = false */)
|
||||
{
|
||||
pxAssert((dTex && dTex->IsDepthStencil()) == HasDepthOutput(shader));
|
||||
pxAssert(linear ? SupportsBilinear(shader) : SupportsNearest(shader));
|
||||
GL_INS("StretchRect(%d) {%d,%d} %dx%d -> {%d,%d) %dx%d", shader, int(sRect.left), int(sRect.top),
|
||||
return CreateTexture(size.x, size.y, mipmap_levels, format, prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateCompatible(GSTexture* tex, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return CreateCompatible(tex, tex->GetWidth(), tex->GetHeight(), clear, prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateCompatible(GSTexture* tex, const GSVector2i& size, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return CreateCompatible(tex, size.x, size.y, clear, prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateCompatible(GSTexture* tex, int w, int h, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return FetchSurface(tex->GetType(), w, h, 1, tex->GetFormat(), clear, !prefer_reuse);
|
||||
}
|
||||
|
||||
void GSDevice::DoStretchRectWithAssertions(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex,
|
||||
const GSVector4& dRect, ShaderConvertSelector shader, Filter filter)
|
||||
{
|
||||
pxAssert((dTex && dTex->IsDepthLike()) == shader.Float32Output());
|
||||
pxAssert(!(filter == Biln && shader.SupportsBilinear())); // Don't allow HW bilinear if SW bilinear is required.
|
||||
GL_INS("StretchRect(%s) {%d,%d} %dx%d -> {%d,%d) %dx%d", ShaderConvertName(shader.Shader()),
|
||||
int(sRect.left), int(sRect.top),
|
||||
int(sRect.right - sRect.left), int(sRect.bottom - sRect.top), int(dRect.left), int(dRect.top),
|
||||
int(dRect.right - dRect.left), int(dRect.bottom - dRect.top));
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, cms, shader, linear);
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, shader, filter);
|
||||
}
|
||||
|
||||
void GSDevice::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
bool red, bool green, bool blue, bool alpha, ShaderConvert shader)
|
||||
ShaderConvertSelector shader, Filter filter)
|
||||
{
|
||||
GSHWDrawConfig::ColorMaskSelector cms;
|
||||
|
||||
cms.wr = red;
|
||||
cms.wg = green;
|
||||
cms.wb = blue;
|
||||
cms.wa = alpha;
|
||||
|
||||
pxAssert(HasVariableWriteMask(shader));
|
||||
GL_INS("ColorCopy Red:%d Green:%d Blue:%d Alpha:%d", cms.wr, cms.wg, cms.wb, cms.wa);
|
||||
|
||||
DoStretchRectWithAssertions(sTex, sRect, dTex, dRect, cms, shader, false);
|
||||
DoStretchRectWithAssertions(sTex, sRect, dTex, dRect, shader, filter);
|
||||
}
|
||||
|
||||
void GSDevice::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
ShaderConvert shader, bool linear)
|
||||
void GSDevice::StretchRect(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, ShaderConvertSelector shader, Filter filter)
|
||||
{
|
||||
DoStretchRectWithAssertions(sTex, sRect, dTex, dRect, GSHWDrawConfig::ColorMaskSelector(ShaderConvertWriteMask(shader)), shader, linear);
|
||||
StretchRect(sTex, GSVector4(0, 0, 1, 1), dTex, dRect, shader, filter);
|
||||
}
|
||||
|
||||
void GSDevice::StretchRect(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, ShaderConvert shader, bool linear)
|
||||
void GSDevice::StretchRect(GSTexture* sTex, GSTexture* dTex, ShaderConvertSelector shader, Filter filter)
|
||||
{
|
||||
StretchRect(sTex, GSVector4(0, 0, 1, 1), dTex, dRect, shader, linear);
|
||||
StretchRect(sTex, dTex, GSVector4(dTex->GetRect()), shader, filter);
|
||||
}
|
||||
|
||||
void GSDevice::StretchRectAuto(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
Filter filter, u32 src_bpp, u32 dst_bpp)
|
||||
{
|
||||
ShaderConvertSelector shader = GetConvertShader(sTex, dTex, src_bpp, dst_bpp);
|
||||
if (shader.SupportsBilinear() && filter == Biln)
|
||||
{
|
||||
// Bilinear is emulated in the shader.
|
||||
shader.SetFilter(Biln);
|
||||
filter = Nearest;
|
||||
}
|
||||
StretchRect(sTex, sRect, dTex, dRect, shader, filter);
|
||||
}
|
||||
|
||||
void GSDevice::StretchRectAuto(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, Filter filter, u32 src_bpp, u32 dst_bpp)
|
||||
{
|
||||
StretchRectAuto(sTex, GSVector4(0, 0, 1, 1), dTex, dRect, filter, src_bpp, dst_bpp);
|
||||
}
|
||||
|
||||
void GSDevice::StretchRectAuto(GSTexture* sTex, GSTexture* dTex, Filter filter, u32 src_bpp, u32 dst_bpp)
|
||||
{
|
||||
StretchRectAuto(sTex, dTex, GSVector4(dTex->GetRect()), filter, src_bpp, dst_bpp);
|
||||
}
|
||||
|
||||
void GSDevice::StretchRectAutoMask(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
bool red, bool green, bool blue, bool alpha, u32 src_bpp, u32 dst_bpp)
|
||||
{
|
||||
StretchRect(sTex, sRect, dTex, dRect, GetConvertShaderMask(sTex, dTex, src_bpp, dst_bpp, red, green, blue, alpha), Nearest);
|
||||
}
|
||||
|
||||
void GSDevice::StretchRectAutoMask(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, bool red, bool green, bool blue, bool alpha, u32 src_bpp, u32 dst_bpp)
|
||||
{
|
||||
StretchRectAutoMask(sTex, GSVector4(0, 0, 1, 1), dTex, dRect, red, green, blue, alpha, src_bpp, dst_bpp);
|
||||
}
|
||||
|
||||
void GSDevice::StretchRectAutoMask(GSTexture* sTex, GSTexture* dTex, bool red, bool green, bool blue, bool alpha,
|
||||
u32 src_bpp, u32 dst_bpp)
|
||||
{
|
||||
StretchRectAutoMask(sTex, dTex, GSVector4(dTex->GetRect()), red, green, blue, alpha, src_bpp, dst_bpp);
|
||||
}
|
||||
|
||||
void GSDevice::DrawMultiStretchRects(
|
||||
const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader)
|
||||
const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader)
|
||||
{
|
||||
for (u32 i = 0; i < num_rects; i++)
|
||||
{
|
||||
const MultiStretchRect& sr = rects[i];
|
||||
pxAssert(HasVariableWriteMask(shader) || rects[0].wmask.wrgba == 0xf);
|
||||
if (rects[0].wmask.wrgba != 0xf)
|
||||
{
|
||||
g_gs_device->StretchRect(sr.src, sr.src_rect, dTex, sr.dst_rect, rects[0].wmask.wr,
|
||||
rects[0].wmask.wg, rects[0].wmask.wb, rects[0].wmask.wa, shader);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_gs_device->StretchRect(sr.src, sr.src_rect, dTex, sr.dst_rect, shader, sr.linear);
|
||||
}
|
||||
g_gs_device->StretchRect(sr.src, sr.src_rect, dTex, sr.dst_rect,
|
||||
shader.SetMask(rects[0].wmask.wrgba).SetFilter(sr.filter), sr.filter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -814,7 +904,7 @@ void GSDevice::SortMultiStretchRects(MultiStretchRect* rects, u32 num_rects)
|
||||
{
|
||||
// Depending on num_rects, insertion sort may be better here.
|
||||
std::sort(rects, rects + num_rects, [](const MultiStretchRect& lhs, const MultiStretchRect& rhs) {
|
||||
return lhs.src < rhs.src || lhs.linear < rhs.linear;
|
||||
return lhs.src < rhs.src || lhs.filter < rhs.filter;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -840,7 +930,7 @@ void GSDevice::ClearCurrent()
|
||||
void GSDevice::Merge(GSTexture* sTex[3], GSVector4* sRect, GSVector4* dRect, const GSVector2i& fs, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c)
|
||||
{
|
||||
if (ResizeRenderTarget(&m_merge, fs.x, fs.y, false, false))
|
||||
DoMerge(sTex, sRect, m_merge, dRect, PMODE, EXTBUF, c, GSConfig.PCRTCOffsets);
|
||||
DoMerge(sTex, sRect, m_merge, dRect, PMODE, EXTBUF, c, BilnIf(GSConfig.PCRTCOffsets));
|
||||
|
||||
m_current = m_merge;
|
||||
}
|
||||
@@ -851,7 +941,7 @@ void GSDevice::Interlace(const GSVector2i& ds, int field, int mode, float yoffse
|
||||
float offset = yoffset * static_cast<float>(field);
|
||||
offset = GSConfig.DisableInterlaceOffset ? 0.0f : offset;
|
||||
|
||||
auto do_interlace = [this](GSTexture* sTex, GSTexture* dTex, ShaderInterlace shader, bool linear, float yoffset, int bufIdx) {
|
||||
auto do_interlace = [this](GSTexture* sTex, GSTexture* dTex, ShaderInterlace shader, Filter filter, float yoffset, int bufIdx) {
|
||||
const GSVector2i ds_i = dTex->GetSize();
|
||||
const GSVector2 ds = GSVector2(static_cast<float>(ds_i.x), static_cast<float>(ds_i.y));
|
||||
|
||||
@@ -872,28 +962,28 @@ void GSDevice::Interlace(const GSVector2i& ds, int field, int mode, float yoffse
|
||||
GSVector4(static_cast<float>(bufIdx), 1.0f / ds.y, ds.y, MAD_SENSITIVITY)
|
||||
};
|
||||
|
||||
GL_PUSH("DoInterlace %dx%d Shader:%d Linear:%d", ds_i.x, ds_i.y, static_cast<int>(shader), linear);
|
||||
DoInterlace(sTex, sRect, dTex, dRect, shader, linear, cb);
|
||||
GL_PUSH("DoInterlace %dx%d Shader:%d Filter:%d", ds_i.x, ds_i.y, static_cast<int>(shader), filter);
|
||||
DoInterlace(sTex, sRect, dTex, dRect, shader, filter, cb);
|
||||
};
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case 0: // Weave
|
||||
ResizeRenderTarget(&m_weavebob, ds.x, ds.y, true, false);
|
||||
do_interlace(m_merge, m_weavebob, ShaderInterlace::WEAVE, false, offset, field);
|
||||
do_interlace(m_merge, m_weavebob, ShaderInterlace::WEAVE, Nearest, offset, field);
|
||||
m_current = m_weavebob;
|
||||
break;
|
||||
case 1: // Bob
|
||||
// Field is reversed here as we are countering the bounce.
|
||||
ResizeRenderTarget(&m_weavebob, ds.x, ds.y, true, false);
|
||||
do_interlace(m_merge, m_weavebob, ShaderInterlace::BOB, true, yoffset * (1 - field), 0);
|
||||
do_interlace(m_merge, m_weavebob, ShaderInterlace::BOB, Biln, yoffset * (1 - field), 0);
|
||||
m_current = m_weavebob;
|
||||
break;
|
||||
case 2: // Blend
|
||||
ResizeRenderTarget(&m_weavebob, ds.x, ds.y, true, false);
|
||||
do_interlace(m_merge, m_weavebob, ShaderInterlace::WEAVE, false, offset, field);
|
||||
do_interlace(m_merge, m_weavebob, ShaderInterlace::WEAVE, Nearest, offset, field);
|
||||
ResizeRenderTarget(&m_blend, ds.x, ds.y, true, false);
|
||||
do_interlace(m_weavebob, m_blend, ShaderInterlace::BLEND, false, 0, 0);
|
||||
do_interlace(m_weavebob, m_blend, ShaderInterlace::BLEND, Biln, 0, 0);
|
||||
m_current = m_blend;
|
||||
break;
|
||||
case 3: // FastMAD Motion Adaptive Deinterlacing
|
||||
@@ -902,9 +992,9 @@ void GSDevice::Interlace(const GSVector2i& ds, int field, int mode, float yoffse
|
||||
bufIdx |= field;
|
||||
bufIdx &= 3;
|
||||
ResizeRenderTarget(&m_mad, ds.x, ds.y * 2.0f, true, false);
|
||||
do_interlace(m_merge, m_mad, ShaderInterlace::MAD_BUFFER, false, offset, bufIdx);
|
||||
do_interlace(m_merge, m_mad, ShaderInterlace::MAD_BUFFER, Nearest, offset, bufIdx);
|
||||
ResizeRenderTarget(&m_weavebob, ds.x, ds.y, true, false);
|
||||
do_interlace(m_mad, m_weavebob, ShaderInterlace::MAD_RECONSTRUCT, false, 0, bufIdx);
|
||||
do_interlace(m_mad, m_weavebob, ShaderInterlace::MAD_RECONSTRUCT, Nearest, 0, bufIdx);
|
||||
m_current = m_weavebob;
|
||||
break;
|
||||
default:
|
||||
@@ -961,7 +1051,7 @@ void GSDevice::Resize(int width, int height)
|
||||
{
|
||||
const GSVector4 sRect(0, 0, 1, 1);
|
||||
const GSVector4 dRect(0, 0, s.x, s.y);
|
||||
StretchRect(m_current, sRect, dTex, dRect, ShaderConvert::COPY, false);
|
||||
StretchRectAuto(m_current, sRect, dTex, dRect, Nearest);
|
||||
m_current = dTex;
|
||||
}
|
||||
}
|
||||
@@ -992,7 +1082,7 @@ bool GSDevice::ResizeRenderTarget(GSTexture** t, int w, int h, bool preserve_con
|
||||
{
|
||||
constexpr GSVector4 sRect = GSVector4::cxpr(0, 0, 1, 1);
|
||||
const GSVector4 dRect = GSVector4(orig_tex->GetRect());
|
||||
StretchRect(orig_tex, sRect, new_tex, dRect, ShaderConvert::COPY, true);
|
||||
StretchRect(orig_tex, sRect, new_tex, dRect, ShaderConvert::COPY, Biln);
|
||||
}
|
||||
|
||||
if (orig_tex)
|
||||
@@ -1012,10 +1102,10 @@ void GSDevice::BeginDSAsRT(GSTexture* ds, const GSVector4i& drawarea)
|
||||
// Create a temporary RT and copy the area needed for the draw.
|
||||
const int w = ds->GetWidth();
|
||||
const int h = ds->GetHeight();
|
||||
m_ds_as_rt = g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::Float32, false, true);
|
||||
m_ds_as_rt = g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::DepthColor, false, true);
|
||||
const GSVector4 dRect(drawarea);
|
||||
const GSVector4 sRect(dRect.x / w, dRect.y / h, dRect.z / w, dRect.w / h);
|
||||
StretchRect(ds, sRect, m_ds_as_rt, dRect, ShaderConvert::FLOAT32_DEPTH_TO_COLOR, false);
|
||||
StretchRectAuto(ds, sRect, m_ds_as_rt, dRect, Nearest);
|
||||
}
|
||||
|
||||
void GSDevice::EndDSAsRT()
|
||||
@@ -1414,9 +1504,9 @@ static const char* GetSetDATMName(SetDATM datm)
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
static const char* GetPSAA1Name(u32 aa1)
|
||||
static const char* GetPSAA1Name(GSHWDrawConfig::PS_AA1 aa1)
|
||||
{
|
||||
switch (static_cast<GSHWDrawConfig::PS_AA1>(aa1))
|
||||
switch (aa1)
|
||||
{
|
||||
case GSHWDrawConfig::PS_AA1::NONE: return "NONE";
|
||||
case GSHWDrawConfig::PS_AA1::LINE: return "LINE";
|
||||
@@ -1437,6 +1527,17 @@ static const char* GetTexHazardName(u32 tex_hazard)
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
static const char* GetPSROVDepthname(GSHWDrawConfig::PS_ROV_DEPTH rov_depth)
|
||||
{
|
||||
switch (rov_depth)
|
||||
{
|
||||
case GSHWDrawConfig::PS_ROV_DEPTH::NONE: return "NONE";
|
||||
case GSHWDrawConfig::PS_ROV_DEPTH::READ_ONLY: return "READ_ONLY";
|
||||
case GSHWDrawConfig::PS_ROV_DEPTH::READ_WRITE: return "READ_WRITE";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
static void DumpPSSelector(DrawConfigWriter& out, const GSHWDrawConfig::PSSelector& ps)
|
||||
{
|
||||
out.WriteLn("aem_fmt: {}", ps.aem_fmt);
|
||||
@@ -1492,9 +1593,13 @@ static void DumpPSSelector(DrawConfigWriter& out, const GSHWDrawConfig::PSSelect
|
||||
out.WriteLn("point_sampler: {}", ps.point_sampler);
|
||||
out.WriteLn("region_rect: {}", ps.region_rect);
|
||||
out.WriteLn("scanmsk: {} ({})", GSUtil::GetSCANMSKName(ps.scanmsk), ps.scanmsk);
|
||||
out.WriteLn("aa1: {} ({})", static_cast<u32>(ps.aa1), GetPSAA1Name(static_cast<u32>(ps.aa1)));
|
||||
out.WriteLn("aa1: {} ({})", GetPSAA1Name(ps.aa1), static_cast<u32>(ps.aa1));
|
||||
out.WriteLn("abe: {}", static_cast<u32>(ps.abe));
|
||||
out.WriteLn("sw_aniso: {}", ps.sw_aniso);
|
||||
out.WriteLn("rov_color: {}", ps.rov_color);
|
||||
out.WriteLn("rov_depth: {} ({})", GetPSROVDepthname(ps.rov_depth), static_cast<u32>(ps.rov_depth));
|
||||
out.WriteLn("ztst: {} ({})", GSUtil::GetZTSTName(ps.ztst), static_cast<u32>(ps.ztst));
|
||||
out.WriteLn("zfloor: {}", static_cast<u32>(ps.zfloor));
|
||||
}
|
||||
|
||||
static void DumpVSSelector(DrawConfigWriter& out, const GSHWDrawConfig::VSSelector& vs)
|
||||
@@ -1618,6 +1723,8 @@ static void DumpConfig(DrawConfigWriter& out, const GSHWDrawConfig& conf,
|
||||
out.WriteLn("topology: {} ({})", GetTopologyName(conf.topology), static_cast<u32>(conf.topology));
|
||||
out.WriteLn("require_one_barrier: {}", conf.require_one_barrier);
|
||||
out.WriteLn("require_full_barrier: {}", conf.require_full_barrier);
|
||||
DumpVector4(out, "drawarea", conf.drawarea);
|
||||
DumpVector4(out, "samplearea", conf.samplearea);
|
||||
out.WriteLn("tex_hazard: {}", GetTexHazardName(conf.tex_hazard));
|
||||
|
||||
out.WriteLn("destination_alpha: {} ({})", GetDestinationAlphaModeName(conf.destination_alpha), static_cast<u32>(conf.destination_alpha));
|
||||
@@ -1691,6 +1798,75 @@ void GSHWDrawConfig::DumpConfig(const std::string& path, const GSHWDrawConfig& c
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr u32 NUM_REMAP_INPUTS = static_cast<u32>(ShaderConvert::Count) * 4;
|
||||
|
||||
static constexpr ShaderConvertSelector GetRemappedShader(u32 idx)
|
||||
{
|
||||
ShaderConvert convert = static_cast<ShaderConvert>(idx >> 2);
|
||||
bool depth_out = (idx >> 0) & 1;
|
||||
Filter filter = static_cast<Filter>((idx >> 1) & 1);
|
||||
return ShaderConvertSelector(convert, 0xf, depth_out, filter);
|
||||
}
|
||||
|
||||
static constexpr bool RemapIndexIsValid(u32 idx)
|
||||
{
|
||||
ShaderConvert convert = static_cast<ShaderConvert>(idx >> 2);
|
||||
bool depth_out = (idx >> 0) & 1;
|
||||
Filter filter = static_cast<Filter>((idx >> 1) & 1);
|
||||
if (HasVariableWriteMask(convert) && !depth_out && filter == Nearest)
|
||||
return false; // Handled as variable write mask
|
||||
if (depth_out && !HasFloat32Output(convert))
|
||||
return false;
|
||||
if (filter == Biln && !SupportsBilinear(convert))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static constexpr u32 CalcNumRemappedShaders()
|
||||
{
|
||||
u32 num = 0;
|
||||
for (u32 i = 0; i < NUM_REMAP_INPUTS; i++)
|
||||
num += RemapIndexIsValid(i);
|
||||
return num;
|
||||
}
|
||||
|
||||
static constexpr u32 NUM_REMAPPED_SHADERS = CalcNumRemappedShaders();
|
||||
static constexpr u32 NUM_TOTAL_SHADERS = NUM_REMAPPED_SHADERS +
|
||||
16 * ShaderConvertSelector::NUM_VARIABLE_WRITE_MASK_SHADERS;
|
||||
static_assert(NUM_REMAPPED_SHADERS <= 256); // We use u8 for the remap indices.
|
||||
|
||||
static constexpr std::array<u8, NUM_REMAP_INPUTS> GenRemapArray()
|
||||
{
|
||||
std::array<u8, NUM_REMAP_INPUTS> out{};
|
||||
u8 out_idx = 0;
|
||||
const u8 invalid = 0xff;
|
||||
for (u32 i = 0; i < NUM_REMAP_INPUTS; i++)
|
||||
out[i] = RemapIndexIsValid(i) ? out_idx++ : invalid;
|
||||
return out;
|
||||
}
|
||||
|
||||
static constexpr std::array<ShaderConvertSelector, NUM_TOTAL_SHADERS> GetPackedShaders()
|
||||
{
|
||||
std::array<ShaderConvertSelector, NUM_TOTAL_SHADERS> out{};
|
||||
u32 append_idx = 0;
|
||||
for (u32 i = 0; i < NUM_REMAP_INPUTS; i++)
|
||||
{
|
||||
if (RemapIndexIsValid(i))
|
||||
out[append_idx++] = GetRemappedShader(i);
|
||||
}
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
out[append_idx++] = ShaderConvertSelector(ShaderConvert::COPY, i);
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
out[append_idx++] = ShaderConvertSelector(ShaderConvert::RTA_CORRECTION, i);
|
||||
return out;
|
||||
}
|
||||
|
||||
constinit const u32 ShaderConvertSelector::NUM_REMAPPED_SHADERS = ::NUM_REMAPPED_SHADERS;
|
||||
constinit const u32 ShaderConvertSelector::NUM_TOTAL_SHADERS = ::NUM_TOTAL_SHADERS;
|
||||
constinit const std::array<u8, NUM_REMAP_INPUTS> ShaderConvertSelector::INDEX_REMAP = GenRemapArray();
|
||||
static constexpr auto PACKED_SHADERS = GetPackedShaders();
|
||||
const std::span<const ShaderConvertSelector> ShaderConvertSelector::SHADERS = PACKED_SHADERS;
|
||||
|
||||
// clang-format off
|
||||
|
||||
// Maps PS2 blend modes to our best approximation of them with PC hardware
|
||||
|
||||
@@ -13,11 +13,27 @@
|
||||
#include "GS/GSAlignedClass.h"
|
||||
#include "GS/GSExtra.h"
|
||||
#include <array>
|
||||
#include <span>
|
||||
|
||||
enum class Filter
|
||||
{
|
||||
Nearest = 0,
|
||||
Biln = 1,
|
||||
};
|
||||
|
||||
static inline constexpr Filter Nearest = Filter::Nearest;
|
||||
static inline constexpr Filter Biln = Filter::Biln;
|
||||
|
||||
static inline constexpr Filter BilnIf(bool biln)
|
||||
{
|
||||
return biln ? Biln : Nearest;
|
||||
}
|
||||
|
||||
enum class ShaderConvert
|
||||
{
|
||||
COPY = 0,
|
||||
RGBA8_TO_16_BITS,
|
||||
DEPTH_COPY,
|
||||
RGB5A1_TO_16_BITS,
|
||||
DATM_1,
|
||||
DATM_0,
|
||||
DATM_1_RTA_CORRECTION,
|
||||
@@ -27,23 +43,16 @@ enum class ShaderConvert
|
||||
RTA_CORRECTION,
|
||||
RTA_DECORRECTION,
|
||||
TRANSPARENCY_FILTER,
|
||||
FLOAT32_TO_16_BITS,
|
||||
FLOAT32_TO_32_BITS,
|
||||
FLOAT32_TO_RGBA8,
|
||||
FLOAT32_TO_RGB8,
|
||||
FLOAT16_TO_RGB5A1,
|
||||
RGBA8_TO_FLOAT32,
|
||||
RGBA8_TO_FLOAT24,
|
||||
RGBA8_TO_FLOAT16,
|
||||
RGB5A1_TO_FLOAT16,
|
||||
RGBA8_TO_FLOAT32_BILN,
|
||||
RGBA8_TO_FLOAT24_BILN,
|
||||
RGBA8_TO_FLOAT16_BILN,
|
||||
RGB5A1_TO_FLOAT16_BILN,
|
||||
FLOAT32_DEPTH_TO_COLOR,
|
||||
FLOAT32_COLOR_TO_DEPTH,
|
||||
FLOAT32_TO_FLOAT24,
|
||||
DEPTH_COPY,
|
||||
DEPTH32_TO_16_BITS,
|
||||
DEPTH32_TO_32_BITS,
|
||||
DEPTH32_TO_RGBA8,
|
||||
DEPTH32_TO_RGB8,
|
||||
DEPTH16_TO_RGB5A1,
|
||||
RGBA8_TO_DEPTH32,
|
||||
RGBA8_TO_DEPTH24,
|
||||
RGBA8_TO_DEPTH16,
|
||||
RGB5A1_TO_DEPTH16,
|
||||
DEPTH32_TO_DEPTH24,
|
||||
DOWNSAMPLE_COPY,
|
||||
RGBA_TO_8I,
|
||||
RGB5A1_TO_8I,
|
||||
@@ -53,6 +62,19 @@ enum class ShaderConvert
|
||||
Count
|
||||
};
|
||||
|
||||
enum class PresentShader
|
||||
{
|
||||
COPY = 0,
|
||||
SCANLINE,
|
||||
DIAGONAL_FILTER,
|
||||
TRIANGULAR_FILTER,
|
||||
COMPLEX_FILTER,
|
||||
LOTTES_FILTER,
|
||||
SUPERSAMPLE_4xRGSS,
|
||||
SUPERSAMPLE_AUTO,
|
||||
Count
|
||||
};
|
||||
|
||||
enum class SetDATM : u8
|
||||
{
|
||||
DATM0 = 0U,
|
||||
@@ -71,7 +93,7 @@ enum class ShaderInterlace
|
||||
Count
|
||||
};
|
||||
|
||||
static inline bool HasVariableWriteMask(ShaderConvert shader)
|
||||
static inline constexpr bool HasVariableWriteMask(ShaderConvert shader)
|
||||
{
|
||||
switch (shader)
|
||||
{
|
||||
@@ -83,37 +105,64 @@ static inline bool HasVariableWriteMask(ShaderConvert shader)
|
||||
}
|
||||
}
|
||||
|
||||
static inline int GetShaderIndexForMask(ShaderConvert shader, int mask)
|
||||
{
|
||||
pxAssert(HasVariableWriteMask(shader));
|
||||
int index = mask;
|
||||
if (shader == ShaderConvert::RTA_CORRECTION)
|
||||
index |= 1 << 4;
|
||||
return index;
|
||||
}
|
||||
|
||||
static inline bool HasDepthOutput(ShaderConvert shader)
|
||||
static inline constexpr bool HasColorOutput(ShaderConvert shader)
|
||||
{
|
||||
switch (shader)
|
||||
{
|
||||
case ShaderConvert::RGBA8_TO_FLOAT32:
|
||||
case ShaderConvert::RGBA8_TO_FLOAT24:
|
||||
case ShaderConvert::RGBA8_TO_FLOAT16:
|
||||
case ShaderConvert::RGB5A1_TO_FLOAT16:
|
||||
case ShaderConvert::RGBA8_TO_FLOAT32_BILN:
|
||||
case ShaderConvert::RGBA8_TO_FLOAT24_BILN:
|
||||
case ShaderConvert::RGBA8_TO_FLOAT16_BILN:
|
||||
case ShaderConvert::RGB5A1_TO_FLOAT16_BILN:
|
||||
case ShaderConvert::FLOAT32_COLOR_TO_DEPTH:
|
||||
case ShaderConvert::FLOAT32_TO_FLOAT24:
|
||||
case ShaderConvert::DEPTH_COPY:
|
||||
case ShaderConvert::COPY:
|
||||
case ShaderConvert::RTA_CORRECTION:
|
||||
case ShaderConvert::RTA_DECORRECTION:
|
||||
case ShaderConvert::TRANSPARENCY_FILTER:
|
||||
case ShaderConvert::DEPTH32_TO_RGBA8:
|
||||
case ShaderConvert::DEPTH32_TO_RGB8:
|
||||
case ShaderConvert::DEPTH16_TO_RGB5A1:
|
||||
case ShaderConvert::DOWNSAMPLE_COPY:
|
||||
case ShaderConvert::RGBA_TO_8I:
|
||||
case ShaderConvert::RGB5A1_TO_8I:
|
||||
case ShaderConvert::CLUT_4:
|
||||
case ShaderConvert::CLUT_8:
|
||||
case ShaderConvert::YUV:
|
||||
case ShaderConvert::COLCLIP_RESOLVE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool HasStencilOutput(ShaderConvert shader)
|
||||
static inline constexpr bool HasFloat32Output(ShaderConvert shader)
|
||||
{
|
||||
switch (shader)
|
||||
{
|
||||
case ShaderConvert::RGBA8_TO_DEPTH32:
|
||||
case ShaderConvert::RGBA8_TO_DEPTH24:
|
||||
case ShaderConvert::RGBA8_TO_DEPTH16:
|
||||
case ShaderConvert::RGB5A1_TO_DEPTH16:
|
||||
case ShaderConvert::DEPTH_COPY:
|
||||
case ShaderConvert::DEPTH32_TO_DEPTH24:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline constexpr bool HasFloat32Input(ShaderConvert shader)
|
||||
{
|
||||
switch (shader)
|
||||
{
|
||||
case ShaderConvert::DEPTH_COPY:
|
||||
case ShaderConvert::DEPTH32_TO_16_BITS:
|
||||
case ShaderConvert::DEPTH32_TO_32_BITS:
|
||||
case ShaderConvert::DEPTH32_TO_RGBA8:
|
||||
case ShaderConvert::DEPTH32_TO_RGB8:
|
||||
case ShaderConvert::DEPTH16_TO_RGB5A1:
|
||||
case ShaderConvert::DEPTH32_TO_DEPTH24:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline constexpr bool IsDATMConvertShader(ShaderConvert shader)
|
||||
{
|
||||
switch (shader)
|
||||
{
|
||||
@@ -127,63 +176,375 @@ static inline bool HasStencilOutput(ShaderConvert shader)
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool SupportsNearest(ShaderConvert shader)
|
||||
static inline constexpr bool HasStencilOutput(ShaderConvert shader)
|
||||
{
|
||||
return IsDATMConvertShader(shader);
|
||||
}
|
||||
|
||||
static inline constexpr int IntegerOutputBpp(ShaderConvert shader)
|
||||
{
|
||||
switch (shader)
|
||||
{
|
||||
case ShaderConvert::RGBA8_TO_FLOAT32_BILN:
|
||||
case ShaderConvert::RGBA8_TO_FLOAT24_BILN:
|
||||
case ShaderConvert::RGBA8_TO_FLOAT16_BILN:
|
||||
case ShaderConvert::RGB5A1_TO_FLOAT16_BILN:
|
||||
return false;
|
||||
case ShaderConvert::DEPTH32_TO_32_BITS:
|
||||
return 32;
|
||||
case ShaderConvert::DEPTH32_TO_16_BITS:
|
||||
case ShaderConvert::RGB5A1_TO_16_BITS:
|
||||
return 16;
|
||||
default:
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool SupportsBilinear(ShaderConvert shader)
|
||||
static inline constexpr bool HasColorClipOutput(ShaderConvert shader)
|
||||
{
|
||||
return (shader == ShaderConvert::COLCLIP_INIT);
|
||||
}
|
||||
|
||||
static inline constexpr bool SupportsBilinear(ShaderConvert shader)
|
||||
{
|
||||
switch (shader)
|
||||
{
|
||||
case ShaderConvert::RGBA8_TO_FLOAT32:
|
||||
case ShaderConvert::RGBA8_TO_FLOAT24:
|
||||
case ShaderConvert::RGBA8_TO_FLOAT16:
|
||||
case ShaderConvert::RGB5A1_TO_FLOAT16:
|
||||
return false;
|
||||
default:
|
||||
case ShaderConvert::RGBA8_TO_DEPTH32:
|
||||
case ShaderConvert::RGBA8_TO_DEPTH24:
|
||||
case ShaderConvert::RGBA8_TO_DEPTH16:
|
||||
case ShaderConvert::RGB5A1_TO_DEPTH16:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u32 ShaderConvertWriteMask(ShaderConvert shader)
|
||||
static inline constexpr u32 ShaderConvertWriteMask(ShaderConvert shader)
|
||||
{
|
||||
switch (shader)
|
||||
{
|
||||
case ShaderConvert::FLOAT32_TO_RGB8:
|
||||
case ShaderConvert::DEPTH32_TO_RGB8:
|
||||
return 0x7;
|
||||
default:
|
||||
return 0xf;
|
||||
}
|
||||
}
|
||||
|
||||
enum class PresentShader
|
||||
static inline constexpr int GetShaderIndexForMask(ShaderConvert shader, int mask)
|
||||
{
|
||||
COPY = 0,
|
||||
SCANLINE,
|
||||
DIAGONAL_FILTER,
|
||||
TRIANGULAR_FILTER,
|
||||
COMPLEX_FILTER,
|
||||
LOTTES_FILTER,
|
||||
SUPERSAMPLE_4xRGSS,
|
||||
SUPERSAMPLE_AUTO,
|
||||
Count
|
||||
pxAssert(HasVariableWriteMask(shader));
|
||||
int index = mask;
|
||||
if (shader == ShaderConvert::RTA_CORRECTION)
|
||||
index |= 1 << 4;
|
||||
return index;
|
||||
}
|
||||
|
||||
static inline constexpr ShaderConvert SetDATMShader(SetDATM datm)
|
||||
{
|
||||
switch (datm)
|
||||
{
|
||||
case SetDATM::DATM1_RTA_CORRECTION:
|
||||
return ShaderConvert::DATM_1_RTA_CORRECTION;
|
||||
case SetDATM::DATM0_RTA_CORRECTION:
|
||||
return ShaderConvert::DATM_0_RTA_CORRECTION;
|
||||
case SetDATM::DATM1:
|
||||
return ShaderConvert::DATM_1;
|
||||
case SetDATM::DATM0:
|
||||
default:
|
||||
return ShaderConvert::DATM_0;
|
||||
}
|
||||
}
|
||||
|
||||
const char* ShaderEntryPoint(ShaderConvert value);
|
||||
const char* ShaderEntryPoint(PresentShader value);
|
||||
const char* ShaderConvertName(ShaderConvert shader);
|
||||
|
||||
class ShaderConvertSelector
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 shader : 8; // Main shader
|
||||
u32 mask : 8; // Variable color mask
|
||||
u32 depth_out : 1; // Depth texture output
|
||||
u32 filter : 1; // Shader filter (HW filter is specified separately)
|
||||
};
|
||||
|
||||
u32 key;
|
||||
} fields;
|
||||
|
||||
static_assert(sizeof(fields) == 4);
|
||||
|
||||
public:
|
||||
constexpr ShaderConvertSelector(ShaderConvert shader = ShaderConvert::COPY, u8 mask = 0xf,
|
||||
bool depth_out = false, Filter filter = Filter::Nearest)
|
||||
: fields { static_cast<u32>(shader) }
|
||||
{
|
||||
*this = SetMask(mask).SetDepthOutput(depth_out).SetFilter(filter);
|
||||
}
|
||||
|
||||
constexpr ShaderConvert Shader() const
|
||||
{
|
||||
return static_cast<ShaderConvert>(fields.shader);
|
||||
}
|
||||
|
||||
constexpr u8 Mask() const
|
||||
{
|
||||
return fields.mask;
|
||||
}
|
||||
|
||||
constexpr u8 DefaultMask() const
|
||||
{
|
||||
return ShaderConvertWriteMask(Shader());
|
||||
}
|
||||
|
||||
constexpr Filter GetFilter() const
|
||||
{
|
||||
return static_cast<Filter>(fields.filter);
|
||||
}
|
||||
|
||||
constexpr bool Biln() const
|
||||
{
|
||||
return GetFilter() == Filter::Biln;
|
||||
}
|
||||
|
||||
constexpr bool Nearest() const
|
||||
{
|
||||
return GetFilter() == Filter::Nearest;
|
||||
}
|
||||
|
||||
constexpr bool SupportsBilinear() const
|
||||
{
|
||||
return ::SupportsBilinear(Shader());
|
||||
}
|
||||
|
||||
constexpr bool ColorOutput() const
|
||||
{
|
||||
return HasColorOutput(Shader());
|
||||
}
|
||||
|
||||
constexpr bool DepthOutput() const
|
||||
{
|
||||
return fields.depth_out;
|
||||
}
|
||||
|
||||
constexpr bool StencilOutput() const
|
||||
{
|
||||
return HasStencilOutput(Shader());
|
||||
}
|
||||
|
||||
constexpr bool DATMConvertShader() const
|
||||
{
|
||||
return IsDATMConvertShader(Shader());
|
||||
}
|
||||
|
||||
constexpr bool Float32Output() const
|
||||
{
|
||||
return HasFloat32Output(Shader());
|
||||
}
|
||||
|
||||
constexpr bool Float32Input() const
|
||||
{
|
||||
return HasFloat32Input(Shader());
|
||||
}
|
||||
|
||||
constexpr int IntegerOutputBpp() const
|
||||
{
|
||||
return ::IntegerOutputBpp(Shader());
|
||||
}
|
||||
|
||||
constexpr bool VariableWriteMask() const
|
||||
{
|
||||
return HasVariableWriteMask(Shader());
|
||||
}
|
||||
|
||||
constexpr bool ColorClipOutput() const
|
||||
{
|
||||
return HasColorClipOutput(Shader());
|
||||
}
|
||||
|
||||
const char* Name() const
|
||||
{
|
||||
return ShaderConvertName(Shader());
|
||||
}
|
||||
|
||||
const char* EntryPoint() const
|
||||
{
|
||||
return ShaderEntryPoint(Shader());
|
||||
}
|
||||
|
||||
constexpr ShaderConvertSelector SetMask(u8 mask = 0xf) const
|
||||
{
|
||||
ShaderConvertSelector tmp = *this;
|
||||
tmp.fields.mask = VariableWriteMask() ? (mask & 0xf) : DefaultMask();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
constexpr ShaderConvertSelector SetMask(bool wr, bool wg, bool wb, bool wa) const
|
||||
{
|
||||
return SetMask((wr ? 1 : 0) | (wg ? 2 : 0) | (wb ? 4 : 0) | (wa ? 8 : 0));
|
||||
}
|
||||
|
||||
constexpr ShaderConvertSelector SetDepthOutput(bool depth_out) const
|
||||
{
|
||||
ShaderConvertSelector tmp = *this;
|
||||
tmp.fields.depth_out = Float32Output() && depth_out;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
constexpr ShaderConvertSelector SetFilter(Filter filter) const
|
||||
{
|
||||
ShaderConvertSelector tmp = *this;
|
||||
tmp.fields.filter = static_cast<u32>(SupportsBilinear() ? filter : Filter::Nearest);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
GSTexture::Format OutputFormat() const
|
||||
{
|
||||
if (DepthOutput())
|
||||
return GSTexture::Format::DepthStencil;
|
||||
else if (int bpp = IntegerOutputBpp())
|
||||
return bpp == 16 ? GSTexture::Format::UInt16 : GSTexture::Format::UInt32;
|
||||
else if (Float32Output())
|
||||
return GSTexture::Format::DepthColor;
|
||||
else if (ColorOutput())
|
||||
return GSTexture::Format::Color;
|
||||
else if (ColorClipOutput())
|
||||
return GSTexture::Format::ColorClip;
|
||||
else
|
||||
return GSTexture::Format::Invalid;
|
||||
}
|
||||
|
||||
private:
|
||||
// Helper variables for packing valid shaders into a contiguous range.
|
||||
static const std::span<const ShaderConvertSelector> SHADERS;
|
||||
static const std::array<u8, static_cast<u32>(ShaderConvert::Count) * 4> INDEX_REMAP;
|
||||
static const u32 NUM_REMAPPED_SHADERS;
|
||||
|
||||
public:
|
||||
static constexpr u32 NUM_VARIABLE_WRITE_MASK_SHADERS = 2;
|
||||
static const u32 NUM_TOTAL_SHADERS;
|
||||
|
||||
u32 Index() const
|
||||
{
|
||||
if (VariableWriteMask() && !fields.depth_out && Nearest())
|
||||
return GetShaderIndexForMask(Shader(), fields.mask) + NUM_REMAPPED_SHADERS;
|
||||
u32 remapped = INDEX_REMAP[(fields.depth_out << 0) +
|
||||
(fields.filter << 1) +
|
||||
(fields.shader << 2)];
|
||||
pxAssert(remapped < NUM_REMAPPED_SHADERS);
|
||||
return remapped;
|
||||
}
|
||||
|
||||
// Inverse of Index()
|
||||
static ShaderConvertSelector Get(u32 index)
|
||||
{
|
||||
return SHADERS[index];
|
||||
}
|
||||
};
|
||||
|
||||
/// Get the name of a shader
|
||||
/// (Can't put methods on an enum class)
|
||||
int SetDATMShader(SetDATM datm);
|
||||
const char* shaderName(ShaderConvert value);
|
||||
const char* shaderName(PresentShader value);
|
||||
static inline ShaderConvertSelector GetConvertShader(GSTexture::Format src, GSTexture::Format dst,
|
||||
u32 src_bpp = 32, u32 dst_bpp = 32, u8 mask = 0xf)
|
||||
{
|
||||
ShaderConvert shader = static_cast<ShaderConvert>(-1);
|
||||
switch (src)
|
||||
{
|
||||
case GSTexture::Format::Color:
|
||||
switch (dst)
|
||||
{
|
||||
case GSTexture::Format::Color:
|
||||
pxAssert(src_bpp == 32 && dst_bpp == 32);
|
||||
shader = ShaderConvert::COPY; // bpp is handled by mask
|
||||
break;
|
||||
case GSTexture::Format::DepthColor:
|
||||
case GSTexture::Format::DepthStencil:
|
||||
switch (dst_bpp)
|
||||
{
|
||||
case 32:
|
||||
shader = ShaderConvert::RGBA8_TO_DEPTH32;
|
||||
break;
|
||||
case 24:
|
||||
shader = ShaderConvert::RGBA8_TO_DEPTH24;
|
||||
break;
|
||||
case 16:
|
||||
pxAssert(src_bpp == 16 || src_bpp == 32);
|
||||
shader = src_bpp == 16 ? ShaderConvert::RGB5A1_TO_DEPTH16 :
|
||||
ShaderConvert::RGBA8_TO_DEPTH16;
|
||||
break;
|
||||
default:
|
||||
pxAssert(false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pxAssert(false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GSTexture::Format::DepthColor:
|
||||
case GSTexture::Format::DepthStencil:
|
||||
switch (dst)
|
||||
{
|
||||
case GSTexture::Format::Color:
|
||||
switch (dst_bpp)
|
||||
{
|
||||
case 32:
|
||||
shader = ShaderConvert::DEPTH32_TO_RGBA8;
|
||||
break;
|
||||
case 24:
|
||||
shader = ShaderConvert::DEPTH32_TO_RGB8;
|
||||
break;
|
||||
case 16:
|
||||
pxAssert(src_bpp == 16);
|
||||
shader = ShaderConvert::DEPTH16_TO_RGB5A1;
|
||||
break;
|
||||
default:
|
||||
pxAssert(false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GSTexture::Format::DepthColor:
|
||||
case GSTexture::Format::DepthStencil:
|
||||
switch (dst_bpp)
|
||||
{
|
||||
case 32:
|
||||
pxAssert(src_bpp == 32);
|
||||
shader = ShaderConvert::DEPTH_COPY;
|
||||
break;
|
||||
case 24:
|
||||
pxAssert(src_bpp == 32);
|
||||
shader = ShaderConvert::DEPTH32_TO_DEPTH24;
|
||||
break;
|
||||
default:
|
||||
pxAssert(false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pxAssert(false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pxAssert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return ShaderConvertSelector(shader, mask, dst == GSTexture::Format::DepthStencil);
|
||||
}
|
||||
|
||||
static inline ShaderConvertSelector GetConvertShader(const GSTexture* src, const GSTexture* dst, u32 src_bpp, u32 dst_bpp, u8 mask = 0xf)
|
||||
{
|
||||
return GetConvertShader(src->GetFormat(), dst->GetFormat(), src_bpp, dst_bpp, mask);
|
||||
}
|
||||
|
||||
static inline ShaderConvertSelector GetConvertShaderMask(GSTexture::Format src, GSTexture::Format dst,
|
||||
u32 src_bpp, u32 dst_bpp, bool red = true, bool green = true, bool blue = true, bool alpha = true)
|
||||
{
|
||||
const u8 mask = (red ? 1 : 0) | (green ? 2 : 0) | (blue ? 4 : 0) | (alpha ? 8 : 0);
|
||||
return GetConvertShader(src, dst, src_bpp, dst_bpp, mask);
|
||||
}
|
||||
|
||||
static inline ShaderConvertSelector GetConvertShaderMask(const GSTexture* src, const GSTexture* dst,
|
||||
u32 src_bpp, u32 dst_bpp, bool red = true, bool green = true, bool blue = true, bool alpha = true)
|
||||
{
|
||||
return GetConvertShaderMask(src->GetFormat(), dst->GetFormat(), src_bpp, dst_bpp, red, green, blue, alpha);
|
||||
}
|
||||
|
||||
enum ChannelFetch
|
||||
{
|
||||
@@ -305,6 +666,7 @@ struct alignas(16) GSHWDrawConfig
|
||||
using PS_ATST = GSShader::PS_ATST;
|
||||
using PS_AFAIL = GSShader::PS_AFAIL;
|
||||
using PS_AA1 = GSShader::PS_AA1;
|
||||
using PS_ROV_DEPTH = GSShader::PS_ROV_DEPTH;
|
||||
#pragma pack(push, 1)
|
||||
struct VSSelector
|
||||
{
|
||||
@@ -425,12 +787,16 @@ struct alignas(16) GSHWDrawConfig
|
||||
|
||||
// Anisotropic filtering
|
||||
u32 sw_aniso : 5;
|
||||
|
||||
// ROVs
|
||||
u32 rov_color : 1;
|
||||
PS_ROV_DEPTH rov_depth : 2;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u64 key_lo;
|
||||
u32 key_hi;
|
||||
u64 key_hi;
|
||||
};
|
||||
};
|
||||
__fi PSSelector() : key_lo(0), key_hi(0) {}
|
||||
@@ -439,6 +805,21 @@ struct alignas(16) GSHWDrawConfig
|
||||
__fi bool operator!=(const PSSelector& rhs) const { return (key_lo != rhs.key_lo || key_hi != rhs.key_hi); }
|
||||
__fi bool operator<(const PSSelector& rhs) const { return (key_lo < rhs.key_lo || key_hi < rhs.key_hi); }
|
||||
|
||||
__fi bool IsSWBlending() const
|
||||
{
|
||||
return blend_a || blend_b || blend_d;
|
||||
}
|
||||
|
||||
__fi bool IsZTesting() const
|
||||
{
|
||||
return ztst == ZTST_GEQUAL || ztst == ZTST_GREATER;
|
||||
}
|
||||
|
||||
__fi bool IsAlphaTesting() const
|
||||
{
|
||||
return atst != PS_ATST::NONE;
|
||||
}
|
||||
|
||||
__fi bool IsFeedbackLoopRT() const
|
||||
{
|
||||
const u32 sw_blend_bits = blend_a | blend_b | blend_d;
|
||||
@@ -455,6 +836,11 @@ struct alignas(16) GSHWDrawConfig
|
||||
return afail_needs_depth || ztst_needs_depth || aa1_needs_depth;
|
||||
}
|
||||
|
||||
__fi bool HasShaderDiscard() const
|
||||
{
|
||||
return (IsAlphaTesting() && afail == PS_AFAIL::KEEP) || scanmsk || date || IsZTesting();
|
||||
}
|
||||
|
||||
/// Disables color output from the pixel shader, this is done when all channels are masked.
|
||||
__fi void DisableColorOutput()
|
||||
{
|
||||
@@ -483,9 +869,39 @@ struct alignas(16) GSHWDrawConfig
|
||||
{
|
||||
aa1 = PS_AA1::TRIANGLE;
|
||||
}
|
||||
|
||||
if (rov_depth == PS_ROV_DEPTH::READ_WRITE)
|
||||
{
|
||||
rov_depth = PS_ROV_DEPTH::READ_ONLY;
|
||||
}
|
||||
}
|
||||
|
||||
__fi bool HasColorOutput() const
|
||||
{
|
||||
return !no_color;
|
||||
}
|
||||
|
||||
__fi bool HasDepthOutput() const
|
||||
{
|
||||
return zfloor || zclamp || IsFeedbackLoopDepth() || (rov_depth == PS_ROV_DEPTH::READ_WRITE);
|
||||
}
|
||||
|
||||
__fi bool HasColorROV() const
|
||||
{
|
||||
return rov_color != 0;
|
||||
}
|
||||
|
||||
__fi bool HasDepthROV() const
|
||||
{
|
||||
return rov_depth == PS_ROV_DEPTH::READ_ONLY || rov_depth == PS_ROV_DEPTH::READ_WRITE;
|
||||
}
|
||||
|
||||
__fi bool HasDepthROVWrite() const
|
||||
{
|
||||
return rov_depth == PS_ROV_DEPTH::READ_WRITE;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(PSSelector) == 12, "PSSelector is 12 bytes");
|
||||
static_assert(sizeof(PSSelector) == 16, "PSSelector is 12 bytes");
|
||||
#pragma pack(pop)
|
||||
struct PSSelectorHash
|
||||
{
|
||||
@@ -810,18 +1226,17 @@ struct alignas(16) GSHWDrawConfig
|
||||
EarlyResolve = 4
|
||||
};
|
||||
|
||||
GSTexture* rt; ///< Render target
|
||||
GSTexture* ds; ///< Depth stencil
|
||||
GSTexture* tex; ///< Source texture
|
||||
GSTexture* pal; ///< Palette texture
|
||||
const GSVertex* verts;///< Vertices to draw
|
||||
const u16* indices; ///< Indices to draw
|
||||
u32 nverts; ///< Number of vertices
|
||||
u32 nindices; ///< Number of indices
|
||||
u32 indices_per_prim; ///< Number of indices that make up one primitive
|
||||
const std::vector<size_t>* drawlist; ///< For reducing barriers on sprites
|
||||
const std::vector<GSVector4i>* drawlist_bbox; ///< For RT copy when barriers not available.
|
||||
const std::vector<GSVector4i>* drawlist_bbox_tex; ///< Additionally if we need to sample not from the same pixel of the RT.
|
||||
GSTexture* rt; ///< Render target
|
||||
GSTexture* ds; ///< Depth stencil
|
||||
GSTexture* tex; ///< Source texture
|
||||
GSTexture* pal; ///< Palette texture
|
||||
const GSVertex* verts; ///< Vertices to draw
|
||||
const u16* indices; ///< Indices to draw
|
||||
u32 nverts; ///< Number of vertices
|
||||
u32 nindices; ///< Number of indices
|
||||
u32 indices_per_prim; ///< Number of indices that make up one primitive
|
||||
const std::vector<size_t>* drawlist; ///< For reducing barriers on sprites
|
||||
const std::vector<GSVector4i>* drawlist_bbox; ///< For RT copy when barriers not available.
|
||||
GSVector4i scissor; ///< Scissor rect
|
||||
GSVector4i drawarea; ///< Area in the framebuffer which will be modified.
|
||||
GSVector4i samplearea; ///< Area in the texture which will be sampled.
|
||||
@@ -894,6 +1309,11 @@ struct alignas(16) GSHWDrawConfig
|
||||
{
|
||||
return ps.IsFeedbackLoopDepth() || (tex_hazard == TEX_HAZARD_DEPTH);
|
||||
}
|
||||
|
||||
bool IsBlending()
|
||||
{
|
||||
return blend.enable || blend_multi_pass.enable || ps.IsSWBlending();
|
||||
}
|
||||
|
||||
// Dumping
|
||||
static void DumpConfig(const std::string& path, const GSHWDrawConfig& conf,
|
||||
@@ -969,6 +1389,7 @@ public:
|
||||
bool test_and_sample_depth: 1; ///< Supports concurrently binding the depth-stencil buffer for sampling and depth testing.
|
||||
bool depth_feedback : 1; ///< Depth feedback loops can be done with DS directly (otherwise need to copy to separate RT). Implies `feedback_loops`.
|
||||
bool aa1 : 1; ///< Supports the GS AA1 feature.
|
||||
bool rov : 1; ///< Supports rasterizer ordered views for both depth and color.
|
||||
FeatureSupport()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
@@ -982,7 +1403,7 @@ public:
|
||||
GSVector4 src_rect;
|
||||
GSVector4 dst_rect;
|
||||
GSTexture* src;
|
||||
bool linear;
|
||||
Filter filter;
|
||||
GSHWDrawConfig::ColorMaskSelector wmask; // 0xf for all channels by default
|
||||
};
|
||||
|
||||
@@ -1059,8 +1480,8 @@ protected:
|
||||
virtual GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) = 0;
|
||||
GSTexture* FetchSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format, bool clear, bool prefer_unused_texture);
|
||||
|
||||
virtual void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) = 0;
|
||||
virtual void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) = 0;
|
||||
virtual void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const Filter filter) = 0;
|
||||
virtual void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, Filter filter, const InterlaceConstantBuffer& cb) = 0;
|
||||
virtual void DoFXAA(GSTexture* sTex, GSTexture* dTex) = 0;
|
||||
virtual void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) = 0;
|
||||
|
||||
@@ -1076,9 +1497,14 @@ protected:
|
||||
protected:
|
||||
// Entry point to the renderer-specific StretchRect code.
|
||||
virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear) = 0;
|
||||
void DoStretchRectWithAssertions(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear);
|
||||
|
||||
ShaderConvertSelector shader, Filter filter) = 0;
|
||||
virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, const GSVector4& dRect,
|
||||
PresentShader shader, Filter filter)
|
||||
{
|
||||
pxFailRel("Not implemented");
|
||||
}
|
||||
void DoStretchRectWithAssertions(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
ShaderConvertSelector shader, Filter filter);
|
||||
public:
|
||||
GSDevice();
|
||||
virtual ~GSDevice();
|
||||
@@ -1098,7 +1524,7 @@ public:
|
||||
/// Returns a string representing the specified API.
|
||||
static const char* RenderAPIToString(RenderAPI api);
|
||||
|
||||
/// Parses the configured fullscreen mode into its components (width * height @ refresh hz)
|
||||
/// Parses the configured fullscreen mode into its components (width * height @ refresh Hz)
|
||||
static bool GetRequestedExclusiveFullscreenMode(u32* width, u32* height, float* refresh_rate);
|
||||
|
||||
/// Converts a fullscreen mode to a string.
|
||||
@@ -1196,23 +1622,44 @@ public:
|
||||
virtual void InsertDebugMessage(DebugMessageCategory category, const char* fmt, ...) = 0;
|
||||
|
||||
GSTexture* CreateRenderTarget(int w, int h, GSTexture::Format format, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateDepthStencil(int w, int h, GSTexture::Format format, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateDepthStencil(int w, int h, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateDepthColor(int w, int h, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateTexture(int w, int h, int mipmap_levels, GSTexture::Format format, bool prefer_reuse = false);
|
||||
GSTexture* CreateRenderTarget(const GSVector2i& size, GSTexture::Format format, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateDepthStencil(const GSVector2i& size, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateDepthColor(const GSVector2i& size, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateTexture(const GSVector2i& size, int mipmap_levels, GSTexture::Format format, bool prefer_reuse = false);
|
||||
GSTexture* CreateCompatible(GSTexture* tex, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateCompatible(GSTexture* tex, const GSVector2i& size, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateCompatible(GSTexture* tex, int w, int h, bool clear = true, bool prefer_reuse = true);
|
||||
|
||||
virtual std::unique_ptr<GSDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format) = 0;
|
||||
|
||||
virtual void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY) = 0;
|
||||
|
||||
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, bool red, bool green, bool blue, bool alpha, ShaderConvert shader = ShaderConvert::COPY);
|
||||
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderConvert shader = ShaderConvert::COPY, bool linear = true);
|
||||
void StretchRect(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, ShaderConvert shader = ShaderConvert::COPY, bool linear = true);
|
||||
// StretchRect - all options
|
||||
void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderConvertSelector shader, Filter filter);
|
||||
void StretchRect(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, ShaderConvertSelector shader, Filter filter);
|
||||
void StretchRect(GSTexture* sTex, GSTexture* dTex, ShaderConvertSelector shader, Filter filter);
|
||||
|
||||
// StretchRect - infer shader based on formats
|
||||
void StretchRectAuto(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, Filter filter,
|
||||
u32 src_bpp = 32, u32 dst_bpp = 32);
|
||||
void StretchRectAuto(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, Filter filter,
|
||||
u32 src_bpp = 32, u32 dst_bpp = 32);
|
||||
void StretchRectAuto(GSTexture* sTex, GSTexture* dTex, Filter filter, u32 src_bpp = 32, u32 dst_bpp = 32);
|
||||
|
||||
// StretchRect - nearest filter, infer shader based on formats, specify channel mask
|
||||
void StretchRectAutoMask(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, bool red, bool green, bool blue, bool alpha, u32 src_bpp = 32, u32 dst_bpp = 32);
|
||||
void StretchRectAutoMask(GSTexture* sTex, GSTexture* dTex, const GSVector4& dRect, bool red, bool green, bool blue, bool alpha, u32 src_bpp = 32, u32 dst_bpp = 32);
|
||||
void StretchRectAutoMask(GSTexture* sTex, GSTexture* dTex, bool red, bool green, bool blue, bool alpha, u32 src_bpp = 32, u32 dst_bpp = 32);
|
||||
|
||||
/// Performs a screen blit for display. If dTex is null, it assumes you are writing to the system framebuffer/swap chain.
|
||||
virtual void PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear) = 0;
|
||||
virtual void PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, Filter filter) = 0;
|
||||
|
||||
/// Same as doing StretchRect for each item, except tries to batch together rectangles in as few draws as possible.
|
||||
/// The provided list should be sorted by texture, the implementations only check if it's the same as the last.
|
||||
virtual void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader = ShaderConvert::COPY);
|
||||
virtual void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader = ShaderConvert::COPY);
|
||||
|
||||
/// Sorts a MultiStretchRect list for optimal batching.
|
||||
static void SortMultiStretchRects(MultiStretchRect* rects, u32 num_rects);
|
||||
|
||||
@@ -695,7 +695,7 @@ void GSRenderer::VSync(u32 field, bool registers_written, bool idle_frame)
|
||||
const float shader_time = static_cast<float>(Common::Timer::ConvertValueToSeconds(current_time - m_shader_time_start));
|
||||
|
||||
g_gs_device->PresentRect(current, src_uv, nullptr, draw_rect,
|
||||
s_tv_shader_indices[GSConfig.TVShader], shader_time, GSConfig.LinearPresent != GSPostBilinearMode::Off);
|
||||
s_tv_shader_indices[GSConfig.TVShader], shader_time, BilnIf(GSConfig.LinearPresent != GSPostBilinearMode::Off));
|
||||
}
|
||||
|
||||
EndPresentFrame();
|
||||
@@ -818,7 +818,7 @@ void GSRenderer::VSync(u32 field, bool registers_written, bool idle_frame)
|
||||
GSTexture* temp = g_gs_device->CreateRenderTarget(size.x, size.y, GSTexture::Format::Color, false);
|
||||
if (temp)
|
||||
{
|
||||
g_gs_device->StretchRect(current, temp, GSVector4(0, 0, size.x, size.y));
|
||||
g_gs_device->StretchRect(current, temp, GSVector4(0, 0, size.x, size.y), ShaderConvert::COPY, Biln);
|
||||
GSCapture::DeliverVideoFrame(temp);
|
||||
g_gs_device->Recycle(temp);
|
||||
}
|
||||
@@ -972,7 +972,7 @@ void GSRenderer::PresentCurrentFrame()
|
||||
const float shader_time = static_cast<float>(Common::Timer::ConvertValueToSeconds(current_time - m_shader_time_start));
|
||||
|
||||
g_gs_device->PresentRect(current, src_uv, nullptr, draw_rect,
|
||||
s_tv_shader_indices[GSConfig.TVShader], shader_time, GSConfig.LinearPresent != GSPostBilinearMode::Off);
|
||||
s_tv_shader_indices[GSConfig.TVShader], shader_time, BilnIf(GSConfig.LinearPresent != GSPostBilinearMode::Off));
|
||||
}
|
||||
|
||||
EndPresentFrame();
|
||||
@@ -1086,7 +1086,7 @@ bool GSRenderer::SaveSnapshotToMemory(u32 window_width, u32 window_height, bool
|
||||
if (dl)
|
||||
{
|
||||
const GSVector4i rc(0, 0, draw_width, draw_height);
|
||||
g_gs_device->StretchRect(current, src_uv, rt, GSVector4(rc), ShaderConvert::TRANSPARENCY_FILTER);
|
||||
g_gs_device->StretchRect(current, src_uv, rt, GSVector4(rc), ShaderConvert::TRANSPARENCY_FILTER, Biln);
|
||||
dl->CopyFromTexture(rc, rt, rc, 0);
|
||||
dl->Flush();
|
||||
|
||||
|
||||
@@ -56,4 +56,11 @@ enum class PS_AA1 : uint32_t
|
||||
TRIANGLE_SW_Z = 3, ///< AA1 triangles with software Z discard
|
||||
};
|
||||
|
||||
enum class PS_ROV_DEPTH : uint32_t
|
||||
{
|
||||
NONE = 0,
|
||||
READ_WRITE = 1,
|
||||
READ_ONLY = 2,
|
||||
};
|
||||
|
||||
} // namespace GSShader
|
||||
|
||||
@@ -20,7 +20,7 @@ bool GSTexture::Save(const std::string& fn)
|
||||
{
|
||||
// Depth textures need special treatment - we have a stencil component.
|
||||
// Just re-use the existing conversion shader instead.
|
||||
if (m_format == Format::DepthStencil || m_format == Format::Float32)
|
||||
if (m_format == Format::DepthStencil || m_format == Format::DepthColor)
|
||||
{
|
||||
GSTexture* temp = g_gs_device->CreateRenderTarget(GetWidth(), GetHeight(), Format::Color, false);
|
||||
if (!temp)
|
||||
@@ -29,7 +29,7 @@ bool GSTexture::Save(const std::string& fn)
|
||||
return false;
|
||||
}
|
||||
|
||||
g_gs_device->StretchRect(this, GSVector4::cxpr(0.0f, 0.0f, 1.0f, 1.0f), temp, GSVector4(GetRect()), ShaderConvert::FLOAT32_TO_RGBA8, false);
|
||||
g_gs_device->StretchRectAuto(this, temp, Nearest);
|
||||
const bool res = temp->Save(fn);
|
||||
g_gs_device->Recycle(temp);
|
||||
return res;
|
||||
@@ -73,7 +73,7 @@ const char* GSTexture::GetFormatName(Format format)
|
||||
case Format::ColorHDR: return "ColorHDR";
|
||||
case Format::ColorClip: return "ColorClip";
|
||||
case Format::DepthStencil: return "DepthStencil";
|
||||
case Format::Float32: return "Float32";
|
||||
case Format::DepthColor: return "DepthColor";
|
||||
case Format::UNorm8: return "UNorm8";
|
||||
case Format::UInt16: return "UInt16";
|
||||
case Format::UInt32: return "UInt32";
|
||||
@@ -116,11 +116,11 @@ u32 GSTexture::GetCompressedBytesPerBlock(Format format)
|
||||
case Format::ColorHDR: return 8; // ColorHDR/RGBA16F
|
||||
case Format::ColorClip: return 8; // ColorClip/RGBA16
|
||||
case Format::DepthStencil: return 4; // DepthStencil
|
||||
case Format::Float32: return 4; // Float32/R32
|
||||
case Format::DepthColor: return 4; // DepthColor/R32
|
||||
case Format::UNorm8: return 1; // UNorm8/R8
|
||||
case Format::UInt16: return 2; // UInt16/R16UI
|
||||
case Format::UInt32: return 4; // UInt32/R32UI
|
||||
case Format::PrimID: return 4; // Int32/R32I
|
||||
case Format::PrimID: return 4; // PrimID/R32
|
||||
case Format::BC1: return 8; // BC1 - 16 pixels in 64 bits
|
||||
case Format::BC2: return 16; // BC2 - 16 pixels in 128 bits
|
||||
case Format::BC3: return 16; // BC3 - 16 pixels in 128 bits
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
ColorHDR, ///< High dynamic range (RGBA16F) color texture
|
||||
ColorClip, ///< Color texture with more bits for colclip (wrap) emulation, given that blending requires 9bpc (RGBA16Unorm)
|
||||
DepthStencil, ///< Depth stencil texture
|
||||
Float32, ///< For treating depth texture as RT
|
||||
DepthColor, ///< For treating depth texture as RT
|
||||
UNorm8, ///< A8UNorm texture for paletted textures and the OSD font
|
||||
UInt16, ///< UInt16 texture for reading back 16-bit depth
|
||||
UInt32, ///< UInt32 texture for reading back 24 and 32-bit depth
|
||||
@@ -73,6 +73,13 @@ protected:
|
||||
bool m_needs_mipmaps_generated = true;
|
||||
ClearValue m_clear_value = {};
|
||||
|
||||
// For GL/DX11 since they don't track layouts.
|
||||
// Used heuristically to decide whether to use ROV for a draw.
|
||||
bool m_unordered_access = false;
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
std::string m_debug_name;
|
||||
#endif
|
||||
public:
|
||||
GSTexture();
|
||||
virtual ~GSTexture();
|
||||
@@ -87,6 +94,7 @@ public:
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
virtual void SetDebugName(std::string_view name) = 0;
|
||||
const std::string& GetDebugName() { return m_debug_name; }
|
||||
#endif
|
||||
|
||||
bool Save(const std::string& fn);
|
||||
@@ -129,10 +137,18 @@ public:
|
||||
{
|
||||
return (m_type == Type::DepthStencil);
|
||||
}
|
||||
__fi bool IsDepthColor() const
|
||||
{
|
||||
return (m_type == Type::RenderTarget && m_format == Format::DepthColor);
|
||||
}
|
||||
__fi bool IsTexture() const
|
||||
{
|
||||
return (m_type == Type::Texture);
|
||||
}
|
||||
__fi bool IsDepthLike() const
|
||||
{
|
||||
return IsDepthStencil() || IsDepthColor();
|
||||
}
|
||||
|
||||
__fi State GetState() const { return m_state; }
|
||||
__fi void SetState(State state) { m_state = state; }
|
||||
@@ -143,6 +159,10 @@ public:
|
||||
__fi u32 GetClearColor() const { return m_clear_value.color; }
|
||||
__fi float GetClearDepth() const { return m_clear_value.depth; }
|
||||
__fi GSVector4 GetUNormClearColor() const { return GSVector4::unorm8(m_clear_value.color); }
|
||||
__fi GSVector4 GetClearForFormat() const
|
||||
{
|
||||
return IsDepthLike() ? GSVector4(m_clear_value.depth, 0.0f, 0.0f, 0.0f) : GetUNormClearColor();
|
||||
}
|
||||
|
||||
__fi void SetClearColor(u32 color)
|
||||
{
|
||||
@@ -161,6 +181,12 @@ public:
|
||||
// Typical size of a RGBA texture
|
||||
u32 GetMemUsage() const { return m_size.x * m_size.y * (m_format == Format::UNorm8 ? 1 : 4); }
|
||||
|
||||
// The unordered access flag is sticky, so once it's set we keep using ROV for the target
|
||||
// until it's recycled/destroyed. Only used for DX11/GL, which don't track actual resource layout/state.
|
||||
virtual bool IsUnorderedAccess() const { return m_unordered_access; }
|
||||
void SetUnorderedAccess() { m_unordered_access = true; }
|
||||
void ClearUnorderedAccess() { m_unordered_access = false; }
|
||||
|
||||
// Helper routines for formats/types
|
||||
static bool IsCompressedFormat(Format format) { return (format >= Format::BC1 && format <= Format::BC7); }
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <d3d11.h>
|
||||
#include <d3d12.h>
|
||||
#include <directx/d3d12.h>
|
||||
#include <d3dcompiler.h>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ bool D3D11ShaderCache::Open(D3D_FEATURE_LEVEL feature_level, bool debug)
|
||||
m_shader_model = D3D::ShaderModel::SM41;
|
||||
break;
|
||||
case D3D_FEATURE_LEVEL_11_0:
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
m_shader_model = D3D::ShaderModel::SM50;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -109,7 +109,8 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
|
||||
wil::com_ptr_nothrow<IDXGIAdapter1> dxgi_adapter = D3D::GetAdapterByName(m_dxgi_factory.get(), GSConfig.Adapter);
|
||||
|
||||
static constexpr std::array<D3D_FEATURE_LEVEL, 2> requested_feature_levels = {{
|
||||
static constexpr std::array<D3D_FEATURE_LEVEL, 3> requested_feature_levels = {{
|
||||
D3D_FEATURE_LEVEL_11_1,
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
D3D_FEATURE_LEVEL_10_0,
|
||||
}};
|
||||
@@ -219,15 +220,35 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
const std::optional<std::string> convert_hlsl = ReadShaderSource("shaders/dx11/convert.fx");
|
||||
if (!convert_hlsl.has_value())
|
||||
return false;
|
||||
ShaderMacro sm_vs;
|
||||
sm_vs.AddMacro("VERTEX_SHADER", 1);
|
||||
if (!m_shader_cache.GetVertexShaderAndInputLayout(m_dev.get(), m_convert.vs.put(), m_convert.il.put(),
|
||||
il_convert, std::size(il_convert), *convert_hlsl, nullptr, "vs_main"))
|
||||
il_convert, std::size(il_convert), *convert_hlsl, sm_vs.GetPtr(), "vs_main"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < std::size(m_convert.ps); i++)
|
||||
const auto WrapEntryPointMacro = [](const std::string& s) { return fmt::format("__{}__", s); };
|
||||
|
||||
m_convert.ps.resize(ShaderConvertSelector::NUM_TOTAL_SHADERS);
|
||||
for (u32 i = 0; i < ShaderConvertSelector::NUM_TOTAL_SHADERS; i++)
|
||||
{
|
||||
m_convert.ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *convert_hlsl, nullptr, shaderName(static_cast<ShaderConvert>(i)));
|
||||
const ShaderConvertSelector shader = ShaderConvertSelector::Get(i);
|
||||
|
||||
const char* entry_point = shader.EntryPoint();
|
||||
std::string entry_point_macro = WrapEntryPointMacro(entry_point);
|
||||
|
||||
ShaderMacro sm_ps;
|
||||
sm_ps.AddMacro("PIXEL_SHADER", 1);
|
||||
sm_ps.AddMacro("HAS_BILN", static_cast<int>(shader.Biln()));
|
||||
sm_ps.AddMacro("HAS_STENCIL_OUTPUT", static_cast<int>(shader.StencilOutput()));
|
||||
sm_ps.AddMacro("HAS_INTEGER_OUTPUT", static_cast<int>(shader.IntegerOutputBpp() != 0));
|
||||
sm_ps.AddMacro("HAS_DEPTH_OUTPUT", static_cast<int>(shader.DepthOutput()));
|
||||
sm_ps.AddMacro("HAS_FLOAT32_INPUT", static_cast<int>(shader.Float32Input()));
|
||||
sm_ps.AddMacro("HAS_FLOAT32_OUTPUT", static_cast<int>(shader.Float32Output()));
|
||||
sm_ps.AddMacro(entry_point_macro.c_str(), 1);
|
||||
|
||||
m_convert.ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *convert_hlsl, sm_ps.GetPtr(), entry_point);
|
||||
if (!m_convert.ps[i])
|
||||
return false;
|
||||
}
|
||||
@@ -243,7 +264,7 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
|
||||
for (size_t i = 0; i < std::size(m_present.ps); i++)
|
||||
{
|
||||
m_present.ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *shader, nullptr, shaderName(static_cast<PresentShader>(i)));
|
||||
m_present.ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *shader, nullptr, ShaderEntryPoint(static_cast<PresentShader>(i)));
|
||||
if (!m_present.ps[i])
|
||||
return false;
|
||||
}
|
||||
@@ -548,8 +569,12 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
|
||||
for (size_t i = 0; i < std::size(m_date.primid_init_ps); i++)
|
||||
{
|
||||
const std::string entry_point(StringUtil::StdStringFromFormat("ps_stencil_image_init_%zu", i));
|
||||
m_date.primid_init_ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *convert_hlsl, nullptr, entry_point.c_str());
|
||||
const std::string entry_point(StringUtil::StdStringFromFormat("ps_primid_image_init_%zu", i));
|
||||
const std::string entry_point_macro = WrapEntryPointMacro(entry_point);
|
||||
ShaderMacro sm_ps;
|
||||
sm_ps.AddMacro("PIXEL_SHADER", 1);
|
||||
sm_ps.AddMacro(entry_point_macro.c_str(), 1);
|
||||
m_date.primid_init_ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *convert_hlsl, sm_ps.GetPtr(), entry_point.c_str());
|
||||
if (!m_date.primid_init_ps[i])
|
||||
return false;
|
||||
}
|
||||
@@ -568,11 +593,18 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
Host::OSD_WARNING_DURATION);
|
||||
}
|
||||
|
||||
// 1x1 dummy texture.
|
||||
m_null_texture = CreateSurface(GSTexture::Type::RenderTarget, 1, 1, 1, GSTexture::Format::Color);
|
||||
if (!m_null_texture)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GSDevice11::Destroy()
|
||||
{
|
||||
delete m_null_texture;
|
||||
|
||||
GSDevice::Destroy();
|
||||
DestroySwapChain();
|
||||
DestroyTimestampQueries();
|
||||
@@ -617,6 +649,20 @@ void GSDevice11::Destroy()
|
||||
}
|
||||
m_state.current_ds = nullptr;
|
||||
|
||||
if (m_state.rt_uav)
|
||||
{
|
||||
m_state.rt_uav->Release();
|
||||
m_state.rt_uav = nullptr;
|
||||
}
|
||||
m_state.current_rt_uav = nullptr;
|
||||
|
||||
if (m_state.ds_uav)
|
||||
{
|
||||
m_state.ds_uav->Release();
|
||||
m_state.ds_uav = nullptr;
|
||||
}
|
||||
m_state.current_ds_uav = nullptr;
|
||||
|
||||
m_shader_cache.Close();
|
||||
|
||||
#ifdef REPORT_LEAKED_OBJECTS
|
||||
@@ -659,6 +705,12 @@ void GSDevice11::SetFeatures(IDXGIAdapter1* adapter)
|
||||
m_conservative_depth = (m_feature_level >= D3D_FEATURE_LEVEL_11_0);
|
||||
m_rgba16_unorm_hw_blend = IsTextureFormatHWBlendable(m_dev.get(), DXGI_FORMAT_R16G16B16A16_UNORM);
|
||||
|
||||
m_uav_texture = (m_feature_level >= D3D_FEATURE_LEVEL_11_0);
|
||||
|
||||
D3D11_FEATURE_DATA_D3D11_OPTIONS2 options2{};
|
||||
m_dev->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS2, &options2, sizeof(options2));
|
||||
m_features.rov = m_uav_texture && options2.ROVsSupported;
|
||||
|
||||
// Let the user know if said features are available.
|
||||
Console.WriteLnFmt("D3D11: DXTn Texture Compression: {}", m_features.dxt_textures ? "Supported" : "Not Supported");
|
||||
Console.WriteLnFmt("D3D11: BC6/7 Texture Compression: {}", m_features.bptc_textures ? "Supported" : "Not Supported");
|
||||
@@ -1242,7 +1294,7 @@ void GSDevice11::CommitClear(GSTexture* t)
|
||||
if (T->GetState() == GSTexture::State::Invalidated)
|
||||
m_ctx->DiscardView(static_cast<ID3D11RenderTargetView*>(*T));
|
||||
else
|
||||
m_ctx->ClearRenderTargetView(*T, T->GetUNormClearColor().F32);
|
||||
m_ctx->ClearRenderTargetView(*T, T->GetClearForFormat().F32);
|
||||
}
|
||||
|
||||
T->SetState(GSTexture::State::Dirty);
|
||||
@@ -1298,6 +1350,8 @@ GSTexture* GSDevice11::CreateSurface(GSTexture::Type type, int width, int height
|
||||
{
|
||||
case GSTexture::Type::RenderTarget:
|
||||
desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
|
||||
if (m_uav_texture)
|
||||
desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS;
|
||||
break;
|
||||
case GSTexture::Type::DepthStencil:
|
||||
desc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
|
||||
@@ -1307,6 +1361,7 @@ GSTexture* GSDevice11::CreateSurface(GSTexture::Type type, int width, int height
|
||||
desc.MiscFlags = (levels > 1 && !GSTexture::IsCompressedFormat(format)) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0;
|
||||
break;
|
||||
case GSTexture::Type::RWTexture:
|
||||
pxAssert(m_uav_texture);
|
||||
desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
|
||||
break;
|
||||
default:
|
||||
@@ -1385,17 +1440,20 @@ void GSDevice11::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
|
||||
}
|
||||
|
||||
void GSDevice11::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear)
|
||||
ShaderConvertSelector shader, Filter filter)
|
||||
{
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_convert.ps[static_cast<int>(shader)].get(), nullptr, m_convert.bs[cms.wrgba].get(), linear);
|
||||
const u8 mask = shader.Mask();
|
||||
shader = shader.SetMask(); // Mask is handled separately from program.
|
||||
filter = shader.SupportsBilinear() ? Nearest : filter; // Don't allow HW bilinear if SW bilinear is needed.
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, GetConvertShader(shader), nullptr, m_convert.bs[mask].get(), filter);
|
||||
}
|
||||
|
||||
void GSDevice11::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, bool linear)
|
||||
void GSDevice11::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, Filter filter)
|
||||
{
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, ps, ps_cb, m_convert.bs[D3D11_COLOR_WRITE_ENABLE_ALL].get(), linear);
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, ps, ps_cb, m_convert.bs[D3D11_COLOR_WRITE_ENABLE_ALL].get(), filter);
|
||||
}
|
||||
|
||||
void GSDevice11::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, ID3D11BlendState* bs, bool linear)
|
||||
void GSDevice11::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, ID3D11BlendState* bs, Filter filter)
|
||||
{
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
|
||||
@@ -1455,8 +1513,8 @@ void GSDevice11::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTextur
|
||||
|
||||
// ps
|
||||
|
||||
PSSetShaderResource(0, sTex);
|
||||
PSSetSamplerState(linear ? m_convert.ln.get() : m_convert.pt.get());
|
||||
PSSetShaderResource(TEXTURE_TEXTURE, sTex);
|
||||
PSSetSamplerState(filter == Biln ? m_convert.ln.get() : m_convert.pt.get());
|
||||
PSSetShader(ps, ps_cb);
|
||||
|
||||
// draw
|
||||
@@ -1464,7 +1522,7 @@ void GSDevice11::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTextur
|
||||
DrawPrimitive();
|
||||
}
|
||||
|
||||
void GSDevice11::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear)
|
||||
void GSDevice11::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, Filter filter)
|
||||
{
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
|
||||
@@ -1520,8 +1578,8 @@ void GSDevice11::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
|
||||
// ps
|
||||
|
||||
PSSetShaderResource(0, sTex);
|
||||
PSSetSamplerState(linear ? m_convert.ln.get() : m_convert.pt.get());
|
||||
PSSetShaderResource(TEXTURE_TEXTURE, sTex);
|
||||
PSSetSamplerState(filter == Biln ? m_convert.ln.get() : m_convert.pt.get());
|
||||
PSSetShader(m_present.ps[static_cast<u32>(shader)].get(), m_present.ps_cb.get());
|
||||
|
||||
// draw
|
||||
@@ -1544,7 +1602,7 @@ void GSDevice11::UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u
|
||||
|
||||
const GSVector4 dRect(0, 0, dSize, 1);
|
||||
const ShaderConvert shader = (dSize == 16) ? ShaderConvert::CLUT_4 : ShaderConvert::CLUT_8;
|
||||
DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, m_convert.ps[static_cast<int>(shader)].get(), m_merge.cb.get(), nullptr, false);
|
||||
DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, GetConvertShader(shader), m_merge.cb.get(), nullptr, Nearest);
|
||||
}
|
||||
|
||||
void GSDevice11::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM)
|
||||
@@ -1563,7 +1621,7 @@ void GSDevice11::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offs
|
||||
|
||||
const GSVector4 dRect(0, 0, dTex->GetWidth(), dTex->GetHeight());
|
||||
const ShaderConvert shader = ((SPSM & 0xE) == 0) ? ShaderConvert::RGBA_TO_8I : ShaderConvert::RGB5A1_TO_8I;
|
||||
DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, m_convert.ps[static_cast<int>(shader)].get(), m_merge.cb.get(), nullptr, false);
|
||||
DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, GetConvertShader(shader), m_merge.cb.get(), nullptr, Nearest);
|
||||
}
|
||||
|
||||
void GSDevice11::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min, const GSVector4& dRect)
|
||||
@@ -1583,23 +1641,25 @@ void GSDevice11::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32
|
||||
UpdateSubresource(m_merge.cb.get(), &cb, &m_merge.cb_uniforms, sizeof(cb));
|
||||
|
||||
const ShaderConvert shader = ShaderConvert::DOWNSAMPLE_COPY;
|
||||
DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, m_convert.ps[static_cast<int>(shader)].get(), m_merge.cb.get(), nullptr, false);
|
||||
DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, GetConvertShader(shader), m_merge.cb.get(), nullptr, Nearest);
|
||||
}
|
||||
|
||||
void GSDevice11::DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader)
|
||||
void GSDevice11::DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader)
|
||||
{
|
||||
shader = shader.SetMask(); // Mask is handled separately from program.
|
||||
|
||||
IASetInputLayout(m_convert.il.get());
|
||||
IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
|
||||
VSSetShader(m_convert.vs.get(), nullptr);
|
||||
PSSetShader(m_convert.ps[static_cast<int>(shader)].get(), nullptr);
|
||||
PSSetShader(GetConvertShader(shader), nullptr);
|
||||
|
||||
OMSetDepthStencilState(dTex->IsRenderTarget() ? m_convert.dss.get() : m_convert.dss_write.get(), 0);
|
||||
OMSetRenderTargets(dTex->IsRenderTarget() ? dTex : nullptr, dTex->IsDepthStencil() ? dTex : nullptr);
|
||||
|
||||
const GSVector2 ds(static_cast<float>(dTex->GetWidth()), static_cast<float>(dTex->GetHeight()));
|
||||
GSTexture* last_tex = rects[0].src;
|
||||
bool last_linear = rects[0].linear;
|
||||
Filter last_filter = rects[0].filter;
|
||||
u8 last_wmask = rects[0].wmask.wrgba;
|
||||
|
||||
u32 first = 0;
|
||||
@@ -1607,7 +1667,7 @@ void GSDevice11::DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_re
|
||||
|
||||
for (u32 i = 1; i < num_rects; i++)
|
||||
{
|
||||
if (rects[i].src == last_tex && rects[i].linear == last_linear && rects[i].wmask.wrgba == last_wmask)
|
||||
if (rects[i].src == last_tex && rects[i].filter == last_filter && rects[i].wmask.wrgba == last_wmask)
|
||||
{
|
||||
count++;
|
||||
continue;
|
||||
@@ -1615,7 +1675,7 @@ void GSDevice11::DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_re
|
||||
|
||||
DoMultiStretchRects(rects + first, count, ds);
|
||||
last_tex = rects[i].src;
|
||||
last_linear = rects[i].linear;
|
||||
last_filter = rects[i].filter;
|
||||
last_wmask = rects[i].wmask.wrgba;
|
||||
first += count;
|
||||
count = 1;
|
||||
@@ -1669,15 +1729,15 @@ void GSDevice11::DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rect
|
||||
IASetIndexBuffer(m_ib.get());
|
||||
|
||||
CommitClear(rects[0].src);
|
||||
PSSetShaderResource(0, rects[0].src);
|
||||
PSSetSamplerState(rects[0].linear ? m_convert.ln.get() : m_convert.pt.get());
|
||||
PSSetShaderResource(TEXTURE_TEXTURE, rects[0].src);
|
||||
PSSetSamplerState(rects[0].filter == Biln ? m_convert.ln.get() : m_convert.pt.get());
|
||||
|
||||
OMSetBlendState(m_convert.bs[rects[0].wmask.wrgba].get(), 0.0f);
|
||||
|
||||
DrawIndexedPrimitive();
|
||||
}
|
||||
|
||||
void GSDevice11::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear)
|
||||
void GSDevice11::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const Filter filter)
|
||||
{
|
||||
const GSVector4 full_r(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
const bool feedback_write_2 = PMODE.EN2 && sTex[2] != nullptr && EXTBUF.FBIN == 1;
|
||||
@@ -1700,14 +1760,14 @@ void GSDevice11::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||
{
|
||||
// 2nd output is enabled and selected. Copy it to destination so we can blend it with 1st output
|
||||
// Note: value outside of dRect must contains the background color (c)
|
||||
StretchRect(sTex[1], sRect[1], dTex, PMODE.SLBG ? dRect[2] : dRect[1], ShaderConvert::COPY, linear);
|
||||
StretchRect(sTex[1], sRect[1], dTex, PMODE.SLBG ? dRect[2] : dRect[1], ShaderConvert::COPY, filter);
|
||||
}
|
||||
|
||||
// Save 2nd output
|
||||
if (feedback_write_2)
|
||||
{
|
||||
DoStretchRect(dTex, full_r, sTex[2], dRect[2], m_convert.ps[static_cast<int>(ShaderConvert::YUV)].get(),
|
||||
m_merge.cb.get(), nullptr, linear);
|
||||
DoStretchRect(dTex, full_r, sTex[2], dRect[2], GetConvertShader(ShaderConvert::YUV),
|
||||
m_merge.cb.get(), nullptr, filter);
|
||||
}
|
||||
|
||||
// Restore background color to process the normal merge
|
||||
@@ -1717,21 +1777,21 @@ void GSDevice11::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||
if (sTex[0])
|
||||
{
|
||||
// 1st output is enabled. It must be blended
|
||||
DoStretchRect(sTex[0], sRect[0], dTex, dRect[0], m_merge.ps[PMODE.MMOD].get(), m_merge.cb.get(), m_merge.bs.get(), linear);
|
||||
DoStretchRect(sTex[0], sRect[0], dTex, dRect[0], m_merge.ps[PMODE.MMOD].get(), m_merge.cb.get(), m_merge.bs.get(), filter);
|
||||
}
|
||||
|
||||
if (feedback_write_1)
|
||||
{
|
||||
DoStretchRect(dTex, full_r, sTex[2], dRect[2], m_convert.ps[static_cast<int>(ShaderConvert::YUV)].get(),
|
||||
m_merge.cb.get(), nullptr, linear);
|
||||
DoStretchRect(dTex, full_r, sTex[2], dRect[2], GetConvertShader(ShaderConvert::YUV),
|
||||
m_merge.cb.get(), nullptr, filter);
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice11::DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb)
|
||||
void GSDevice11::DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, Filter filter, const InterlaceConstantBuffer& cb)
|
||||
{
|
||||
UpdateSubresource(m_interlace.cb.get(), &cb, &m_interlace.cb_uniforms, sizeof(cb));
|
||||
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_interlace.ps[static_cast<int>(shader)].get(), m_interlace.cb.get(), linear);
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_interlace.ps[static_cast<int>(shader)].get(), m_interlace.cb.get(), filter);
|
||||
}
|
||||
|
||||
void GSDevice11::DoFXAA(GSTexture* sTex, GSTexture* dTex)
|
||||
@@ -1757,7 +1817,7 @@ void GSDevice11::DoFXAA(GSTexture* sTex, GSTexture* dTex)
|
||||
return;
|
||||
}
|
||||
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_fxaa_ps.get(), nullptr, true);
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_fxaa_ps.get(), nullptr, Biln);
|
||||
}
|
||||
|
||||
void GSDevice11::DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4])
|
||||
@@ -1769,7 +1829,7 @@ void GSDevice11::DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float para
|
||||
|
||||
UpdateSubresource(m_shadeboost.cb.get(), params, &m_shadeboost.cb_uniforms, sizeof(float) * 4);
|
||||
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_shadeboost.ps.get(), m_shadeboost.cb.get(), false);
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_shadeboost.ps.get(), m_shadeboost.cb.get(), Nearest);
|
||||
}
|
||||
|
||||
void GSDevice11::SetupVS(VSSelector sel, const GSHWDrawConfig::VSConstantBuffer* cb)
|
||||
@@ -1892,6 +1952,8 @@ void GSDevice11::SetupPS(const PSSelector& sel, const GSHWDrawConfig::PSConstant
|
||||
sm.AddMacro("PS_AA1", static_cast<u32>(sel.aa1));
|
||||
sm.AddMacro("PS_ABE", sel.abe);
|
||||
sm.AddMacro("PS_ANISOTROPIC_FILTERING", sel.sw_aniso);
|
||||
sm.AddMacro("PS_ROV_COLOR", sel.rov_color);
|
||||
sm.AddMacro("PS_ROV_DEPTH", static_cast<u32>(sel.rov_depth));
|
||||
|
||||
wil::com_ptr_nothrow<ID3D11PixelShader> ps = m_shader_cache.GetPixelShader(m_dev.get(), m_tfx_source, sm.GetPtr(), "ps_main");
|
||||
i = m_ps.try_emplace(sel, std::move(ps)).first;
|
||||
@@ -2310,9 +2372,9 @@ void GSDevice11::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSV
|
||||
|
||||
// ps
|
||||
|
||||
PSSetShaderResource(0, rt);
|
||||
PSSetShaderResource(TEXTURE_TEXTURE, rt);
|
||||
PSSetSamplerState(m_convert.pt.get());
|
||||
PSSetShader(m_convert.ps[SetDATMShader(datm)].get(), nullptr);
|
||||
PSSetShader(GetConvertShader(SetDATMShader(datm)), nullptr);
|
||||
|
||||
// draw
|
||||
|
||||
@@ -2678,10 +2740,16 @@ void GSDevice11::OMSetBlendState(ID3D11BlendState* bs, u8 bf)
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor, ID3D11DepthStencilView* read_only_dsv)
|
||||
void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, GSTexture* rt_uav_tex, GSTexture* ds_uav_tex,
|
||||
const GSVector4i* scissor, ID3D11DepthStencilView* read_only_dsv)
|
||||
{
|
||||
if (!(rt || rt_uav_tex) && ds_uav_tex)
|
||||
rt_uav_tex = m_null_texture; // Fill in the first UAV slot with the null texture.
|
||||
|
||||
ID3D11RenderTargetView* rtv = nullptr;
|
||||
ID3D11DepthStencilView* dsv = nullptr;
|
||||
ID3D11UnorderedAccessView* rt_uav = nullptr;
|
||||
ID3D11UnorderedAccessView* ds_uav = nullptr;
|
||||
|
||||
if (rt)
|
||||
{
|
||||
@@ -2693,9 +2761,22 @@ void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector
|
||||
CommitClear(ds);
|
||||
dsv = read_only_dsv ? read_only_dsv : *static_cast<GSTexture11*>(ds);
|
||||
}
|
||||
if (rt_uav_tex)
|
||||
{
|
||||
CommitClear(rt_uav_tex);
|
||||
rt_uav = *static_cast<GSTexture11*>(rt_uav_tex);
|
||||
}
|
||||
if (ds_uav_tex)
|
||||
{
|
||||
CommitClear(ds_uav_tex);
|
||||
ds_uav = *static_cast<GSTexture11*>(ds_uav_tex);
|
||||
}
|
||||
|
||||
const bool changed = (m_state.rtv != rtv || m_state.dsv != dsv);
|
||||
g_perfmon.Put(GSPerfMon::RenderPasses, static_cast<double>(changed));
|
||||
const bool changed = (m_state.rtv != rtv || m_state.dsv != dsv || m_state.rt_uav != rt_uav || m_state.ds_uav != ds_uav);
|
||||
const bool no_uavs = m_state.rt_uav == nullptr && rt_uav == nullptr && m_state.ds_uav == nullptr && ds_uav == nullptr;
|
||||
|
||||
if (changed)
|
||||
g_perfmon.Put(GSPerfMon::RenderPasses, 1.0);
|
||||
|
||||
if (m_state.rtv != rtv)
|
||||
{
|
||||
@@ -2715,15 +2796,54 @@ void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector
|
||||
m_state.dsv = dsv;
|
||||
m_state.current_ds = ds;
|
||||
}
|
||||
if (m_state.rt_uav != rt_uav)
|
||||
{
|
||||
if (m_state.rt_uav)
|
||||
m_state.rt_uav->Release();
|
||||
if (rt_uav)
|
||||
rt_uav->AddRef();
|
||||
m_state.rt_uav = rt_uav;
|
||||
m_state.current_rt_uav = rt_uav_tex;
|
||||
}
|
||||
if (m_state.ds_uav != ds_uav)
|
||||
{
|
||||
if (m_state.ds_uav)
|
||||
m_state.ds_uav->Release();
|
||||
if (ds_uav)
|
||||
ds_uav->AddRef();
|
||||
m_state.ds_uav = ds_uav;
|
||||
m_state.current_ds_uav = ds_uav_tex;
|
||||
}
|
||||
|
||||
PSUnbindConflictingSRVs(m_state.current_rt, read_only_dsv ? nullptr : m_state.current_ds);
|
||||
PSUnbindConflictingSRVs(m_state.current_rt_uav, m_state.current_ds_uav);
|
||||
|
||||
if (changed)
|
||||
m_ctx->OMSetRenderTargets(1, &rtv, dsv);
|
||||
|
||||
if (rt || ds)
|
||||
{
|
||||
const GSVector2i size = rt ? rt->GetSize() : ds->GetSize();
|
||||
// OM targets and UAVs share the same namespace in DX11, so we need to pack them into contiguous slots.
|
||||
const u32 num_rtvs = rt ? 1 : 0;
|
||||
ID3D11RenderTargetView* rtvs[] = {rtv};
|
||||
if (no_uavs)
|
||||
m_ctx->OMSetRenderTargets(num_rtvs, rtvs, dsv);
|
||||
else
|
||||
{
|
||||
u32 num_uavs = 0;
|
||||
ID3D11UnorderedAccessView* uavs[2];
|
||||
if (rt_uav)
|
||||
uavs[num_uavs++] = rt_uav;
|
||||
if (ds_uav)
|
||||
uavs[num_uavs++] = ds_uav;
|
||||
m_ctx->OMSetRenderTargetsAndUnorderedAccessViews(num_rtvs, rtvs, dsv, num_rtvs, num_uavs, uavs, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (rt || ds || rt_uav_tex || ds_uav_tex)
|
||||
{
|
||||
const GSVector2i size =
|
||||
rt ? rt->GetSize() :
|
||||
ds ? ds->GetSize() :
|
||||
(rt_uav_tex && rt_uav_tex != m_null_texture) ? rt_uav_tex->GetSize() :
|
||||
ds_uav_tex->GetSize();
|
||||
SetViewport(size);
|
||||
SetScissor(scissor ? *scissor : GSVector4i::loadh(size));
|
||||
}
|
||||
@@ -2786,6 +2906,10 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
{
|
||||
const GSVector2i rtsize = (config.rt ? config.rt : config.ds)->GetSize();
|
||||
GSTexture* colclip_rt = g_gs_device->GetColorClipTexture();
|
||||
GSTexture* draw_rt = config.ps.HasColorROV() ? nullptr : config.rt;
|
||||
GSTexture* draw_ds = config.ps.HasDepthROV() ? nullptr : config.ds;
|
||||
GSTexture* draw_rt_rov = config.ps.HasColorROV() ? config.rt : nullptr;
|
||||
GSTexture* draw_ds_rov = config.ps.HasDepthROV() ? config.ds : nullptr;
|
||||
GSTexture* draw_rt_clone = nullptr;
|
||||
GSTexture* draw_ds_clone = nullptr;
|
||||
GSTexture* primid_texture = nullptr;
|
||||
@@ -2806,7 +2930,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
const GSVector2i size = config.rt->GetSize();
|
||||
const GSVector4 dRect(config.colclip_update_area);
|
||||
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
|
||||
StretchRect(colclip_rt, sRect, config.rt, dRect, ShaderConvert::COLCLIP_RESOLVE, false);
|
||||
StretchRect(colclip_rt, sRect, config.rt, dRect, ShaderConvert::COLCLIP_RESOLVE, Nearest);
|
||||
Recycle(colclip_rt);
|
||||
|
||||
g_gs_device->SetColorClipTexture(nullptr);
|
||||
@@ -2834,8 +2958,10 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
|
||||
const GSVector4 dRect = GSVector4((config.colclip_mode == GSHWDrawConfig::ColClipMode::ConvertOnly) ? GSVector4i::loadh(rtsize) : config.drawarea);
|
||||
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
|
||||
StretchRect(config.rt, sRect, colclip_rt, dRect, ShaderConvert::COLCLIP_INIT, false);
|
||||
StretchRect(config.rt, sRect, colclip_rt, dRect, ShaderConvert::COLCLIP_INIT, Nearest);
|
||||
}
|
||||
|
||||
draw_rt = colclip_rt ? colclip_rt : draw_rt;
|
||||
}
|
||||
|
||||
// Destination Alpha Setup
|
||||
@@ -2850,7 +2976,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
}
|
||||
|
||||
DoStretchRect(colclip_rt ? colclip_rt : config.rt, GSVector4(config.drawarea) / GSVector4(rtsize).xyxy(),
|
||||
primid_texture, GSVector4(config.drawarea), m_date.primid_init_ps[static_cast<u8>(config.datm)].get(), nullptr, false);
|
||||
primid_texture, GSVector4(config.drawarea), m_date.primid_init_ps[static_cast<u8>(config.datm)].get(), nullptr, Nearest);
|
||||
}
|
||||
else if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::Stencil ||
|
||||
(config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne && !need_barrier))
|
||||
@@ -2921,7 +3047,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
const OMBlendSelector blend(GSHWDrawConfig::ColorMaskSelector(1),
|
||||
GSHWDrawConfig::BlendState(true, CONST_ONE, CONST_ONE, 3 /* MIN */, CONST_ONE, CONST_ZERO, false, 0));
|
||||
SetupOM(dss, blend, 0);
|
||||
OMSetRenderTargets(primid_texture, config.ds, &config.scissor, read_only_dsv);
|
||||
OMSetRenderTargets(primid_texture, config.ds, nullptr, nullptr, &config.scissor, read_only_dsv);
|
||||
SetRenderHWShaderResources(config, nullptr);
|
||||
Draw(config);
|
||||
|
||||
@@ -2931,24 +3057,28 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
}
|
||||
|
||||
// Avoid changing framebuffer just to switch from rt+depth to rt and vice versa.
|
||||
GSTexture* draw_rt = colclip_rt ? colclip_rt : config.rt;
|
||||
GSTexture* draw_ds = config.ds;
|
||||
// Make sure no tex is bound as both rtv and srv at the same time.
|
||||
// All conflicts should've been taken care of by PSUnbindConflictingSRVs.
|
||||
if (!draw_rt && draw_ds && m_state.rtv && m_state.current_rt && m_state.rtv == *static_cast<GSTexture11*>(m_state.current_rt) &&
|
||||
m_state.current_ds == draw_ds && config.tex != m_state.current_rt && m_state.current_rt->GetSize() == draw_ds->GetSize())
|
||||
if (!(draw_rt || draw_rt_rov) && draw_ds && m_state.current_rt && config.tex != m_state.current_rt && m_state.current_rt->GetSize() == draw_ds->GetSize())
|
||||
{
|
||||
draw_rt = m_state.current_rt;
|
||||
}
|
||||
else if (!draw_ds && draw_rt && m_state.dsv && m_state.current_ds && m_state.dsv == *static_cast<GSTexture11*>(m_state.current_ds) &&
|
||||
m_state.current_rt == draw_rt && config.tex != m_state.current_ds && m_state.current_ds->GetSize() == draw_rt->GetSize())
|
||||
else if (!(draw_ds || draw_ds_rov) && draw_rt && m_state.current_ds && config.tex != m_state.current_ds && m_state.current_ds->GetSize() == draw_rt->GetSize())
|
||||
{
|
||||
draw_ds = m_state.current_ds;
|
||||
}
|
||||
else if (!(draw_rt || draw_rt_rov) && draw_ds_rov && m_state.current_rt_uav && config.tex != m_state.current_rt_uav)
|
||||
{
|
||||
draw_rt_rov = m_state.current_rt_uav;
|
||||
}
|
||||
else if (!(draw_ds || draw_ds_rov) && draw_rt_rov && m_state.current_ds_uav && config.tex != m_state.current_ds_uav)
|
||||
{
|
||||
draw_ds_rov = m_state.current_ds_uav;
|
||||
}
|
||||
|
||||
const bool rt_feedbackloop_pass1 = config.IsFeedbackLoopRT(config.ps);
|
||||
const bool rt_feedbackloop_pass2 = config.IsFeedbackLoopRT(config.alpha_second_pass.ps);
|
||||
if (draw_rt && (((config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy)) &&
|
||||
if (draw_rt && !draw_rt_rov && (((config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy)) &&
|
||||
(rt_feedbackloop_pass1 || rt_feedbackloop_pass2))))
|
||||
{
|
||||
// Requires a copy of the RT.
|
||||
@@ -2960,7 +3090,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
|
||||
const bool ds_feedbackloop_pass1 = config.IsFeedbackLoopDepth(config.ps);
|
||||
const bool ds_feedbackloop_pass2 = config.IsFeedbackLoopDepth(config.alpha_second_pass.ps);
|
||||
if (draw_ds && m_features.depth_feedback && (config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy)) &&
|
||||
if (draw_ds && !draw_ds_rov && m_features.depth_feedback && (config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy)) &&
|
||||
(ds_feedbackloop_pass1 || ds_feedbackloop_pass2))
|
||||
{
|
||||
// Requires a copy of the DS.
|
||||
@@ -2970,7 +3100,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
Console.Warning("D3D11: Failed to allocate temp texture for DS copy.");
|
||||
}
|
||||
|
||||
OMSetRenderTargets(draw_rt, draw_ds, &config.scissor, read_only_dsv);
|
||||
OMSetRenderTargets(draw_rt, draw_ds, draw_rt_rov, draw_ds_rov, &config.scissor, read_only_dsv);
|
||||
SetRenderHWShaderResources(config, primid_texture);
|
||||
SetupOM(config.depth, OMBlendSelector(config.colormask, config.blend), config.blend.constant);
|
||||
|
||||
@@ -2979,7 +3109,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
m_ctx->ClearDepthStencilView(*static_cast<GSTexture11*>(draw_ds), D3D11_CLEAR_STENCIL, 0.0f, 1);
|
||||
|
||||
SendHWDraw(config, rt_feedbackloop_pass1 ? draw_rt_clone : nullptr, draw_rt, ds_feedbackloop_pass1 ? draw_ds_clone : nullptr, draw_ds,
|
||||
config.require_one_barrier, config.require_full_barrier);
|
||||
config.require_one_barrier, config.require_full_barrier, rtsize);
|
||||
|
||||
if (config.blend_multi_pass.enable)
|
||||
{
|
||||
@@ -3007,7 +3137,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
const bool one_barrier = config.alpha_second_pass.require_one_barrier && m_features.multidraw_fb_copy;
|
||||
SetupOM(config.alpha_second_pass.depth, OMBlendSelector(config.alpha_second_pass.colormask, config.blend), config.blend.constant);
|
||||
SendHWDraw(config, rt_feedbackloop_pass2 ? draw_rt_clone : nullptr, draw_rt, ds_feedbackloop_pass2 ? draw_ds_clone : nullptr, draw_ds,
|
||||
one_barrier, config.alpha_second_pass.require_full_barrier);
|
||||
one_barrier, config.alpha_second_pass.require_full_barrier, rtsize);
|
||||
}
|
||||
|
||||
if (colclip_rt)
|
||||
@@ -3019,7 +3149,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
const GSVector2i size = config.rt->GetSize();
|
||||
const GSVector4 dRect(config.colclip_update_area);
|
||||
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
|
||||
StretchRect(colclip_rt, sRect, config.rt, dRect, ShaderConvert::COLCLIP_RESOLVE, false);
|
||||
StretchRect(colclip_rt, sRect, config.rt, dRect, ShaderConvert::COLCLIP_RESOLVE, Nearest);
|
||||
Recycle(colclip_rt);
|
||||
|
||||
g_gs_device->SetColorClipTexture(nullptr);
|
||||
@@ -3027,36 +3157,67 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice11::FeedbackCopyAndBind(const GSHWDrawConfig& config,
|
||||
GSTexture* rt, GSTexture* rt_clone, GSTexture* ds, GSTexture* ds_clone, const GSVector4i& copyarea)
|
||||
{
|
||||
if (rt_clone)
|
||||
{
|
||||
CopyRect(rt, rt_clone, copyarea, copyarea.left, copyarea.top);
|
||||
PSSetShaderResource(2, rt_clone);
|
||||
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_RT)
|
||||
PSSetShaderResource(0, rt_clone);
|
||||
}
|
||||
if (ds_clone)
|
||||
{
|
||||
CopyRect(ds, ds_clone, copyarea, copyarea.left, copyarea.top);
|
||||
PSSetShaderResource(4, ds_clone);
|
||||
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_DEPTH)
|
||||
PSSetShaderResource(0, ds_clone);
|
||||
}
|
||||
}
|
||||
|
||||
// Choose the best copy area based on the hazards and whether we need RT and/or DS copies.
|
||||
void GSDevice11::FeedbackCopyAndBind(const GSHWDrawConfig& config,
|
||||
GSTexture* rt, GSTexture* rt_clone, GSTexture* ds, GSTexture* ds_clone,
|
||||
const GSVector4i& copyarea, const GSVector4i& samplearea)
|
||||
{
|
||||
const GSVector4i rtsize = (rt ? rt : ds)->GetRect();
|
||||
|
||||
// DX11 can't do partial depth copies so only do attempt individual copies for RT hazards.
|
||||
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_RT)
|
||||
{
|
||||
const GSVector4i union_rect = config.drawarea.runion(config.samplearea);
|
||||
const u32 size_union = union_rect.width() * union_rect.height();
|
||||
const u32 size_indiv = config.drawarea.width() * config.drawarea.height() +
|
||||
config.samplearea.width() * config.samplearea.height();
|
||||
|
||||
// Do an individual copy if the union is larger than the sum of individual areas.
|
||||
if (size_union > size_indiv)
|
||||
{
|
||||
FeedbackCopyAndBind(config, rt, rt_clone, ds, ds_clone, ProcessCopyArea(rtsize, config.drawarea));
|
||||
FeedbackCopyAndBind(config, rt, rt_clone, ds, ds_clone, ProcessCopyArea(rtsize, config.samplearea));
|
||||
}
|
||||
else
|
||||
{
|
||||
FeedbackCopyAndBind(config, rt, rt_clone, ds, ds_clone, ProcessCopyArea(rtsize, union_rect));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No RT hazards so just need the draw area (or full area for DS).
|
||||
FeedbackCopyAndBind(config, rt, rt_clone, ds, ds_clone, ProcessCopyArea(rtsize, config.drawarea));
|
||||
}
|
||||
};
|
||||
|
||||
void GSDevice11::SendHWDraw(const GSHWDrawConfig& config,
|
||||
GSTexture* draw_rt_clone, GSTexture* draw_rt, GSTexture* draw_ds_clone, GSTexture* draw_ds,
|
||||
const bool one_barrier, const bool full_barrier)
|
||||
const bool one_barrier, const bool full_barrier, GSVector2i rtsize)
|
||||
{
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
if ((one_barrier || full_barrier) && !(config.IsFeedbackLoopRT(config.ps) || config.IsFeedbackLoopDepth(config.ps))) [[unlikely]]
|
||||
Console.Warning("D3D11: Possible unnecessary copy detected.");
|
||||
#endif
|
||||
|
||||
auto CopyAndBind = [&](GSVector4i drawarea) {
|
||||
if (draw_rt_clone)
|
||||
{
|
||||
CopyRect(draw_rt, draw_rt_clone, drawarea, drawarea.left, drawarea.top);
|
||||
if ((one_barrier || full_barrier))
|
||||
PSSetShaderResource(2, draw_rt_clone);
|
||||
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_RT)
|
||||
PSSetShaderResource(0, draw_rt_clone);
|
||||
}
|
||||
if (draw_ds_clone)
|
||||
{
|
||||
CopyRect(draw_ds, draw_ds_clone, drawarea, drawarea.left, drawarea.top);
|
||||
if ((one_barrier || full_barrier))
|
||||
PSSetShaderResource(4, draw_ds_clone);
|
||||
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_DEPTH)
|
||||
PSSetShaderResource(0, draw_ds_clone);
|
||||
}
|
||||
};
|
||||
|
||||
const GSVector4i rtsize(0, 0, (draw_rt ? draw_rt : draw_ds)->GetWidth(), (draw_rt ? draw_rt : draw_ds)->GetHeight());
|
||||
|
||||
if (full_barrier)
|
||||
{
|
||||
const u32 draw_list_size = static_cast<u32>(config.drawlist->size());
|
||||
@@ -3065,12 +3226,16 @@ void GSDevice11::SendHWDraw(const GSHWDrawConfig& config,
|
||||
pxAssert(config.drawlist && !config.drawlist->empty());
|
||||
pxAssert(config.drawlist_bbox && static_cast<u32>(config.drawlist_bbox->size()) == draw_list_size);
|
||||
|
||||
if (config.tex_hazard != config.TEX_HAZARD_NONE)
|
||||
FeedbackCopyAndBind(config, draw_rt, draw_rt_clone, draw_ds, draw_ds_clone, config.samplearea);
|
||||
|
||||
for (u32 n = 0, p = 0; n < draw_list_size; n++)
|
||||
{
|
||||
const u32 count = (*config.drawlist)[n] * indices_per_prim;
|
||||
const u32 count = config.drawlist->at(n) * indices_per_prim;
|
||||
|
||||
const GSVector4i original_bbox = (*config.drawlist_bbox)[n].rintersect(config.drawarea);
|
||||
CopyAndBind(ProcessCopyArea(rtsize, original_bbox));
|
||||
const GSVector4i bbox = config.drawlist_bbox->at(n).rintersect(config.drawarea);
|
||||
|
||||
FeedbackCopyAndBind(config, draw_rt, draw_rt_clone, draw_ds, draw_ds_clone, bbox);
|
||||
|
||||
Draw(config, p, count);
|
||||
|
||||
@@ -3082,32 +3247,13 @@ void GSDevice11::SendHWDraw(const GSHWDrawConfig& config,
|
||||
|
||||
if (one_barrier)
|
||||
{
|
||||
// DX11 can't do partial depth copies.
|
||||
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_RT)
|
||||
{
|
||||
const GSVector4i union_rect = config.drawarea.runion(config.samplearea);
|
||||
const u32 size_union = union_rect.width() * union_rect.height();
|
||||
const u32 size_indiv = config.drawarea.width() * config.drawarea.height() +
|
||||
config.samplearea.width() * config.samplearea.height();
|
||||
|
||||
// Do an individual copy if the union is larger than the sum of individual areas.
|
||||
if (size_union > size_indiv)
|
||||
{
|
||||
CopyAndBind(ProcessCopyArea(rtsize, config.drawarea));
|
||||
CopyAndBind(ProcessCopyArea(rtsize, config.samplearea));
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyAndBind(ProcessCopyArea(rtsize, union_rect));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyAndBind(ProcessCopyArea(rtsize, config.drawarea));
|
||||
}
|
||||
FeedbackCopyAndBind(config, draw_rt, draw_rt_clone, draw_ds, draw_ds_clone, config.drawarea, config.samplearea);
|
||||
}
|
||||
|
||||
Draw(config);
|
||||
|
||||
if (config.ps.HasColorROV() || config.ps.HasDepthROV())
|
||||
g_perfmon.Put(GSPerfMon::DrawCallsROV, 1);
|
||||
}
|
||||
|
||||
void GSDevice11::SetRenderHWShaderResources(const GSHWDrawConfig& config, GSTexture* primid_texture)
|
||||
@@ -3115,13 +3261,13 @@ void GSDevice11::SetRenderHWShaderResources(const GSHWDrawConfig& config, GSText
|
||||
if (config.tex && config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_NONE)
|
||||
{
|
||||
CommitClear(config.tex);
|
||||
PSSetShaderResource(0, config.tex);
|
||||
PSSetShaderResource(TEXTURE_TEXTURE, config.tex);
|
||||
}
|
||||
if (config.pal)
|
||||
{
|
||||
CommitClear(config.pal);
|
||||
PSSetShaderResource(1, config.pal);
|
||||
PSSetShaderResource(TEXTURE_PALETTE, config.pal);
|
||||
}
|
||||
if (primid_texture)
|
||||
PSSetShaderResource(3, primid_texture);
|
||||
PSSetShaderResource(TEXTURE_PRIMID, primid_texture);
|
||||
}
|
||||
|
||||
@@ -83,6 +83,11 @@ public:
|
||||
private:
|
||||
enum : u32
|
||||
{
|
||||
TEXTURE_TEXTURE = 0,
|
||||
TEXTURE_PALETTE = 1,
|
||||
TEXTURE_RT = 2,
|
||||
TEXTURE_PRIMID = 3,
|
||||
TEXTURE_DEPTH = 4,
|
||||
MAX_TEXTURES = 5,
|
||||
MAX_SAMPLERS = 1,
|
||||
VERTEX_BUFFER_SIZE = 32 * 1024 * 1024,
|
||||
@@ -102,8 +107,8 @@ private:
|
||||
void PopTimestampQuery();
|
||||
void KickTimestampQuery();
|
||||
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) override;
|
||||
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) override;
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const Filter filter) override;
|
||||
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, Filter filter, const InterlaceConstantBuffer& cb) override;
|
||||
void DoFXAA(GSTexture* sTex, GSTexture* dTex) override;
|
||||
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) override;
|
||||
|
||||
@@ -129,6 +134,8 @@ private:
|
||||
wil::com_ptr_nothrow<ID3D11ShaderResourceView> m_expand_vb_srv;
|
||||
wil::com_ptr_nothrow<ID3D11ShaderResourceView> m_expand_ib_vs_srv;
|
||||
|
||||
GSTexture* m_null_texture;
|
||||
|
||||
D3D_FEATURE_LEVEL m_feature_level = D3D_FEATURE_LEVEL_10_0;
|
||||
u32 m_vb_pos = 0; // bytes
|
||||
u32 m_ib_pos = 0; // indices/sizeof(u16)
|
||||
@@ -141,6 +148,7 @@ private:
|
||||
bool m_is_exclusive_fullscreen = false;
|
||||
bool m_conservative_depth = false;
|
||||
bool m_rgba16_unorm_hw_blend = false;
|
||||
bool m_uav_texture = false;
|
||||
|
||||
struct
|
||||
{
|
||||
@@ -166,8 +174,12 @@ private:
|
||||
u8 bf;
|
||||
ID3D11RenderTargetView* rtv;
|
||||
ID3D11DepthStencilView* dsv;
|
||||
ID3D11UnorderedAccessView* rt_uav;
|
||||
ID3D11UnorderedAccessView* ds_uav;
|
||||
GSTexture* current_rt;
|
||||
GSTexture* current_ds;
|
||||
GSTexture* current_rt_uav;
|
||||
GSTexture* current_ds_uav;
|
||||
} m_state;
|
||||
|
||||
std::array<std::array<wil::com_ptr_nothrow<ID3D11Query>, 3>, NUM_TIMESTAMP_QUERIES> m_timestamp_queries = {};
|
||||
@@ -182,7 +194,7 @@ private:
|
||||
{
|
||||
wil::com_ptr_nothrow<ID3D11InputLayout> il;
|
||||
wil::com_ptr_nothrow<ID3D11VertexShader> vs;
|
||||
wil::com_ptr_nothrow<ID3D11PixelShader> ps[static_cast<int>(ShaderConvert::Count)];
|
||||
std::vector<wil::com_ptr_nothrow<ID3D11PixelShader>> ps;
|
||||
wil::com_ptr_nothrow<ID3D11SamplerState> ln;
|
||||
wil::com_ptr_nothrow<ID3D11SamplerState> pt;
|
||||
wil::com_ptr_nothrow<ID3D11DepthStencilState> dss;
|
||||
@@ -190,6 +202,16 @@ private:
|
||||
std::array<wil::com_ptr_nothrow<ID3D11BlendState>, 16> bs;
|
||||
} m_convert;
|
||||
|
||||
ID3D11PixelShader* GetConvertShader(ShaderConvertSelector shader) const
|
||||
{
|
||||
return m_convert.ps[shader.Index()].get();
|
||||
}
|
||||
|
||||
ID3D11PixelShader* GetConvertShader(ShaderConvert shader) const
|
||||
{
|
||||
return m_convert.ps[ShaderConvertSelector(shader).Index()].get();
|
||||
}
|
||||
|
||||
struct
|
||||
{
|
||||
wil::com_ptr_nothrow<ID3D11InputLayout> il;
|
||||
@@ -268,9 +290,9 @@ private:
|
||||
std::string m_tfx_source;
|
||||
|
||||
protected:
|
||||
using GSDevice::DoStretchRect; // Suppress overloaded virtual function warning
|
||||
virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear) override;
|
||||
|
||||
ShaderConvertSelector shader, Filter filter) override;
|
||||
public:
|
||||
GSDevice11();
|
||||
~GSDevice11() override;
|
||||
@@ -322,13 +344,13 @@ public:
|
||||
|
||||
void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY) override;
|
||||
|
||||
void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, bool linear);
|
||||
void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, ID3D11BlendState* bs, bool linear);
|
||||
void PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear) override;
|
||||
void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, Filter filter);
|
||||
void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, ID3D11BlendState* bs, Filter filter);
|
||||
void PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, Filter filter) override;
|
||||
void UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) override;
|
||||
void ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) override;
|
||||
void FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min, const GSVector4& dRect) override;
|
||||
void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) override;
|
||||
void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader) override;
|
||||
void DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, const GSVector2& ds);
|
||||
|
||||
void SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSVector4i& bbox);
|
||||
@@ -361,7 +383,8 @@ public:
|
||||
|
||||
void OMSetDepthStencilState(ID3D11DepthStencilState* dss, u8 sref);
|
||||
void OMSetBlendState(ID3D11BlendState* bs, u8 bf);
|
||||
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor = nullptr, ID3D11DepthStencilView* read_only_dsv = nullptr);
|
||||
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, GSTexture* rt_uav = nullptr, GSTexture* ds_uav = nullptr,
|
||||
const GSVector4i* scissor = nullptr, ID3D11DepthStencilView* read_only_dsv = nullptr);
|
||||
void SetViewport(const GSVector2i& viewport);
|
||||
void SetScissor(const GSVector4i& scissor);
|
||||
|
||||
@@ -372,9 +395,15 @@ public:
|
||||
void SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, u8 afix);
|
||||
|
||||
void RenderHW(GSHWDrawConfig& config) override;
|
||||
|
||||
void FeedbackCopyAndBind(const GSHWDrawConfig& config,
|
||||
GSTexture* rt, GSTexture* rt_clone, GSTexture* ds, GSTexture* ds_clone, const GSVector4i& copyarea);
|
||||
void FeedbackCopyAndBind(const GSHWDrawConfig& config,
|
||||
GSTexture* rt, GSTexture* rt_clone, GSTexture* ds, GSTexture* ds_clone,
|
||||
const GSVector4i& copyarea, const GSVector4i& samplearea);
|
||||
void SendHWDraw(const GSHWDrawConfig& config,
|
||||
GSTexture* draw_rt_clone, GSTexture* draw_rt, GSTexture* draw_ds_clone, GSTexture* draw_ds,
|
||||
const bool one_barrier, const bool full_barrier);
|
||||
const bool one_barrier, const bool full_barrier, GSVector2i rtsize);
|
||||
void SetRenderHWShaderResources(const GSHWDrawConfig& config, GSTexture* primid_texture);
|
||||
|
||||
void ClearSamplerCache() override;
|
||||
|
||||
@@ -28,23 +28,24 @@ DXGI_FORMAT GSTexture11::GetDXGIFormat(Format format)
|
||||
// clang-format off
|
||||
switch (format)
|
||||
{
|
||||
case GSTexture::Format::Color: return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case GSTexture::Format::ColorHQ: return DXGI_FORMAT_R10G10B10A2_UNORM;
|
||||
case GSTexture::Format::ColorHDR: return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
case GSTexture::Format::ColorClip: return DXGI_FORMAT_R16G16B16A16_UNORM;
|
||||
case GSTexture::Format::DepthStencil: return DXGI_FORMAT_R32G8X24_TYPELESS;
|
||||
case GSTexture::Format::UNorm8: return DXGI_FORMAT_A8_UNORM;
|
||||
case GSTexture::Format::UInt16: return DXGI_FORMAT_R16_UINT;
|
||||
case GSTexture::Format::UInt32: return DXGI_FORMAT_R32_UINT;
|
||||
case GSTexture::Format::PrimID: return DXGI_FORMAT_R32_FLOAT;
|
||||
case GSTexture::Format::BC1: return DXGI_FORMAT_BC1_UNORM;
|
||||
case GSTexture::Format::BC2: return DXGI_FORMAT_BC2_UNORM;
|
||||
case GSTexture::Format::BC3: return DXGI_FORMAT_BC3_UNORM;
|
||||
case GSTexture::Format::BC7: return DXGI_FORMAT_BC7_UNORM;
|
||||
case GSTexture::Format::Invalid:
|
||||
default:
|
||||
pxAssert(0);
|
||||
return DXGI_FORMAT_UNKNOWN;
|
||||
case GSTexture::Format::Color: return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case GSTexture::Format::ColorHQ: return DXGI_FORMAT_R10G10B10A2_UNORM;
|
||||
case GSTexture::Format::ColorHDR: return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
case GSTexture::Format::ColorClip: return DXGI_FORMAT_R16G16B16A16_UNORM;
|
||||
case GSTexture::Format::DepthStencil: return DXGI_FORMAT_R32G8X24_TYPELESS;
|
||||
case GSTexture::Format::DepthColor: return DXGI_FORMAT_R32_FLOAT;
|
||||
case GSTexture::Format::UNorm8: return DXGI_FORMAT_A8_UNORM;
|
||||
case GSTexture::Format::UInt16: return DXGI_FORMAT_R16_UINT;
|
||||
case GSTexture::Format::UInt32: return DXGI_FORMAT_R32_UINT;
|
||||
case GSTexture::Format::PrimID: return DXGI_FORMAT_R32_FLOAT;
|
||||
case GSTexture::Format::BC1: return DXGI_FORMAT_BC1_UNORM;
|
||||
case GSTexture::Format::BC2: return DXGI_FORMAT_BC2_UNORM;
|
||||
case GSTexture::Format::BC3: return DXGI_FORMAT_BC3_UNORM;
|
||||
case GSTexture::Format::BC7: return DXGI_FORMAT_BC7_UNORM;
|
||||
case GSTexture::Format::Invalid:
|
||||
default:
|
||||
pxAssert(0);
|
||||
return DXGI_FORMAT_UNKNOWN;
|
||||
}
|
||||
// clang-format on
|
||||
}
|
||||
@@ -101,6 +102,8 @@ void GSTexture11::SetDebugName(std::string_view name)
|
||||
GSDevice11::SetD3DDebugObjectName(m_srv.get(), fmt::format("{} SRV", name));
|
||||
if (m_rtv)
|
||||
GSDevice11::SetD3DDebugObjectName(m_rtv.get(), fmt::format("{} RTV", name));
|
||||
|
||||
m_debug_name = name;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,7 +19,6 @@ class GSTexture11 final : public GSTexture
|
||||
wil::com_ptr_nothrow<ID3D11UnorderedAccessView> m_uav;
|
||||
wil::com_ptr_nothrow<ID3D11DepthStencilView> m_read_only_dsv;
|
||||
D3D11_TEXTURE2D_DESC m_desc;
|
||||
|
||||
public:
|
||||
explicit GSTexture11(wil::com_ptr_nothrow<ID3D11Texture2D> texture, const D3D11_TEXTURE2D_DESC& desc,
|
||||
GSTexture::Type type, GSTexture::Format format);
|
||||
|
||||
@@ -354,6 +354,31 @@ u32 D3D12::RootSignatureBuilder::AddDescriptorTable(
|
||||
return index;
|
||||
}
|
||||
|
||||
// Allows using ranges of non-contiguous shader registers in a single descriptor table.
|
||||
u32 D3D12::RootSignatureBuilder::AddDescriptorTableMultiRange(u32 num_ranges,
|
||||
D3D12_DESCRIPTOR_RANGE_TYPE* rt, u32* start_shader_reg, u32* num_shader_regs, D3D12_SHADER_VISIBILITY visibility)
|
||||
{
|
||||
const u32 index = m_desc.NumParameters++;
|
||||
const u32 dr_index = m_num_descriptor_ranges;
|
||||
m_num_descriptor_ranges += num_ranges;
|
||||
|
||||
for (u32 i = 0; i < num_ranges; i++)
|
||||
{
|
||||
m_descriptor_ranges[dr_index + i].RangeType = rt[i];
|
||||
m_descriptor_ranges[dr_index + i].NumDescriptors = num_shader_regs[i];
|
||||
m_descriptor_ranges[dr_index + i].BaseShaderRegister = start_shader_reg[i];
|
||||
m_descriptor_ranges[dr_index + i].RegisterSpace = 0;
|
||||
m_descriptor_ranges[dr_index + i].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
}
|
||||
|
||||
m_params[index].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
m_params[index].DescriptorTable.pDescriptorRanges = &m_descriptor_ranges[dr_index];
|
||||
m_params[index].DescriptorTable.NumDescriptorRanges = num_ranges;
|
||||
m_params[index].ShaderVisibility = visibility;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "common/RedtapeWilCom.h"
|
||||
|
||||
#include <array>
|
||||
#include <d3d12.h>
|
||||
#include <directx/d3d12.h>
|
||||
#include <string_view>
|
||||
|
||||
class D3D12ShaderCache;
|
||||
@@ -37,6 +37,8 @@ namespace D3D12
|
||||
u32 AddSRVParameter(u32 shader_reg, D3D12_SHADER_VISIBILITY visibility);
|
||||
u32 AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE rt, u32 start_shader_reg, u32 num_shader_regs,
|
||||
D3D12_SHADER_VISIBILITY visibility);
|
||||
u32 AddDescriptorTableMultiRange(u32 num_ranges, D3D12_DESCRIPTOR_RANGE_TYPE* rt, u32* start_shader_reg,
|
||||
u32* num_shader_regs, D3D12_SHADER_VISIBILITY visibility);
|
||||
|
||||
private:
|
||||
D3D12_ROOT_SIGNATURE_DESC m_desc{};
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <bitset>
|
||||
#include <cstring>
|
||||
#include <d3d12.h>
|
||||
#include <directx/d3d12.h>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "common/RedtapeWilCom.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <d3d12.h>
|
||||
#include <directx/d3d12.h>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "common/RedtapeWilCom.h"
|
||||
#include "common/Assertions.h"
|
||||
|
||||
#include <d3d12.h>
|
||||
#include <directx/d3d12.h>
|
||||
#include <deque>
|
||||
#include <utility>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -56,6 +56,44 @@ public:
|
||||
D3D12_RESOURCE_DESC desc;
|
||||
};
|
||||
|
||||
enum class ResourceType
|
||||
{
|
||||
SRV, // Shader resource view
|
||||
FBL, // Feedback loop
|
||||
UAV, // Unordered access
|
||||
};
|
||||
|
||||
D3D12DescriptorHandle GetResourceDescriptor(GSTexture12* tex, ResourceType type) const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ResourceType::SRV:
|
||||
return tex->GetSRVDescriptor();
|
||||
case ResourceType::FBL:
|
||||
return m_enhanced_barriers ? tex->GetSRVDescriptor() : tex->GetFBLDescriptor();
|
||||
case ResourceType::UAV:
|
||||
return tex->GetUAVDescriptor();
|
||||
default:
|
||||
pxFailRel("Impossible.");
|
||||
return D3D12DescriptorHandle{ 0, 0 };
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr GSTexture12::ResourceState GetResourceState(ResourceType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ResourceType::SRV:
|
||||
case ResourceType::FBL:
|
||||
return GSTexture12::ResourceState::PixelShaderResource;
|
||||
case ResourceType::UAV:
|
||||
return GSTexture12::ResourceState::PixelShaderUAV;
|
||||
default:
|
||||
pxFailRel("Impossible.");
|
||||
return static_cast<GSTexture12::ResourceState>(-1);
|
||||
}
|
||||
}
|
||||
|
||||
__fi IDXGIAdapter1* GetAdapter() const { return m_adapter.get(); }
|
||||
__fi ID3D12Device* GetDevice() const { return m_device.get(); }
|
||||
__fi ID3D12CommandQueue* GetCommandQueue() const { return m_command_queue.get(); }
|
||||
@@ -96,7 +134,6 @@ public:
|
||||
D3D12DescriptorHeapManager& GetRTVHeapManager() { return m_rtv_heap_manager; }
|
||||
D3D12DescriptorHeapManager& GetDSVHeapManager() { return m_dsv_heap_manager; }
|
||||
D3D12DescriptorHeapManager& GetSamplerHeapManager() { return m_sampler_heap_manager; }
|
||||
const D3D12DescriptorHandle& GetNullSRVDescriptor() const { return m_null_srv_descriptor; }
|
||||
D3D12StreamBuffer& GetTextureStreamBuffer() { return m_texture_stream_buffer; }
|
||||
|
||||
// Root signature access.
|
||||
@@ -198,7 +235,6 @@ private:
|
||||
D3D12DescriptorHeapManager m_rtv_heap_manager;
|
||||
D3D12DescriptorHeapManager m_dsv_heap_manager;
|
||||
D3D12DescriptorHeapManager m_sampler_heap_manager;
|
||||
D3D12DescriptorHandle m_null_srv_descriptor;
|
||||
|
||||
D3D_FEATURE_LEVEL m_feature_level = D3D_FEATURE_LEVEL_11_0;
|
||||
|
||||
@@ -224,14 +260,13 @@ public:
|
||||
GSHWDrawConfig::VSSelector vs;
|
||||
GSHWDrawConfig::DepthStencilSelector dss;
|
||||
GSHWDrawConfig::ColorMaskSelector cms;
|
||||
u8 pad;
|
||||
|
||||
__fi bool operator==(const PipelineSelector& p) const { return BitEqual(*this, p); }
|
||||
__fi bool operator!=(const PipelineSelector& p) const { return !BitEqual(*this, p); }
|
||||
|
||||
__fi PipelineSelector() { std::memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
static_assert(sizeof(PipelineSelector) == 24, "Pipeline selector is 24 bytes");
|
||||
static_assert(sizeof(PipelineSelector) == 32, "Pipeline selector is 32 bytes");
|
||||
|
||||
struct PipelineSelectorHash
|
||||
{
|
||||
@@ -282,11 +317,14 @@ public:
|
||||
TEXTURE_RT = 2,
|
||||
TEXTURE_PRIMID = 3,
|
||||
TEXTURE_DEPTH = 4,
|
||||
TEXTURE_RT_UAV = 5,
|
||||
TEXTURE_DEPTH_UAV = 6,
|
||||
|
||||
NUM_TFX_CONSTANT_BUFFERS = 2,
|
||||
NUM_TFX_TEXTURES = 2,
|
||||
NUM_TFX_RT_TEXTURES = 3,
|
||||
NUM_TOTAL_TFX_TEXTURES = NUM_TFX_TEXTURES + NUM_TFX_RT_TEXTURES,
|
||||
NUM_TFX_UAV_TEXTURES = 2,
|
||||
NUM_TOTAL_TFX_TEXTURES = NUM_TFX_TEXTURES + NUM_TFX_RT_TEXTURES + NUM_TFX_UAV_TEXTURES,
|
||||
NUM_TFX_SAMPLERS = 1,
|
||||
NUM_UTILITY_TEXTURES = 1,
|
||||
NUM_UTILITY_SAMPLERS = 1,
|
||||
@@ -346,18 +384,27 @@ private:
|
||||
|
||||
std::unordered_map<u32, D3D12DescriptorHandle> m_samplers;
|
||||
|
||||
std::array<ComPtr<ID3D12PipelineState>, static_cast<int>(ShaderConvert::Count)> m_convert{};
|
||||
std::vector<ComPtr<ID3D12PipelineState>> m_convert;
|
||||
std::array<ComPtr<ID3D12PipelineState>, static_cast<int>(PresentShader::Count)> m_present{};
|
||||
std::array<ComPtr<ID3D12PipelineState>, 32> m_color_copy{};
|
||||
std::array<ComPtr<ID3D12PipelineState>, 2> m_merge{};
|
||||
std::array<ComPtr<ID3D12PipelineState>, NUM_INTERLACE_SHADERS> m_interlace{};
|
||||
std::array<ComPtr<ID3D12PipelineState>, 2> m_colclip_setup_pipelines{}; // [depth]
|
||||
std::array<ComPtr<ID3D12PipelineState>, 2> m_colclip_finish_pipelines{}; // [depth]
|
||||
std::array<std::array<ComPtr<ID3D12PipelineState>, 4>, 2> m_date_image_setup_pipelines{}; // [depth][datm]
|
||||
std::array<std::array<ComPtr<ID3D12PipelineState>, 4>, 2> m_primid_image_setup_pipelines{}; // [depth][datm]
|
||||
ComPtr<ID3D12PipelineState> m_fxaa_pipeline;
|
||||
ComPtr<ID3D12PipelineState> m_shadeboost_pipeline;
|
||||
ComPtr<ID3D12PipelineState> m_imgui_pipeline;
|
||||
|
||||
ID3D12PipelineState* GetConvertPipeline(ShaderConvertSelector shader) const
|
||||
{
|
||||
return m_convert[shader.Index()].get();
|
||||
}
|
||||
|
||||
ID3D12PipelineState* GetConvertPipeline(ShaderConvert shader) const
|
||||
{
|
||||
return m_convert[ShaderConvertSelector(shader).Index()].get();
|
||||
}
|
||||
|
||||
std::unordered_map<u32, ComPtr<ID3DBlob>> m_tfx_vertex_shaders;
|
||||
std::unordered_map<GSHWDrawConfig::PSSelector, ComPtr<ID3DBlob>, GSHWDrawConfig::PSSelectorHash>
|
||||
m_tfx_pixel_shaders;
|
||||
@@ -376,7 +423,7 @@ private:
|
||||
std::string m_tfx_source;
|
||||
|
||||
void LookupNativeFormat(GSTexture::Format format, DXGI_FORMAT* d3d_format, DXGI_FORMAT* srv_format,
|
||||
DXGI_FORMAT* rtv_format, DXGI_FORMAT* dsv_format) const;
|
||||
DXGI_FORMAT* rtv_format, DXGI_FORMAT* dsv_format, DXGI_FORMAT* uav_format) const;
|
||||
|
||||
u32 GetSwapChainBufferCount() const;
|
||||
bool CreateSwapChain();
|
||||
@@ -388,9 +435,9 @@ private:
|
||||
GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
|
||||
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE,
|
||||
const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) final;
|
||||
const GSRegEXTBUF& EXTBUF, u32 c, const Filter filter) final;
|
||||
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) final;
|
||||
ShaderInterlace shader, Filter filter, const InterlaceConstantBuffer& cb) final;
|
||||
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) final;
|
||||
void DoFXAA(GSTexture* sTex, GSTexture* dTex) final;
|
||||
|
||||
@@ -430,9 +477,11 @@ private:
|
||||
void DestroyResources();
|
||||
|
||||
protected:
|
||||
using GSDevice::DoStretchRect; // Suppress overloaded virtual function warning
|
||||
virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear) override;
|
||||
|
||||
ShaderConvertSelector shader, Filter filter) override;
|
||||
virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, const GSVector4& dRect,
|
||||
PresentShader shader, Filter filter) override;
|
||||
public:
|
||||
GSDevice12();
|
||||
~GSDevice12() override;
|
||||
@@ -478,7 +527,7 @@ public:
|
||||
void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY) override;
|
||||
|
||||
void PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
PresentShader shader, float shaderTime, bool linear) override;
|
||||
PresentShader shader, float shaderTime, Filter filter) override;
|
||||
void UpdateCLUTTexture(
|
||||
GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) override;
|
||||
void ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM,
|
||||
@@ -486,13 +535,13 @@ public:
|
||||
void FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min, const GSVector4& dRect) override;
|
||||
|
||||
void DrawMultiStretchRects(
|
||||
const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) override;
|
||||
void DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture12* dTex, ShaderConvert shader);
|
||||
const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader) override;
|
||||
void DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture12* dTex, ShaderConvertSelector shader);
|
||||
|
||||
void BeginRenderPassForStretchRect(
|
||||
GSTexture12* dTex, const GSVector4i& dtex_rc, const GSVector4i& dst_rc, bool allow_discard = true);
|
||||
void DoStretchRect(GSTexture12* sTex, const GSVector4& sRect, GSTexture12* dTex, const GSVector4& dRect,
|
||||
const ID3D12PipelineState* pipeline, bool linear, bool allow_discard);
|
||||
const ID3D12PipelineState* pipeline, Filter filter, bool allow_discard);
|
||||
void DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect, const GSVector2i& ds);
|
||||
|
||||
void SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSVector4i& bbox);
|
||||
@@ -502,11 +551,12 @@ public:
|
||||
void IASetIndexBuffer(const void* index, size_t count);
|
||||
void VSSetIndexBuffer(const void* index, size_t count);
|
||||
|
||||
void PSSetShaderResource(int i, GSTexture* sr, bool check_state, bool feedback = false);
|
||||
void PSSetShaderResource(int i, GSTexture* sr, bool check_state, ResourceType type = ResourceType::SRV);
|
||||
void PSSetSampler(GSHWDrawConfig::SamplerSelector sel);
|
||||
void PSSetUnorderedAccess(GSTexture* rt, GSTexture* ds, bool write_rt, bool write_ds);
|
||||
|
||||
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, GSTexture* ds_as_rt, const GSVector4i& scissor,
|
||||
bool depth_read = false);
|
||||
bool depth_read = false, const GSVector2i& viewport_size = {});
|
||||
|
||||
void SetVSConstantBuffer(const GSHWDrawConfig::VSConstantBuffer& cb);
|
||||
void SetPSConstantBuffer(const GSHWDrawConfig::PSConstantBuffer& cb);
|
||||
@@ -515,8 +565,8 @@ public:
|
||||
|
||||
void RenderHW(GSHWDrawConfig& config) override;
|
||||
void SendHWDraw(const PipelineSelector& pipe, const GSHWDrawConfig& config, GSTexture12* draw_rt,
|
||||
GSTexture12* draw_ds, const bool feedback_rt, const bool feedback_depth, const bool one_barrier,
|
||||
const bool full_barrier);
|
||||
GSTexture12* draw_ds, GSTexture12* draw_rt_rov, GSTexture12* draw_ds_rov,
|
||||
const bool feedback_rt, const bool feedback_depth, const bool one_barrier, const bool full_barrier);
|
||||
|
||||
void UpdateHWPipelineSelector(GSHWDrawConfig& config);
|
||||
void UploadHWDrawVerticesAndIndices(GSHWDrawConfig& config);
|
||||
@@ -582,8 +632,8 @@ private:
|
||||
DIRTY_FLAG_PS_CONSTANT_BUFFER_BINDING = (1 << 6),
|
||||
DIRTY_FLAG_VS_VERTEX_BUFFER_BINDING = (1 << 7),
|
||||
DIRTY_FLAG_VS_INDEX_BUFFER_BINDING = (1 << 8),
|
||||
DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE = (1 << 9),
|
||||
DIRTY_FLAG_SAMPLERS_DESCRIPTOR_TABLE = (1 << 10),
|
||||
DIRTY_FLAG_SAMPLERS_DESCRIPTOR_TABLE = (1 << 9),
|
||||
DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE = (1 << 10),
|
||||
DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE_2 = (1 << 11),
|
||||
DIRTY_FLAG_VS_PUSH_CONSTANTS = (1 << 12),
|
||||
|
||||
@@ -646,6 +696,7 @@ private:
|
||||
|
||||
std::array<D3D12_GPU_VIRTUAL_ADDRESS, NUM_TFX_CONSTANT_BUFFERS> m_tfx_constant_buffers{};
|
||||
std::array<D3D12DescriptorHandle, NUM_TOTAL_TFX_TEXTURES> m_tfx_textures{};
|
||||
std::array<GSTexture12*, NUM_TFX_UAV_TEXTURES> m_tfx_textures_uav{};
|
||||
D3D12DescriptorHandle m_tfx_sampler;
|
||||
u32 m_tfx_sampler_sel = 0;
|
||||
D3D12DescriptorHandle m_tfx_textures_handle_gpu;
|
||||
|
||||
@@ -110,6 +110,10 @@ void GSTexture12::Destroy(bool defer)
|
||||
}
|
||||
|
||||
m_write_descriptor_type = WriteDescriptorType::None;
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
m_debug_name.clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
// For use with non-simultaneous textures only.
|
||||
@@ -203,6 +207,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
desc.desc1.Flags = (levels > 1 && !IsCompressedFormat(format)) ? D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET :
|
||||
D3D12_RESOURCE_FLAG_NONE;
|
||||
state = ResourceState::CopyDst;
|
||||
pxAssert(uav_format == DXGI_FORMAT_UNKNOWN);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -217,6 +222,10 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
desc.desc1.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE;
|
||||
optimized_clear_value.Format = rtv_format;
|
||||
state = ResourceState::RenderTarget;
|
||||
if (uav_format != DXGI_FORMAT_UNKNOWN)
|
||||
{
|
||||
desc.desc1.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -227,6 +236,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
desc.desc1.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
||||
optimized_clear_value.Format = dsv_format;
|
||||
state = ResourceState::DepthWriteStencil;
|
||||
pxAssert(uav_format == DXGI_FORMAT_UNKNOWN);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -235,6 +245,8 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
pxAssert(levels == 1);
|
||||
allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED;
|
||||
state = ResourceState::PixelShaderResource;
|
||||
pxAssert(uav_format != DXGI_FORMAT_UNKNOWN);
|
||||
desc.desc1.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -242,9 +254,6 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
return {};
|
||||
}
|
||||
|
||||
if (uav_format != DXGI_FORMAT_UNKNOWN)
|
||||
desc.desc1.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
|
||||
wil::com_ptr_nothrow<ID3D12Resource> resource;
|
||||
wil::com_ptr_nothrow<ID3D12Resource> resource_fbl;
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation;
|
||||
@@ -330,6 +339,12 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
if (uav_format != DXGI_FORMAT_UNKNOWN && !CreateUAVDescriptor(resource.get(), uav_format, &uav_descriptor))
|
||||
{
|
||||
dev->GetRTVHeapManager().Free(&write_descriptor);
|
||||
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -350,26 +365,15 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (uav_format != DXGI_FORMAT_UNKNOWN && !CreateUAVDescriptor(resource.get(), dsv_format, &uav_descriptor))
|
||||
{
|
||||
switch (write_descriptor_type)
|
||||
case Type::RWTexture:
|
||||
{
|
||||
case WriteDescriptorType::RTV:
|
||||
dev->GetRTVHeapManager().Free(&write_descriptor);
|
||||
break;
|
||||
case WriteDescriptorType::DSV:
|
||||
dev->GetDSVHeapManager().Free(&ro_dsv_descriptor);
|
||||
dev->GetDSVHeapManager().Free(&write_descriptor);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (uav_format != DXGI_FORMAT_UNKNOWN && !CreateUAVDescriptor(resource.get(), uav_format, &uav_descriptor))
|
||||
{
|
||||
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
break;
|
||||
}
|
||||
|
||||
// Feedback descriptor used with legacy barriers
|
||||
@@ -442,7 +446,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
|
||||
|
||||
if (uav_format != DXGI_FORMAT_UNKNOWN)
|
||||
{
|
||||
if (!CreateUAVDescriptor(resource.get(), srv_format, &uav_descriptor))
|
||||
if (!CreateUAVDescriptor(resource.get(), uav_format, &uav_descriptor))
|
||||
{
|
||||
switch (write_descriptor_type)
|
||||
{
|
||||
@@ -796,6 +800,8 @@ void GSTexture12::SetDebugName(std::string_view name)
|
||||
return;
|
||||
|
||||
D3D12::SetObjectName(m_resource.get(), name);
|
||||
|
||||
m_debug_name = name;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1137,6 +1143,14 @@ void GSTexture12::TransitionSubresourceToState(const D3D12CommandList& cmdlist,
|
||||
|
||||
cmdlist.list4->ResourceBarrier(num_barriers, barriers);
|
||||
}
|
||||
|
||||
// Count as a UAV barrier if we transition to/from UAV.
|
||||
if (IsRenderTargetOrDepthStencil() &&
|
||||
(before_state == ResourceState::PixelShaderUAV || after_state == ResourceState::PixelShaderUAV))
|
||||
{
|
||||
g_perfmon.Put(GSPerfMon::Barriers, 1);
|
||||
g_perfmon.Put(GSPerfMon::BarriersROV, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void GSTexture12::CommitClear()
|
||||
@@ -1159,7 +1173,7 @@ void GSTexture12::CommitClear(const D3D12CommandList& cmdlist)
|
||||
else
|
||||
{
|
||||
TransitionToState(cmdlist, ResourceState::RenderTarget);
|
||||
cmdlist.list4->ClearRenderTargetView(GetWriteDescriptor(), GSVector4::unorm8(m_clear_value.color).v, 0, nullptr);
|
||||
cmdlist.list4->ClearRenderTargetView(GetWriteDescriptor(), GetClearForFormat().v, 0, nullptr);
|
||||
}
|
||||
|
||||
SetState(GSTexture::State::Dirty);
|
||||
|
||||
@@ -56,6 +56,8 @@ public:
|
||||
__fi ID3D12Resource* GetResource() const { return m_resource.get(); }
|
||||
__fi ID3D12Resource* GetFBLResource() const { return m_resource_fbl.get(); }
|
||||
|
||||
virtual bool IsUnorderedAccess() const override { return GetResourceState() == ResourceState::PixelShaderUAV; }
|
||||
|
||||
void* GetNativeHandle() const override;
|
||||
|
||||
bool Update(const GSVector4i& r, const void* data, int pitch, int layer = 0) override;
|
||||
|
||||
@@ -1135,14 +1135,14 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,
|
||||
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);
|
||||
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->StretchRectAuto(rt_again->m_texture, source_rect, tex, dRect, Nearest);
|
||||
|
||||
g_gs_device->Recycle(rt_again->m_texture);
|
||||
rt_again->m_texture = tex;
|
||||
@@ -1172,7 +1172,7 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,
|
||||
// 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);
|
||||
g_gs_device->StretchRectAutoMask(src->m_texture, sRect, rt, dRect, true, true, true, false);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1358,8 +1358,10 @@ bool GSHwHack::MV_Growlanser(GSRendererHW& r)
|
||||
|
||||
GL_INS("MV_Growlanser: %x -> %x %dx%d", RSBP, RDBP, src->GetUnscaledWidth(), src->GetUnscaledHeight());
|
||||
|
||||
g_gs_device->StretchRect(src->GetTexture(), GSVector4(rc) / GSVector4(src->GetUnscaledSize()).xyxy(),
|
||||
dst->GetTexture(), GSVector4(rc) * GSVector4(dst->GetScale()), ShaderConvert::RGBA8_TO_FLOAT32, false);
|
||||
g_gs_device->StretchRectAuto(
|
||||
src->GetTexture(), GSVector4(rc) / GSVector4(src->GetUnscaledSize()).xyxy(),
|
||||
dst->GetTexture(), GSVector4(rc) * GSVector4(dst->GetScale()),
|
||||
Nearest);
|
||||
|
||||
s_last_hacked_move_n = r.s_n;
|
||||
return true;
|
||||
|
||||
@@ -1358,10 +1358,10 @@ GSVector4i GSRendererHW::ComputeBoundingBoxRT(const GSVector2i& rtsize, float rt
|
||||
return GSVector4i(box * GSVector4(rtscale)).rintersect(GSVector4i(0, 0, rtsize.x, rtsize.y));
|
||||
}
|
||||
|
||||
GSVector4i GSRendererHW::ComputeBoundingBoxTex(const GSVector2i& texsize, const GSVector4i& region, float texscale)
|
||||
GSVector4i GSRendererHW::ComputeBoundingBoxTex(const GSVector2i& texsize, const GSVector4i& coverage, const GSVector4i& region, float texscale)
|
||||
{
|
||||
const GSVector4 offset = GSVector4(region.xyxy()) + GSVector4(-1.0f, -1.0f, 1.0f, 1.0f); // Region offset + round value
|
||||
const GSVector4 box = m_vt.m_min.t.upld(m_vt.m_max.t) + offset;
|
||||
const GSVector4 box = GSVector4(coverage) + offset;
|
||||
return GSVector4i(box * GSVector4(texscale)).rintersect(GSVector4i(0, 0, texsize.x, texsize.y));
|
||||
}
|
||||
|
||||
@@ -3016,8 +3016,11 @@ void GSRendererHW::Draw()
|
||||
{
|
||||
GL_CACHE("HW: Pre-draw resolve of colclip! Address: %x", FRAME.TBP0);
|
||||
GSTexture* colclip_texture = g_gs_device->GetColorClipTexture();
|
||||
g_gs_device->StretchRect(colclip_texture, GSVector4(m_conf.colclip_update_area) / GSVector4(GSVector4i(colclip_texture->GetSize()).xyxy()), old_rt->m_texture, GSVector4(m_conf.colclip_update_area),
|
||||
ShaderConvert::COLCLIP_RESOLVE, false);
|
||||
const GSVector4 colclip_texture_dims = GSVector4(GSVector4i(colclip_texture->GetSize()).xyxy());
|
||||
g_gs_device->StretchRect(
|
||||
colclip_texture, GSVector4(m_conf.colclip_update_area) / colclip_texture_dims,
|
||||
old_rt->m_texture, GSVector4(m_conf.colclip_update_area),
|
||||
ShaderConvert::COLCLIP_RESOLVE, Nearest);
|
||||
|
||||
g_gs_device->Recycle(colclip_texture);
|
||||
|
||||
@@ -4218,7 +4221,7 @@ void GSRendererHW::Draw()
|
||||
static_cast<float>((ds->m_valid.w + vertical_offset + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetHeight()));
|
||||
|
||||
GL_CACHE("HW: RT in RT Z copy back draw %lld z_vert_offset %d z_offset %d", s_n, z_vertical_offset, vertical_offset);
|
||||
g_gs_device->StretchRect(g_texture_cache->GetTemporaryZ(), sRect, ds->m_texture, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
|
||||
g_gs_device->StretchRectAuto(g_texture_cache->GetTemporaryZ(), sRect, ds->m_texture, GSVector4(dRect), Nearest);
|
||||
}
|
||||
|
||||
g_texture_cache->InvalidateTemporaryZ();
|
||||
@@ -4234,7 +4237,7 @@ void GSRendererHW::Draw()
|
||||
sRect = sRect.min(GSVector4(1.0f));
|
||||
dRect = dRect.min_u32(GSVector4i(ds->m_unscaled_size.x * ds->m_scale, ds->m_unscaled_size.y * ds->m_scale).xyxy());
|
||||
|
||||
g_gs_device->StretchRect(ds->m_texture, sRect, g_texture_cache->GetTemporaryZ(), GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
|
||||
g_gs_device->StretchRectAuto(ds->m_texture, sRect, g_texture_cache->GetTemporaryZ(), GSVector4(dRect), Nearest);
|
||||
z_address_info.rect_since = GSVector4i::zero();
|
||||
g_texture_cache->SetTemporaryZInfo(z_address_info);
|
||||
}
|
||||
@@ -4260,7 +4263,7 @@ void GSRendererHW::Draw()
|
||||
const int new_height = std::min(2048, std::max(t_size.y, static_cast<int>(vertical_size))) * ds->m_scale;
|
||||
const int new_width = std::min(2048, std::max(t_size.x, static_cast<int>(horizontal_size))) * ds->m_scale;
|
||||
|
||||
if (GSTexture* tex = g_gs_device->CreateDepthStencil(new_width, new_height, GSTexture::Format::DepthStencil, true))
|
||||
if (GSTexture* tex = g_gs_device->CreateDepthStencil(new_width, new_height, true))
|
||||
{
|
||||
GSVector4 sRect = GSVector4(static_cast<float>(z_horizontal_offset) / static_cast<float>(ds->m_unscaled_size.x), static_cast<float>(z_vertical_offset) / static_cast<float>(ds->m_unscaled_size.y), 1.0f , 1.0f);
|
||||
|
||||
@@ -4281,7 +4284,7 @@ void GSRendererHW::Draw()
|
||||
|
||||
if (m_cached_ctx.TEST.ZTST > ZTST_ALWAYS || !dRect.rintersect(GSVector4i(GSVector4(m_r) * ds->m_scale)).eq(dRect))
|
||||
{
|
||||
g_gs_device->StretchRect(ds->m_texture, sRect, tex, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
|
||||
g_gs_device->StretchRectAuto(ds->m_texture, sRect, tex, GSVector4(dRect), Nearest);
|
||||
}
|
||||
g_texture_cache->SetTemporaryZ(tex);
|
||||
g_texture_cache->SetTemporaryZInfo(ds->m_TEX0.TBP0, page_offset, rt_page_offset);
|
||||
@@ -4869,10 +4872,9 @@ void GSRendererHW::Draw()
|
||||
|
||||
if (z_width != new_w || z_height != new_h)
|
||||
{
|
||||
if (GSTexture* tex = g_gs_device->CreateDepthStencil(new_w * ds->m_scale, new_h * ds->m_scale, GSTexture::Format::DepthStencil, true))
|
||||
if (GSTexture* tex = g_gs_device->CreateDepthStencil(new_w * ds->m_scale, new_h * ds->m_scale, true))
|
||||
{
|
||||
const GSVector4i dRect = GSVector4i(0, 0, g_texture_cache->GetTemporaryZ()->GetWidth(), g_texture_cache->GetTemporaryZ()->GetHeight());
|
||||
g_gs_device->StretchRect(g_texture_cache->GetTemporaryZ(), GSVector4(0.0f, 0.0f, 1.0f, 1.0f), tex, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
|
||||
g_gs_device->StretchRectAuto(g_texture_cache->GetTemporaryZ(), tex, Nearest);
|
||||
g_texture_cache->InvalidateTemporaryZ();
|
||||
g_texture_cache->SetTemporaryZ(tex);
|
||||
}
|
||||
@@ -5178,7 +5180,7 @@ void GSRendererHW::Draw()
|
||||
static_cast<float>((real_rect.w + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetHeight()));
|
||||
|
||||
GL_CACHE("HW: RT in RT Z copy back draw %lld z_vert_offset %d rt_vert_offset %d z_horz_offset %d rt_horz_offset %d", s_n, z_vertical_offset, vertical_offset, z_horizontal_offset, horizontal_offset);
|
||||
g_gs_device->StretchRect(g_texture_cache->GetTemporaryZ(), sRect, ds->m_texture, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
|
||||
g_gs_device->StretchRectAuto(g_texture_cache->GetTemporaryZ(), sRect, ds->m_texture, GSVector4(dRect), Nearest);
|
||||
}
|
||||
else if (m_temp_z_full_copy)
|
||||
{
|
||||
@@ -5190,7 +5192,7 @@ void GSRendererHW::Draw()
|
||||
static_cast<float>((ds->m_valid.w + vertical_offset + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetHeight()));
|
||||
|
||||
GL_CACHE("HW: RT in RT Z copy back draw %lld z_vert_offset %d z_offset %d", s_n, z_vertical_offset, vertical_offset);
|
||||
g_gs_device->StretchRect(g_texture_cache->GetTemporaryZ(), sRect, ds->m_texture, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
|
||||
g_gs_device->StretchRectAuto(g_texture_cache->GetTemporaryZ(), sRect, ds->m_texture, GSVector4(dRect), Nearest);
|
||||
}
|
||||
|
||||
m_temp_z_full_copy = false;
|
||||
@@ -5219,8 +5221,11 @@ void GSRendererHW::Draw()
|
||||
if (writeback_colclip_texture)
|
||||
{
|
||||
GSTexture* colclip_texture = g_gs_device->GetColorClipTexture();
|
||||
g_gs_device->StretchRect(colclip_texture, GSVector4(m_conf.colclip_update_area) / GSVector4(GSVector4i(colclip_texture->GetSize()).xyxy()), rt->m_texture, GSVector4(m_conf.colclip_update_area),
|
||||
ShaderConvert::COLCLIP_RESOLVE, false);
|
||||
const GSVector4 colclip_texture_dims = GSVector4(GSVector4i(colclip_texture->GetSize()).xyxy());
|
||||
g_gs_device->StretchRect(
|
||||
colclip_texture, GSVector4(m_conf.colclip_update_area) / colclip_texture_dims,
|
||||
rt->m_texture, GSVector4(m_conf.colclip_update_area),
|
||||
ShaderConvert::COLCLIP_RESOLVE, Nearest);
|
||||
}
|
||||
|
||||
const u64 frame = g_perfmon.GetFrame();
|
||||
@@ -5800,9 +5805,7 @@ void GSRendererHW::DetermineAlphaScaling(GSTextureCache::Target* rt, GSTextureCa
|
||||
|
||||
void GSRendererHW::EmulateAA1()
|
||||
{
|
||||
const GSDevice::FeatureSupport& features = g_gs_device->Features();
|
||||
|
||||
pxAssert(!features.aa1 || features.feedback_loops());
|
||||
pxAssert(!g_gs_device->Features().aa1 || g_gs_device->Features().feedback_loops());
|
||||
|
||||
if (IsCoverageAlphaSupported())
|
||||
{
|
||||
@@ -6032,8 +6035,7 @@ void GSRendererHW::EmulateDATEGetConfig(DATEOptions& date_options, bool scale_rt
|
||||
if (date_stencil_needs_ds)
|
||||
{
|
||||
const bool need_barrier = m_conf.require_one_barrier || (m_conf.require_full_barrier && features.feedback_loops());
|
||||
if ((temp_ds.reset(g_gs_device->CreateDepthStencil(m_conf.rt->GetWidth(), m_conf.rt->GetHeight(),
|
||||
GSTexture::Format::DepthStencil, false)), temp_ds))
|
||||
if ((temp_ds.reset(g_gs_device->CreateDepthStencil(m_conf.rt->GetWidth(), m_conf.rt->GetHeight(), false)), temp_ds))
|
||||
{
|
||||
m_conf.ds = temp_ds.get();
|
||||
}
|
||||
@@ -6161,7 +6163,7 @@ void GSRendererHW::DetermineVSConfig(GSTextureCache::Target* rt, float rtscale,
|
||||
m_conf.vs.iip = !IsFlatShaded();
|
||||
}
|
||||
|
||||
void GSRendererHW::DetermineBarriers(GSTextureCache::Target* rt)
|
||||
void GSRendererHW::DetermineBarriers(GSTextureCache::Target* rt, GSTextureCache::Source* tex)
|
||||
{
|
||||
const GSDevice::FeatureSupport& features = g_gs_device->Features();
|
||||
|
||||
@@ -6415,7 +6417,7 @@ bool GSRendererHW::TestChannelShuffle(GSTextureCache::Target* src)
|
||||
|
||||
__ri u32 GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool test_only, GSTextureCache::Target* rt)
|
||||
{
|
||||
if (src && (src->m_texture->GetType() == GSTexture::Type::DepthStencil) && !src->m_32_bits_fmt)
|
||||
if (src && src->m_texture->IsDepthLike() && !src->m_32_bits_fmt)
|
||||
{
|
||||
// So far 2 games hit this code path. Urban Chaos and Tales of Abyss
|
||||
// UC: will copy depth to green channel
|
||||
@@ -6813,6 +6815,13 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, DATEOptio
|
||||
m_conf.ps.blend_d = 2;
|
||||
}
|
||||
|
||||
// Save in case needed for ROV setup.
|
||||
m_optimized_blend.A = m_conf.ps.blend_a;
|
||||
m_optimized_blend.B = m_conf.ps.blend_b;
|
||||
m_optimized_blend.C = m_conf.ps.blend_c;
|
||||
m_optimized_blend.D = m_conf.ps.blend_d;
|
||||
m_optimized_blend.FIX = AFIX;
|
||||
|
||||
// TODO: blend_ad_alpha_masked, as well as other blend cases can be optimized on dx11/dx12/gl to use
|
||||
// blend multipass more which might be faster, vk likely won't benefit as barriers are already fast.
|
||||
|
||||
@@ -6989,8 +6998,11 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, DATEOptio
|
||||
if (colclip_texture->GetSize() != rt->m_texture->GetSize())
|
||||
{
|
||||
GL_CACHE("HW: Pre-Blend resolve of colclip due to size change! Address: %x", rt->m_TEX0.TBP0);
|
||||
g_gs_device->StretchRect(colclip_texture, GSVector4(m_conf.colclip_update_area) / GSVector4(GSVector4i(colclip_texture->GetSize()).xyxy()), rt->m_texture, GSVector4(m_conf.colclip_update_area),
|
||||
ShaderConvert::COLCLIP_RESOLVE, false);
|
||||
const GSVector4 colclip_texture_dims = GSVector4(GSVector4i(colclip_texture->GetSize()).xyxy());
|
||||
g_gs_device->StretchRect(
|
||||
colclip_texture, GSVector4(m_conf.colclip_update_area) / colclip_texture_dims,
|
||||
rt->m_texture, GSVector4(m_conf.colclip_update_area),
|
||||
ShaderConvert::COLCLIP_RESOLVE, Nearest);
|
||||
|
||||
g_gs_device->Recycle(colclip_texture);
|
||||
|
||||
@@ -7463,6 +7475,396 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, DATEOptio
|
||||
}
|
||||
}
|
||||
|
||||
// In certain cases using a ROV with depth or color will force the other one
|
||||
// because of how color and depth interact via testing.
|
||||
__fi void GSRendererHW::GetForcedROVUsage(bool& rov_color, bool& rov_depth)
|
||||
{
|
||||
// Cannot force if both are already enabled or disabled.
|
||||
if (rov_color == rov_depth)
|
||||
return;
|
||||
|
||||
// If depth and color have feedback and one uses ROV, the other must also.
|
||||
// We currently don't have a way of using barriers in one and ROV in the other.
|
||||
if ((m_conf.ps.IsFeedbackLoopRT() && rov_depth) || (m_conf.ps.IsFeedbackLoopDepth() && rov_color))
|
||||
{
|
||||
GL_INS("ROV: Feedback compatibility forces color and depth ROV");
|
||||
rov_color = true;
|
||||
rov_depth = true;
|
||||
}
|
||||
|
||||
// If we use color ROV with discard or the pixel shader writes to depth,
|
||||
// we cannot use early depth stencil, so must use depth ROV with feedback.
|
||||
// Same applies in reverse for depth ROV forcing color ROV with feedback.
|
||||
const bool color_write = (m_conf.colormask.wrgba != 0);
|
||||
const bool depth_test = m_cached_ctx.DepthRead();
|
||||
|
||||
// Separate flag for DATE since they are many methods and the interaction with ROV is not clear.
|
||||
const bool date = m_cached_ctx.TEST.DATE;
|
||||
|
||||
if (m_conf.ds && rov_color && (m_conf.ps.HasShaderDiscard() || m_conf.ps.HasDepthOutput() || date))
|
||||
{
|
||||
GL_INS("ROV: Color ROV with shader discard/depth write forces depth ROV");
|
||||
rov_depth = true;
|
||||
}
|
||||
else if (m_conf.rt && color_write && rov_depth && (m_conf.ps.HasShaderDiscard() || depth_test || date))
|
||||
{
|
||||
GL_INS("ROV: Depth ROV with shader discard forces color ROV");
|
||||
rov_color = true;
|
||||
}
|
||||
}
|
||||
|
||||
void GSRendererHW::DetermineROVUsage(GSTextureCache::Target* rt, GSTextureCache::Target* ds)
|
||||
{
|
||||
const GSDevice::FeatureSupport& features = g_gs_device->Features();
|
||||
|
||||
if (!(GSConfig.HWROV && features.rov))
|
||||
return;
|
||||
|
||||
GL_PUSH("HW: ROV Setup");
|
||||
|
||||
if (features.framebuffer_fetch)
|
||||
{
|
||||
GL_INS("ROV: Disabled because have FB-fetch");
|
||||
return;
|
||||
}
|
||||
|
||||
if (rt && rt->m_texture == m_conf.tex && !m_conf.ps.tex_is_fb)
|
||||
{
|
||||
GL_INS("ROV: Disabled because tex is RT and not sampling from current pixel");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ds && ds->m_texture == m_conf.tex)
|
||||
{
|
||||
GL_INS("ROV: Disabled because tex is depth");
|
||||
return;
|
||||
}
|
||||
|
||||
const bool color_write = rt && m_conf.colormask.wrgba != 0;
|
||||
const bool depth_write = ds && m_cached_ctx.DepthWrite();
|
||||
|
||||
const u32 colormask = GSUtil::GetChannelMask(m_cached_ctx.FRAME.PSM) & m_conf.colormask.wrgba;
|
||||
const bool colormask_needs_rt = colormask != 0xF;
|
||||
|
||||
const u32 ate = m_cached_ctx.TEST.ATE;
|
||||
const u32 atst = m_cached_ctx.TEST.ATST;
|
||||
const u32 afail = m_cached_ctx.TEST.AFAIL;
|
||||
|
||||
const bool afail_needs_rt = ate && ((afail == AFAIL_ZB_ONLY) || (afail == AFAIL_RGB_ONLY));
|
||||
const bool afail_needs_depth = ate && ((afail == AFAIL_FB_ONLY) || (afail == AFAIL_RGB_ONLY));
|
||||
|
||||
const bool blend = m_conf.IsBlending();
|
||||
const bool blend_needs_rt = blend &&
|
||||
(m_optimized_blend.A == ALPHA_ABD_CD || m_optimized_blend.B == ALPHA_ABD_CD ||
|
||||
m_optimized_blend.C == ALPHA_C_AD || m_optimized_blend.D == ALPHA_ABD_CD);
|
||||
|
||||
const bool two_pass_alpha = GSHWDrawConfig::HasAlphaTestSecondPass(m_conf.alpha_test);
|
||||
|
||||
const bool date = m_conf.destination_alpha != GSHWDrawConfig::DestinationAlphaMode::Off;
|
||||
|
||||
const bool ztst = m_cached_ctx.DepthRead();
|
||||
|
||||
const bool full_barrier = m_conf.require_full_barrier;
|
||||
|
||||
// Heuristically determine what ROVs would be needed to eliminate passes based on the current config.
|
||||
const bool multipass_color = (full_barrier && m_conf.ps.IsFeedbackLoopRT()) ||
|
||||
two_pass_alpha ||
|
||||
m_conf.blend_multi_pass.enable;
|
||||
|
||||
const bool multipass_depth = (full_barrier && m_conf.ps.IsFeedbackLoopDepth()) || two_pass_alpha;
|
||||
|
||||
// If already ROV, just continue the usage.
|
||||
const bool color_is_rov = rt && rt->m_texture->IsUnorderedAccess();
|
||||
const bool depth_is_rov = ds && ds->m_texture->IsDepthColor();
|
||||
|
||||
bool use_rov_color = (color_write && multipass_color) || color_is_rov;
|
||||
bool use_rov_depth = (depth_write && multipass_depth) || depth_is_rov;
|
||||
|
||||
// In certain cases, ROV in color or depth will force ROV in the other for correctness.
|
||||
GetForcedROVUsage(use_rov_color, use_rov_depth);
|
||||
|
||||
// Get the number of barriers that would be used with the current config.
|
||||
u32 barriers = 1;
|
||||
if (full_barrier)
|
||||
{
|
||||
if (m_drawlist.size() > 0)
|
||||
{
|
||||
barriers = static_cast<u32>(m_drawlist.size()); // Already computed
|
||||
}
|
||||
else
|
||||
{
|
||||
barriers = 2; // Tells drawlist computation to stop after reaching 2.
|
||||
GetPrimitiveOverlapDrawlist(false, false, 1.0f, &barriers);
|
||||
}
|
||||
}
|
||||
|
||||
const u32 multiplier = m_conf.alpha_second_pass.enable ? 2 : 1; // Alpha second pass doubles the barriers.
|
||||
barriers *= multiplier;
|
||||
|
||||
// Heuristic: only activate ROV if we save at least one draw call by doing so.
|
||||
const bool activate = (use_rov_color != color_is_rov || use_rov_depth != depth_is_rov) && barriers >= 2;
|
||||
|
||||
if (!color_is_rov && !depth_is_rov && !activate)
|
||||
{
|
||||
// Not enough barriers or no feedback to activate, and ROV is not already active.
|
||||
GL_ROV("No ROV usage: Draw=%05lld | C=%016p | D=%016p | BAR=%d.",
|
||||
s_n, rt ? rt->m_texture : nullptr, ds ? ds->m_texture : nullptr, barriers);
|
||||
return;
|
||||
}
|
||||
|
||||
if (activate)
|
||||
{
|
||||
GL_ROV("ROV activated: Draw=%05lld | C=%016p | D=%016p | BAR=%d | C=[%d=>%d] | D=[%d=>%d].",
|
||||
s_n, rt ? rt->m_texture : nullptr, ds ? ds->m_texture : nullptr, barriers,
|
||||
color_is_rov, use_rov_color, depth_is_rov, use_rov_depth);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL_ROV("ROV continued: Draw=%05lld | C=%016p | D=%016p | BAR=%d | C=%d | D=%d.",
|
||||
s_n, rt ? rt->m_texture : nullptr, ds ? ds->m_texture : nullptr, barriers,
|
||||
color_is_rov, depth_is_rov);
|
||||
}
|
||||
|
||||
GL_INS("ROV: Color ROV %s / depth ROV %s",
|
||||
use_rov_color ? "enabled" : "disabled", use_rov_depth ? "enabled" : "disabled");
|
||||
|
||||
// Do the actual pipeline config.
|
||||
ConfigureROV(use_rov_color, use_rov_depth);
|
||||
}
|
||||
|
||||
void GSRendererHW::ConfigureROV(bool color_rov, bool depth_rov)
|
||||
{
|
||||
// Do the actual config for depth.
|
||||
if (depth_rov)
|
||||
{
|
||||
m_conf.depth = GSHWDrawConfig::DepthStencilSelector::NoDepth(); // Disable real depth.
|
||||
const bool depth_write = m_cached_ctx.DepthWrite();
|
||||
GL_INS("ROV: Using %s depth ROV", depth_write ? "read/write" : "read-only");
|
||||
ConfigureDepthFeedback(true);
|
||||
m_conf.ps.rov_depth = depth_write ? GSHWDrawConfig::PS_ROV_DEPTH::READ_WRITE : GSHWDrawConfig::PS_ROV_DEPTH::READ_ONLY;
|
||||
}
|
||||
|
||||
// Do the actual config for color.
|
||||
if (color_rov)
|
||||
{
|
||||
// FbMask setup
|
||||
if (m_conf.colormask.wrgba != 0)
|
||||
{
|
||||
const GSVector4i fbmask = GSVector4i(m_conf.colormask.wr ? 0 : 0xFF, m_conf.colormask.wg ? 0 : 0xFF,
|
||||
m_conf.colormask.wb ? 0 : 0xFF, m_conf.colormask.wa ? 0 : 0xFF);
|
||||
if (!m_conf.ps.fbmask)
|
||||
{
|
||||
// Don't enable FB mask emulation, just use the mask for ROV.
|
||||
m_conf.cb_ps.FbMask = fbmask;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_conf.cb_ps.FbMask |= fbmask;
|
||||
}
|
||||
GL_INS("ROV: FbMask={ R=%x, G=%x, B=%x, A=%x }",
|
||||
m_conf.cb_ps.FbMask.r, m_conf.cb_ps.FbMask.g, m_conf.cb_ps.FbMask.b, m_conf.cb_ps.FbMask.a);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_conf.ps.no_color = true;
|
||||
}
|
||||
|
||||
// Blend setup
|
||||
if (m_conf.IsBlending())
|
||||
{
|
||||
GL_INS("ROV: Using SW blend%s", m_conf.blend.enable ? " and disabling HW" : "");
|
||||
m_conf.ps.blend_a = m_optimized_blend.A;
|
||||
m_conf.ps.blend_b = m_optimized_blend.B;
|
||||
m_conf.ps.blend_c = m_optimized_blend.C;
|
||||
m_conf.ps.blend_d = m_optimized_blend.D;
|
||||
|
||||
if (m_conf.ps.blend_c == ALPHA_C_FIX)
|
||||
m_conf.cb_ps.TA_MaxDepth_Af.a = m_optimized_blend.FIX / 128.0f;
|
||||
|
||||
// Disable HW or mixed blend or multipass blend
|
||||
m_conf.blend = {};
|
||||
m_conf.ps.blend_hw = false;
|
||||
m_conf.ps.blend_mix = false;
|
||||
m_conf.blend_multi_pass = {};
|
||||
|
||||
if (!m_conf.ps.no_color1)
|
||||
{
|
||||
// We should never need dual source with SW blend
|
||||
GL_INS("ROV: Disabling dual source blending");
|
||||
m_conf.ps.no_color1 = true;
|
||||
}
|
||||
|
||||
// Only needed with HW blend.
|
||||
m_conf.ps.round_inv = false;
|
||||
m_conf.ps.a_masked = false;
|
||||
}
|
||||
|
||||
// Dither setup
|
||||
if (m_conf.ps.dither)
|
||||
{
|
||||
// Only needed with HW blend.
|
||||
m_conf.ps.dither_adjust = false;
|
||||
}
|
||||
|
||||
// Destination alpha test setup
|
||||
if (m_conf.destination_alpha != GSHWDrawConfig::DestinationAlphaMode::Off)
|
||||
{
|
||||
GL_INS("ROV: Using DATE Full%s",
|
||||
(m_conf.destination_alpha != GSHWDrawConfig::DestinationAlphaMode::Full) ? " and replace current method" : "");
|
||||
|
||||
if (m_conf.destination_alpha != GSHWDrawConfig::DestinationAlphaMode::Full)
|
||||
{
|
||||
m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Full;
|
||||
m_conf.depth.date = false; // Don't use stencil with ROV
|
||||
m_conf.depth.date_one = false; // Don't use stencil with ROV
|
||||
m_conf.ps.date = 5 + m_cached_ctx.TEST.DATM; // Shader discard DATM.
|
||||
m_conf.datm = static_cast<SetDATM>(0); // Not needed
|
||||
}
|
||||
}
|
||||
|
||||
// Colclip setup
|
||||
if (m_conf.ps.colclip_hw)
|
||||
{
|
||||
// Remove HW colclip texture if needed
|
||||
GL_INS("ROV: Replacing colclip HW with SW");
|
||||
const bool has_colclip_texture = g_gs_device->GetColorClipTexture() != nullptr;
|
||||
m_conf.ps.colclip_hw = 0;
|
||||
m_conf.ps.colclip = true;
|
||||
m_conf.colclip_mode = has_colclip_texture ? GSHWDrawConfig::ColClipMode::EarlyResolve : GSHWDrawConfig::ColClipMode::NoModify;
|
||||
}
|
||||
|
||||
// PABE setup
|
||||
const bool PABE = m_draw_env->PABE.PABE && GetAlphaMinMax().min < 128;
|
||||
if (m_conf.IsBlending() && PABE && !m_conf.ps.pabe)
|
||||
{
|
||||
GL_INS("ROV: Enabling PABE");
|
||||
m_conf.ps.pabe = true;
|
||||
}
|
||||
|
||||
// Alpha test setup. KEEP will already be fine.
|
||||
if (m_cached_ctx.TEST.ATE && m_conf.alpha_test != GSHWDrawConfig::AlphaTestMode::KEEP)
|
||||
{
|
||||
GL_INS("ROV: Using SW feedback alpha test%s", m_conf.alpha_second_pass.enable ?
|
||||
" and disabling alpha second pass" : "");
|
||||
|
||||
m_conf.alpha_test = GSHWDrawConfig::AlphaTestMode::FEEDBACK;
|
||||
|
||||
GSHWDrawConfig::PS_ATST ps_atst;
|
||||
float ps_aref;
|
||||
GetAlphaTestConfigPS(m_cached_ctx.TEST.ATST, m_cached_ctx.TEST.AREF, false, ps_atst, ps_aref);
|
||||
m_conf.ps.atst = ps_atst;
|
||||
m_conf.ps.afail = static_cast<GSHWDrawConfig::PS_AFAIL>(m_cached_ctx.TEST.AFAIL);
|
||||
if (m_cached_ctx.DepthWrite() && m_cached_ctx.TEST.AFAIL == AFAIL_RGB_ONLY)
|
||||
{
|
||||
pxAssert(depth_rov); // Should have enabled depth ROV for depth feedback loop.
|
||||
m_conf.ps.afail = PS_AFAIL::RGB_ONLY_SW_Z;
|
||||
}
|
||||
m_conf.cb_ps.FogColor_AREF.a = ps_aref;
|
||||
|
||||
GL_INS("ROV: Using ATST=%d, AFAIL=%d, AREF=%.2f", ps_atst, static_cast<u32>(m_conf.ps.afail), ps_aref);
|
||||
|
||||
if (m_conf.alpha_second_pass.enable)
|
||||
{
|
||||
m_conf.alpha_second_pass = {};
|
||||
}
|
||||
}
|
||||
|
||||
m_conf.ps.rov_color = true;
|
||||
}
|
||||
|
||||
// Remove regular barriers.
|
||||
if (color_rov || depth_rov)
|
||||
{
|
||||
m_conf.require_full_barrier = false;
|
||||
m_conf.require_one_barrier = false;
|
||||
}
|
||||
}
|
||||
|
||||
void GSRendererHW::SetUnorderedAccessFlag(GSTextureCache::Target* rt)
|
||||
{
|
||||
// Set flag for ROV activation heuristic. Only used by DX11.
|
||||
// Only needed for RT, as we use a different method for depth.
|
||||
if (rt)
|
||||
{
|
||||
if (m_conf.ps.HasColorROV())
|
||||
rt->m_texture->SetUnorderedAccess();
|
||||
else
|
||||
rt->m_texture->ClearUnorderedAccess();
|
||||
}
|
||||
}
|
||||
|
||||
static void CopyDepthTextureROV(GSTexture* src, GSTexture* dst)
|
||||
{
|
||||
switch (src->GetState())
|
||||
{
|
||||
case GSTexture::State::Cleared:
|
||||
g_gs_device->ClearDepth(dst, src->GetClearDepth());
|
||||
break;
|
||||
case GSTexture::State::Invalidated:
|
||||
g_gs_device->InvalidateRenderTarget(dst);
|
||||
break;
|
||||
case GSTexture::State::Dirty:
|
||||
g_gs_device->StretchRectAuto(src, dst, Nearest);
|
||||
break;
|
||||
}
|
||||
|
||||
// These stats are counted both as part of ROV and non-ROV stats.
|
||||
g_perfmon.Put(GSPerfMon::DepthCopiesROV, 1.0);
|
||||
g_perfmon.Put(GSPerfMon::DrawCallsROV, 1.0);
|
||||
};
|
||||
|
||||
void GSRendererHW::ConvertDepthFormatROV(GSTextureCache::Target* ds)
|
||||
{
|
||||
if (!ds)
|
||||
return;
|
||||
|
||||
GSTexture* ds_tex_old = m_conf.ds;
|
||||
GSTexture* ds_tex_new = nullptr;
|
||||
|
||||
// Convert depth to depth color or vice versa if needed.
|
||||
bool depth_to_color;
|
||||
if (m_conf.ps.HasDepthROV() && !ds_tex_old->IsDepthColor())
|
||||
{
|
||||
depth_to_color = true;
|
||||
ds_tex_new = g_gs_device->CreateDepthColor(ds_tex_old->GetSize(), false, true);
|
||||
}
|
||||
else if (!m_conf.ps.HasDepthROV() && ds_tex_old->IsDepthColor())
|
||||
{
|
||||
depth_to_color = false;
|
||||
ds_tex_new = g_gs_device->CreateDepthStencil(ds->m_texture->GetSize(), false, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GL_PUSH("HW: Convert %s for ROV.", depth_to_color ? "DepthStencil -> DepthColor" : "DepthColor -> DepthStencil");
|
||||
|
||||
CopyDepthTextureROV(ds_tex_old, ds_tex_new);
|
||||
|
||||
#if PCSX2_DEVBUILD
|
||||
ds_tex_new->SetDebugName(ds->m_texture->GetDebugName());
|
||||
#endif
|
||||
|
||||
// Fix up the texture cache.
|
||||
if (ds->m_texture == ds_tex_old)
|
||||
{
|
||||
GL_CACHE("HW: Replaced texture for DS @ 0x%04x", ds->m_TEX0.TBP0);
|
||||
ds->m_texture = ds_tex_new;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Must be the temporary Z.
|
||||
pxAssert(g_texture_cache->GetTemporaryZ() == ds_tex_old);
|
||||
GL_CACHE("HW: Replaced texture for temporary Z @ 0x%04x", g_texture_cache->GetTemporaryZInfo().ZBP);
|
||||
g_texture_cache->SetTemporaryZ(ds_tex_new);
|
||||
}
|
||||
|
||||
g_gs_device->Recycle(ds_tex_old);
|
||||
|
||||
m_conf.ds = ds_tex_new;
|
||||
}
|
||||
|
||||
__ri static constexpr bool IsRedundantClamp(u8 clamp, u32 clamp_min, u32 clamp_max, u32 tsize)
|
||||
{
|
||||
// Don't shader sample when the clamp/repeat is configured to the texture size.
|
||||
@@ -7576,7 +7978,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
|
||||
// Depth + bilinear filtering isn't done yet. But if the game has just set a Z24 swizzle on a colour texture, we can
|
||||
// just pretend it's not a depth format, since in the texture cache, it's not.
|
||||
// Other games worth testing: Area 51, Burnout
|
||||
if (psm.depth && m_vt.IsLinear() && tex->GetTexture()->IsDepthStencil())
|
||||
if (psm.depth && m_vt.IsLinear() && tex->GetTexture()->IsDepthLike())
|
||||
GL_INS("HW: WARNING: Depth + bilinear filtering not supported");
|
||||
|
||||
// Performance note:
|
||||
@@ -7595,7 +7997,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
|
||||
// Require a float conversion if the texure is a depth otherwise uses Integral scaling
|
||||
if (psm.depth)
|
||||
{
|
||||
m_conf.ps.depth_fmt = (tex->m_texture->GetType() != GSTexture::Type::DepthStencil) ? 3 : tex->m_32_bits_fmt ? 1 : 2;
|
||||
m_conf.ps.depth_fmt = !tex->m_texture->IsDepthLike() ? 3 : tex->m_32_bits_fmt ? 1 : 2;
|
||||
}
|
||||
|
||||
// Shuffle is a 16 bits format, so aem is always required
|
||||
@@ -7675,7 +8077,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
|
||||
}
|
||||
|
||||
// Depth format
|
||||
if (tex->m_texture->IsDepthStencil())
|
||||
if (tex->m_texture->IsDepthLike())
|
||||
{
|
||||
// Require a float conversion if the texure is a depth format
|
||||
m_conf.ps.depth_fmt = (psm.bpp == 16) ? 2 : 1;
|
||||
@@ -8034,7 +8436,7 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
|
||||
// Shuffles take the whole target. This should've already been halved.
|
||||
// We can't partially copy depth targets in DirectX, and GL/Vulkan should use the direct read above.
|
||||
// Restricting it also breaks Tom and Jerry...
|
||||
if (m_downscale_source || m_channel_shuffle || tex->m_texture->GetType() == GSTexture::Type::DepthStencil)
|
||||
if (m_downscale_source || m_channel_shuffle || tex->m_texture->IsDepthLike())
|
||||
{
|
||||
if (m_channel_shuffle)
|
||||
{
|
||||
@@ -8060,8 +8462,10 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
|
||||
const int clamp_horizontal_page_offset = m_cached_ctx.CLAMP.WMS == CLAMP_REGION_REPEAT ? (m_cached_ctx.CLAMP.MAXU / GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].pgs.x) : 0;
|
||||
const int clamp_vertical_page_offset = m_cached_ctx.CLAMP.WMT == CLAMP_REGION_REPEAT ? (m_cached_ctx.CLAMP.MAXV / GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].pgs.y) : 0;
|
||||
const int page_offset = ((m_cached_ctx.TEX0.TBP0 - src_target->m_TEX0.TBP0) >> 5) + clamp_horizontal_page_offset + clamp_vertical_page_offset;
|
||||
const int horizontal_offset = ((page_offset % src_target->m_TEX0.TBW) * GSLocalMemory::m_psm[src_target->m_TEX0.PSM].pgs.x);
|
||||
const int vertical_offset = ((page_offset / src_target->m_TEX0.TBW) * GSLocalMemory::m_psm[src_target->m_TEX0.PSM].pgs.y);
|
||||
const GSVector2i draw_offset = GSVector2i((static_cast<int>(m_vt.m_min.t.x) / GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].pgs.x) * GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].pgs.x,
|
||||
(static_cast<int>(m_vt.m_min.t.y) / GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].pgs.y) * GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].pgs.y);
|
||||
const int horizontal_offset = ((page_offset % src_target->m_TEX0.TBW) * GSLocalMemory::m_psm[src_target->m_TEX0.PSM].pgs.x) + draw_offset.x;
|
||||
const int vertical_offset = ((page_offset / src_target->m_TEX0.TBW) * GSLocalMemory::m_psm[src_target->m_TEX0.PSM].pgs.y) + draw_offset.y;
|
||||
|
||||
if (HandleBarrierHazard(false) || (rt != tex->m_from_target && ds != tex->m_from_target))
|
||||
{
|
||||
@@ -8182,10 +8586,8 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
|
||||
|
||||
const GSVector2i scaled_copy_size = GSVector2i(static_cast<int>(std::ceil(static_cast<float>(copy_size.x) * scale)),
|
||||
static_cast<int>(std::ceil(static_cast<float>(copy_size.y) * scale)));
|
||||
|
||||
src_copy.reset(src_target->m_texture->IsDepthStencil() ?
|
||||
g_gs_device->CreateDepthStencil(scaled_copy_size.x, scaled_copy_size.y, src_target->m_texture->GetFormat(), false) :
|
||||
g_gs_device->CreateRenderTarget(scaled_copy_size.x, scaled_copy_size.y, src_target->m_texture->GetFormat(), true, true));
|
||||
const bool clear = src_target->m_texture->IsRenderTarget();
|
||||
src_copy.reset(g_gs_device->CreateCompatible(src_target->m_texture, scaled_copy_size, clear));
|
||||
if (!src_copy) [[unlikely]]
|
||||
{
|
||||
Console.Error("HW: Failed to allocate %dx%d texture for hazard copy", scaled_copy_size.x, scaled_copy_size.y);
|
||||
@@ -8201,8 +8603,7 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
|
||||
{
|
||||
GSVector4 src_rect = GSVector4(tmm.coverage) / GSVector4(GSVector4i::loadh(src_unscaled_size).zwzw());
|
||||
const GSVector4 dst_rect = GSVector4(tmm.coverage);
|
||||
g_gs_device->StretchRect(src_target->m_texture, src_rect, src_copy.get(), dst_rect,
|
||||
src_target->m_texture->IsDepthStencil() ? ShaderConvert::DEPTH_COPY : ShaderConvert::COPY, false);
|
||||
g_gs_device->StretchRectAuto(src_target->m_texture, src_rect, src_copy.get(), dst_rect, Nearest);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -8234,8 +8635,7 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
|
||||
const GSVector4 src_rect = GSVector4(copy_range) / GSVector4(src_unscaled_size).xyxy();
|
||||
const GSVector4 dst_rect = (GSVector4(copy_range) - GSVector4(offset).xyxy()) * scale;
|
||||
|
||||
g_gs_device->StretchRect(src_target->m_texture, src_rect, src_copy.get(), dst_rect,
|
||||
src_target->m_texture->IsDepthStencil() ? ShaderConvert::DEPTH_COPY : ShaderConvert::COPY, false);
|
||||
g_gs_device->StretchRectAuto(src_target->m_texture, src_rect, src_copy.get(), dst_rect, Nearest);
|
||||
}
|
||||
m_conf.tex = src_copy.get();
|
||||
}
|
||||
@@ -8769,14 +9169,14 @@ void GSRendererHW::EmulateAlphaTestSecondPass()
|
||||
}
|
||||
|
||||
// Setup barriers and/or SW depth testing for depth feedback.
|
||||
void GSRendererHW::ConfigureDepthFeedback()
|
||||
void GSRendererHW::ConfigureDepthFeedback(bool rov_depth)
|
||||
{
|
||||
if (m_conf.ps.IsFeedbackLoopDepth())
|
||||
if (m_conf.ps.IsFeedbackLoopDepth() || rov_depth)
|
||||
{
|
||||
const GSDevice::FeatureSupport& features = g_gs_device->Features();
|
||||
|
||||
// We need barriers for the feedback.
|
||||
if (features.feedback_loops())
|
||||
// We need barriers for the feedback (except with ROV).
|
||||
if (features.feedback_loops() && !rov_depth)
|
||||
{
|
||||
m_conf.require_one_barrier |= (m_prim_overlap == PRIM_OVERLAP_NO);
|
||||
m_conf.require_full_barrier |= (m_prim_overlap != PRIM_OVERLAP_NO);
|
||||
@@ -9026,8 +9426,14 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||
m_conf.ps.rta_correction = rt->m_rt_alpha_scale;
|
||||
}
|
||||
|
||||
// Call before computing the full drawlist in case ROV is used and we don't need it.
|
||||
DetermineROVUsage(rt, ds);
|
||||
ConvertDepthFormatROV(ds);
|
||||
SetUnorderedAccessFlag(rt);
|
||||
|
||||
// Barriers must be determined before indices are modified via HandleProvokingVertexFirst/SetupIA.
|
||||
DetermineBarriers(rt);
|
||||
// This also computes the drawlist if needed.
|
||||
DetermineBarriers(rt, tex);
|
||||
|
||||
// Perform second pass setup here once barriers are determined.
|
||||
EmulateAlphaTestSecondPass();
|
||||
@@ -9046,7 +9452,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||
|
||||
const GSVector4i tex_region = tex ? tex->GetRegionRect() : GSVector4i::zero();
|
||||
m_conf.samplearea = m_channel_shuffle ? scissor :
|
||||
GSVector4i::loadh(texsize).rintersect(ComputeBoundingBoxTex(texsize, tex_region, texscale));
|
||||
GSVector4i::loadh(texsize).rintersect(ComputeBoundingBoxTex(texsize, tmm.coverage, tex_region, texscale));
|
||||
|
||||
m_conf.scissor = (date_options.enabled && !date_options.barrier) ? m_conf.drawarea : scissor;
|
||||
|
||||
@@ -9054,7 +9460,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||
|
||||
SetupIA(rtscale, vs_scale_x, vs_scale_y, m_channel_shuffle_width != 0, no_rt);
|
||||
|
||||
if (m_conf.ds && m_conf.ps.IsFeedbackLoopDepth() && !g_gs_device->Features().depth_feedback)
|
||||
if (m_conf.ds && m_conf.ps.IsFeedbackLoopDepth() && !g_gs_device->Features().depth_feedback && !m_conf.ps.HasDepthROV())
|
||||
{
|
||||
GL_PUSH("HW: Creating temporary R32 RT for depth feedback");
|
||||
|
||||
@@ -10106,7 +10512,7 @@ bool GSRendererHW::OI_BlitFMV(GSTextureCache::Target* _rt, GSTextureCache::Sourc
|
||||
th = new_height;
|
||||
const GSVector4 sRect(m_vt.m_min.t.x / tw, m_vt.m_min.t.y / th, m_vt.m_max.t.x / tw, m_vt.m_max.t.y / th);
|
||||
const GSVector4i r_full_new(0, 0, tw, th);
|
||||
g_gs_device->StretchRect(tex->m_texture, sRect, rt, dRect, ShaderConvert::COPY, m_vt.IsRealLinear());
|
||||
g_gs_device->StretchRectAuto(tex->m_texture, sRect, rt, dRect, BilnIf(m_vt.IsRealLinear()));
|
||||
g_gs_device->CopyRect(rt, tex->m_texture, r_full_new, 0, 0);
|
||||
g_gs_device->Recycle(rt);
|
||||
}
|
||||
@@ -10454,6 +10860,16 @@ void GSRendererHW::OffsetDraw(s32 fbp_offset, s32 zbp_offset, s32 xoffset, s32 y
|
||||
m_vertex->buff[i].XYZ.X += fp_xoffset;
|
||||
m_vertex->buff[i].XYZ.Y += fp_yoffset;
|
||||
}
|
||||
|
||||
m_vt.m_min.p.x += static_cast<float>(xoffset);
|
||||
m_vt.m_min.p.y += static_cast<float>(yoffset);
|
||||
m_vt.m_max.p.x += static_cast<float>(xoffset);
|
||||
m_vt.m_max.p.y += static_cast<float>(yoffset);
|
||||
|
||||
m_r.x += xoffset;
|
||||
m_r.y += yoffset;
|
||||
m_r.z += xoffset;
|
||||
m_r.w += yoffset;
|
||||
}
|
||||
|
||||
GSHWDrawConfig& GSRendererHW::BeginHLEHardwareDraw(
|
||||
|
||||
@@ -236,7 +236,7 @@ private:
|
||||
static void GetAlphaTestConfigPS(const u32 atst, const u8 aref, const bool invert_test, PS_ATST& ps_atst_out, float& aref_out);
|
||||
void EmulateAlphaTest(DATEOptions& date_options);
|
||||
void EmulateAlphaTestSecondPass();
|
||||
void ConfigureDepthFeedback();
|
||||
void ConfigureDepthFeedback(bool rov_depth = false);
|
||||
|
||||
void CalculateAlphaRange(GSTextureCache::Target* rt, GSTextureCache::Target* ds, DATEOptions& date_options,
|
||||
int& blend_alpha_min, int& blend_alpha_max, int& rt_new_alpha_min, int& rt_new_alpha_max);
|
||||
@@ -251,7 +251,13 @@ private:
|
||||
|
||||
void DetermineVSConfig(GSTextureCache::Target* rt, float rtscale, const GSVector2i& rtsize,
|
||||
const GSVector2i& unscaled_size, float& vs_scale_x, float& vs_scale_y);
|
||||
void DetermineBarriers(GSTextureCache::Target* rt);
|
||||
void DetermineBarriers(GSTextureCache::Target* rt, GSTextureCache::Source* tex);
|
||||
|
||||
void GetForcedROVUsage(bool& color_cov, bool& depth_rov); // Whether having color or depth with the current config forces the other.
|
||||
void DetermineROVUsage(GSTextureCache::Target* rt, GSTextureCache::Target* ds); // Heuristics to determine whether to enable/disable ROV
|
||||
void ConfigureROV(bool color_rov, bool depth_rov); // Actual config for ROV
|
||||
void SetUnorderedAccessFlag(GSTextureCache::Target* rt); // Set flag for DX11 ROV heuristic to work.
|
||||
void ConvertDepthFormatROV(GSTextureCache::Target* ds); // Convert between depth and depth color if needed.
|
||||
|
||||
void SetTCOffset();
|
||||
bool NextDrawColClip() const;
|
||||
@@ -330,6 +336,8 @@ private:
|
||||
|
||||
GSVector2i m_lod = {}; // Min & Max level of detail
|
||||
|
||||
GIFRegALPHA m_optimized_blend = {}; // Save for ROV setup
|
||||
|
||||
GSHWDrawConfig m_conf = {};
|
||||
HWCachedCtx m_cached_ctx;
|
||||
|
||||
@@ -356,7 +364,7 @@ public:
|
||||
void ExpandLineIndices();
|
||||
GSVector4 RealignTargetTextureCoordinate(const GSTextureCache::Source* tex);
|
||||
GSVector4i ComputeBoundingBoxRT(const GSVector2i& rtsize, float rtscale);
|
||||
GSVector4i ComputeBoundingBoxTex(const GSVector2i& texsize, const GSVector4i& region, float texscale);
|
||||
GSVector4i ComputeBoundingBoxTex(const GSVector2i& texsize, const GSVector4i& coverage, const GSVector4i& region, float texscale);
|
||||
void MergeSprite(GSTextureCache::Source* tex);
|
||||
float GetTextureScaleFactor() override;
|
||||
GSVector2i GetValidSize(const GSTextureCache::Source* tex = nullptr, const bool is_shuffle = false);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -575,10 +575,10 @@ public:
|
||||
HashCacheEntry* hc_entry, bool new_texture_is_shared);
|
||||
|
||||
/// Converts single color value to depth using the specified shader expression.
|
||||
static float ConvertColorToDepth(u32 c, ShaderConvert convert);
|
||||
static float ConvertColorToDepth(u32 c, u32 src_bpp, u32 dst_bpp);
|
||||
|
||||
/// Converts single depth value to colour using the specified shader expression.
|
||||
static u32 ConvertDepthToColor(float d, ShaderConvert convert);
|
||||
static u32 ConvertDepthToColor(float d, u32 dst_bpp);
|
||||
|
||||
/// Copies RGB channels from depth target to a color target.
|
||||
bool CopyRGBFromDepthToColor(Target* dst, Target* depth_src);
|
||||
|
||||
@@ -101,7 +101,7 @@ struct PipelineSelectorMTL
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(PipelineSelectorMTL) == 24);
|
||||
static_assert(sizeof(PipelineSelectorMTL) == 28);
|
||||
|
||||
template <>
|
||||
struct std::hash<PipelineSelectorMTL>
|
||||
@@ -249,9 +249,8 @@ public:
|
||||
|
||||
// Functions and Pipeline States
|
||||
MRCOwned<id<MTLComputePipelineState>> m_cas_pipeline[2];
|
||||
MRCOwned<id<MTLRenderPipelineState>> m_convert_pipeline[static_cast<int>(ShaderConvert::Count)];
|
||||
std::vector<MRCOwned<id<MTLRenderPipelineState>>> m_convert_pipeline;
|
||||
MRCOwned<id<MTLRenderPipelineState>> m_present_pipeline[static_cast<int>(PresentShader::Count)];
|
||||
MRCOwned<id<MTLRenderPipelineState>> m_convert_pipeline_copy_mask[1 << 5];
|
||||
MRCOwned<id<MTLRenderPipelineState>> m_merge_pipeline[4];
|
||||
MRCOwned<id<MTLRenderPipelineState>> m_interlace_pipeline[NUM_INTERLACE_SHADERS];
|
||||
MRCOwned<id<MTLRenderPipelineState>> m_datm_pipeline[4];
|
||||
@@ -265,6 +264,16 @@ public:
|
||||
MRCOwned<id<MTLRenderPipelineState>> m_shadeboost_pipeline;
|
||||
MRCOwned<id<MTLRenderPipelineState>> m_imgui_pipeline;
|
||||
|
||||
id<MTLRenderPipelineState> GetConvertPipeline(ShaderConvertSelector shader) const
|
||||
{
|
||||
return m_convert_pipeline[shader.Index()];
|
||||
}
|
||||
|
||||
id<MTLRenderPipelineState> GetConvertPipeline(ShaderConvert shader) const
|
||||
{
|
||||
return m_convert_pipeline[ShaderConvertSelector(shader).Index()];
|
||||
}
|
||||
|
||||
MRCOwned<id<MTLFunction>> m_hw_vs[6 << 3];
|
||||
std::unordered_map<PSSelector, MRCOwned<id<MTLFunction>>> m_hw_ps;
|
||||
std::unordered_map<PipelineSelectorMTL, MRCOwned<id<MTLRenderPipelineState>>> m_hw_pipeline;
|
||||
@@ -370,8 +379,8 @@ public:
|
||||
|
||||
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
|
||||
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) override;
|
||||
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) override;
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const Filter filter) override;
|
||||
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, Filter filter, const InterlaceConstantBuffer& cb) override;
|
||||
void DoFXAA(GSTexture* sTex, GSTexture* dTex) override;
|
||||
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) override;
|
||||
|
||||
@@ -411,12 +420,12 @@ public:
|
||||
|
||||
void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY) override;
|
||||
void BeginStretchRect(NSString* name, GSTexture* dTex, MTLLoadAction action);
|
||||
void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, id<MTLRenderPipelineState> pipeline, bool linear, LoadAction load_action, const void* frag_uniform, size_t frag_uniform_len);
|
||||
void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, id<MTLRenderPipelineState> pipeline, std::optional<Filter> filter, LoadAction load_action, const void* frag_uniform, size_t frag_uniform_len);
|
||||
void DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect, const GSVector2& ds);
|
||||
/// Copy from a position in sTex to the same position in the currently active render encoder using the given fs pipeline and rect
|
||||
void RenderCopy(GSTexture* sTex, id<MTLRenderPipelineState> pipeline, const GSVector4i& rect);
|
||||
void PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear) override;
|
||||
void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) override;
|
||||
void PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, Filter filter) override;
|
||||
void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader) override;
|
||||
void UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) override;
|
||||
void ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) override;
|
||||
void FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min, const GSVector4& dRect) override;
|
||||
@@ -462,8 +471,9 @@ public:
|
||||
u32 FrameNo() const { return m_frame; }
|
||||
|
||||
protected:
|
||||
using GSDevice::DoStretchRect; // Suppress overloaded virtual function warning
|
||||
virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear) override;
|
||||
ShaderConvertSelector shader, Filter filter) override;
|
||||
};
|
||||
|
||||
static constexpr bool IsCommandBufferCompleted(MTLCommandBufferStatus status)
|
||||
|
||||
@@ -402,7 +402,25 @@ void GSDeviceMTL::EndRenderPass()
|
||||
}
|
||||
}
|
||||
|
||||
void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadAction color_load, GSTexture* depth, MTLLoadAction depth_load, GSTexture* stencil, MTLLoadAction stencil_load, bool rt1)
|
||||
static GSVector4 GetRTLoadInfo(GSTextureMTL* tex, MTLLoadAction* load_action)
|
||||
{
|
||||
if (tex)
|
||||
{
|
||||
if (tex->GetState() == GSTexture::State::Invalidated)
|
||||
{
|
||||
*load_action = MTLLoadActionDontCare;
|
||||
}
|
||||
else if (tex->GetState() == GSTexture::State::Cleared && *load_action != MTLLoadActionDontCare)
|
||||
{
|
||||
*load_action = MTLLoadActionClear;
|
||||
return tex->GetClearForFormat();
|
||||
}
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadAction color_load,
|
||||
GSTexture* depth, MTLLoadAction depth_load, GSTexture* stencil, MTLLoadAction stencil_load, bool rt1)
|
||||
{
|
||||
GSTextureMTL* mc = static_cast<GSTextureMTL*>(color);
|
||||
GSTextureMTL* md = static_cast<GSTextureMTL*>(depth);
|
||||
@@ -411,31 +429,16 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio
|
||||
|| depth != m_current_render.depth_target
|
||||
|| stencil != m_current_render.stencil_target
|
||||
|| rt1 != m_current_render.has.rt1_depth;
|
||||
GSVector4 color_clear;
|
||||
float depth_clear;
|
||||
// Depth and stencil might be the same, so do all invalidation checks before resetting invalidation
|
||||
#define CHECK_CLEAR(tex, load_action, clear, ClearGetter) \
|
||||
if (tex) \
|
||||
{ \
|
||||
if (tex->GetState() == GSTexture::State::Invalidated) \
|
||||
{ \
|
||||
load_action = MTLLoadActionDontCare; \
|
||||
} \
|
||||
else if (tex->GetState() == GSTexture::State::Cleared && load_action != MTLLoadActionDontCare) \
|
||||
{ \
|
||||
clear = tex->ClearGetter(); \
|
||||
load_action = MTLLoadActionClear; \
|
||||
} \
|
||||
}
|
||||
|
||||
CHECK_CLEAR(mc, color_load, color_clear, GetUNormClearColor)
|
||||
CHECK_CLEAR(md, depth_load, depth_clear, GetClearDepth)
|
||||
#undef CHECK_CLEAR
|
||||
// Depth and stencil might be the same, so do all invalidation checks before resetting invalidation
|
||||
GSVector4 color_clear = GetRTLoadInfo(mc, &color_load);
|
||||
GSVector4 depth_clear = GetRTLoadInfo(md, &depth_load);
|
||||
|
||||
// Stencil and depth are one texture, stencil clears aren't supported
|
||||
if (ms && ms->GetState() == GSTexture::State::Invalidated)
|
||||
stencil_load = MTLLoadActionDontCare;
|
||||
needs_new |= mc && color_load == MTLLoadActionClear;
|
||||
needs_new |= md && depth_load == MTLLoadActionClear;
|
||||
needs_new |= mc && color_load == MTLLoadActionClear;
|
||||
needs_new |= md && depth_load == MTLLoadActionClear;
|
||||
|
||||
// Reset texture state
|
||||
if (mc) mc->SetState(GSTexture::State::Dirty);
|
||||
@@ -480,7 +483,7 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio
|
||||
md->m_last_write = m_current_draw;
|
||||
desc.depthAttachment.texture = md->GetTexture();
|
||||
if (depth_load == MTLLoadActionClear)
|
||||
desc.depthAttachment.clearDepth = depth_clear;
|
||||
desc.depthAttachment.clearDepth = depth_clear.x;
|
||||
desc.depthAttachment.loadAction = depth_load;
|
||||
}
|
||||
if (ms)
|
||||
@@ -496,7 +499,7 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio
|
||||
MTLRenderPassColorAttachmentDescriptor* color1 = desc.colorAttachments[1];
|
||||
color1.texture = GetRT1DepthTexture(md);
|
||||
if (m_features.framebuffer_fetch)
|
||||
color1.clearColor = MTLClearColorMake(depth_load == MTLLoadActionClear ? depth_clear : -1, 0, 0, 0);
|
||||
color1.clearColor = MTLClearColorMake(depth_load == MTLLoadActionClear ? depth_clear.x : -1, 0, 0, 0);
|
||||
}
|
||||
|
||||
EndRenderPass();
|
||||
@@ -524,7 +527,7 @@ static constexpr MTLPixelFormat ConvertPixelFormat(GSTexture::Format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case GSTexture::Format::Float32: return MTLPixelFormatR32Float;
|
||||
case GSTexture::Format::DepthColor: return MTLPixelFormatR32Float;
|
||||
case GSTexture::Format::PrimID: return MTLPixelFormatR32Float;
|
||||
case GSTexture::Format::UInt32: return MTLPixelFormatR32Uint;
|
||||
case GSTexture::Format::UInt16: return MTLPixelFormatR16Uint;
|
||||
@@ -598,7 +601,7 @@ GSTexture* GSDeviceMTL::CreateSurface(GSTexture::Type type, int width, int heigh
|
||||
}
|
||||
}}
|
||||
|
||||
void GSDeviceMTL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear)
|
||||
void GSDeviceMTL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const Filter filter)
|
||||
{ @autoreleasepool {
|
||||
id<MTLCommandBuffer> cmdbuf = GetRenderCmdBuf();
|
||||
GSScopedDebugGroupMTL dbg(cmdbuf, @"DoMerge");
|
||||
@@ -620,12 +623,12 @@ void GSDeviceMTL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||
{
|
||||
// 2nd output is enabled and selected. Copy it to destination so we can blend it with 1st output
|
||||
// Note: value outside of dRect must contains the background color (c)
|
||||
StretchRect(sTex[1], sRect[1], dTex, dRect[1], ShaderConvert::COPY, linear);
|
||||
StretchRect(sTex[1], sRect[1], dTex, dRect[1], ShaderConvert::COPY, filter);
|
||||
}
|
||||
|
||||
// Save 2nd output
|
||||
if (feedback_write_2) // FIXME I'm not sure dRect[1] is always correct
|
||||
DoStretchRect(dTex, full_r, sTex[2], dRect[1], m_convert_pipeline[static_cast<int>(ShaderConvert::YUV)], linear, LoadAction::DontCareIfFull, &cb_yuv, sizeof(cb_yuv));
|
||||
DoStretchRect(dTex, full_r, sTex[2], dRect[1], GetConvertPipeline(ShaderConvert::YUV), filter, LoadAction::DontCareIfFull, &cb_yuv, sizeof(cb_yuv));
|
||||
|
||||
if (feedback_write_2_but_blend_bg)
|
||||
ClearRenderTarget(dTex, c);
|
||||
@@ -639,26 +642,27 @@ void GSDeviceMTL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||
if (PMODE.MMOD == 1)
|
||||
{
|
||||
// Blend with a constant alpha
|
||||
DoStretchRect(sTex[0], sRect[0], dTex, dRect[0], pipeline, linear, LoadAction::Load, &cb_c, sizeof(cb_c));
|
||||
DoStretchRect(sTex[0], sRect[0], dTex, dRect[0], pipeline, filter, LoadAction::Load, &cb_c, sizeof(cb_c));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Blend with 2 * input alpha
|
||||
DoStretchRect(sTex[0], sRect[0], dTex, dRect[0], pipeline, linear, LoadAction::Load, nullptr, 0);
|
||||
DoStretchRect(sTex[0], sRect[0], dTex, dRect[0], pipeline, filter, LoadAction::Load, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (feedback_write_1) // FIXME I'm not sure dRect[0] is always correct
|
||||
StretchRect(dTex, full_r, sTex[2], dRect[0], ShaderConvert::YUV, linear);
|
||||
StretchRect(dTex, full_r, sTex[2], dRect[0], ShaderConvert::YUV, filter);
|
||||
}}
|
||||
|
||||
void GSDeviceMTL::DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb)
|
||||
void GSDeviceMTL::DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, Filter filter, const InterlaceConstantBuffer& cb)
|
||||
{ @autoreleasepool {
|
||||
id<MTLCommandBuffer> cmdbuf = GetRenderCmdBuf();
|
||||
GSScopedDebugGroupMTL dbg(cmdbuf, @"DoInterlace");
|
||||
|
||||
const bool can_discard = shader == ShaderInterlace::WEAVE || shader == ShaderInterlace::MAD_BUFFER;
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_interlace_pipeline[static_cast<int>(shader)], linear, !can_discard ? LoadAction::DontCareIfFull : LoadAction::Load, &cb, sizeof(cb));
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_interlace_pipeline[static_cast<int>(shader)], filter,
|
||||
!can_discard ? LoadAction::DontCareIfFull : LoadAction::Load, &cb, sizeof(cb));
|
||||
}}
|
||||
|
||||
void GSDeviceMTL::DoFXAA(GSTexture* sTex, GSTexture* dTex)
|
||||
@@ -890,6 +894,25 @@ static bool getDepthFeedback(const GSMTLDevice& dev, bool fbfetch)
|
||||
}
|
||||
}
|
||||
|
||||
// Some shaders are only used by methods on MTLDevice, which currently use separately-compiled shaders
|
||||
static bool ConvertShaderNotNeeded(ShaderConvert shader)
|
||||
{
|
||||
switch (shader)
|
||||
{
|
||||
case ShaderConvert::DATM_0:
|
||||
case ShaderConvert::DATM_1:
|
||||
case ShaderConvert::DATM_0_RTA_CORRECTION:
|
||||
case ShaderConvert::DATM_1_RTA_CORRECTION:
|
||||
case ShaderConvert::CLUT_4:
|
||||
case ShaderConvert::CLUT_8:
|
||||
case ShaderConvert::COLCLIP_INIT:
|
||||
case ShaderConvert::COLCLIP_RESOLVE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool GSDeviceMTL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
{ @autoreleasepool {
|
||||
if (!GSDevice::Create(vsync_mode, allow_present_throttle))
|
||||
@@ -1164,97 +1187,54 @@ bool GSDeviceMTL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
NSString* name = [NSString stringWithFormat:@"ps_interlace%zu", i];
|
||||
m_interlace_pipeline[i] = MakePipeline(pdesc, vs_convert, LoadShader(name), name);
|
||||
}
|
||||
for (size_t i = 0; i < std::size(m_convert_pipeline); i++)
|
||||
|
||||
m_convert_pipeline.resize(ShaderConvertSelector::NUM_TOTAL_SHADERS);
|
||||
for (u32 i = 0; i < ShaderConvertSelector::NUM_TOTAL_SHADERS; i++)
|
||||
{
|
||||
ShaderConvert conv = static_cast<ShaderConvert>(i);
|
||||
NSString* name = [NSString stringWithCString:shaderName(conv) encoding:NSUTF8StringEncoding];
|
||||
switch (conv)
|
||||
const ShaderConvertSelector shader = ShaderConvertSelector::Get(i);
|
||||
if (ConvertShaderNotNeeded(shader.Shader()))
|
||||
continue;
|
||||
NSString* shader_name = [NSString stringWithCString:shader.EntryPoint() encoding:NSUTF8StringEncoding];
|
||||
if (shader.DepthOutput())
|
||||
{
|
||||
case ShaderConvert::Count:
|
||||
case ShaderConvert::DATM_0:
|
||||
case ShaderConvert::DATM_1:
|
||||
case ShaderConvert::DATM_0_RTA_CORRECTION:
|
||||
case ShaderConvert::DATM_1_RTA_CORRECTION:
|
||||
case ShaderConvert::CLUT_4:
|
||||
case ShaderConvert::CLUT_8:
|
||||
case ShaderConvert::COLCLIP_INIT:
|
||||
case ShaderConvert::COLCLIP_RESOLVE:
|
||||
continue;
|
||||
case ShaderConvert::FLOAT32_TO_32_BITS:
|
||||
pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::UInt32);
|
||||
pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid;
|
||||
break;
|
||||
case ShaderConvert::FLOAT32_TO_16_BITS:
|
||||
case ShaderConvert::RGBA8_TO_16_BITS:
|
||||
pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::UInt16);
|
||||
pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid;
|
||||
break;
|
||||
case ShaderConvert::DEPTH_COPY:
|
||||
case ShaderConvert::FLOAT32_TO_FLOAT24:
|
||||
case ShaderConvert::FLOAT32_COLOR_TO_DEPTH:
|
||||
case ShaderConvert::RGBA8_TO_FLOAT32:
|
||||
case ShaderConvert::RGBA8_TO_FLOAT24:
|
||||
case ShaderConvert::RGBA8_TO_FLOAT16:
|
||||
case ShaderConvert::RGB5A1_TO_FLOAT16:
|
||||
case ShaderConvert::RGBA8_TO_FLOAT32_BILN:
|
||||
case ShaderConvert::RGBA8_TO_FLOAT24_BILN:
|
||||
case ShaderConvert::RGBA8_TO_FLOAT16_BILN:
|
||||
case ShaderConvert::RGB5A1_TO_FLOAT16_BILN:
|
||||
pdesc.colorAttachments[0].pixelFormat = MTLPixelFormatInvalid;
|
||||
pdesc.depthAttachmentPixelFormat = ConvertPixelFormat(GSTexture::Format::DepthStencil);
|
||||
break;
|
||||
case ShaderConvert::COPY:
|
||||
case ShaderConvert::DOWNSAMPLE_COPY:
|
||||
case ShaderConvert::RGBA_TO_8I: // Yes really
|
||||
case ShaderConvert::RGB5A1_TO_8I:
|
||||
case ShaderConvert::RTA_CORRECTION:
|
||||
case ShaderConvert::RTA_DECORRECTION:
|
||||
case ShaderConvert::TRANSPARENCY_FILTER:
|
||||
case ShaderConvert::FLOAT32_TO_RGBA8:
|
||||
case ShaderConvert::FLOAT32_TO_RGB8:
|
||||
case ShaderConvert::FLOAT16_TO_RGB5A1:
|
||||
case ShaderConvert::YUV:
|
||||
pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::Color);
|
||||
pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid;
|
||||
break;
|
||||
case ShaderConvert::FLOAT32_DEPTH_TO_COLOR:
|
||||
pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::Float32);
|
||||
pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid;
|
||||
break;
|
||||
pdesc.colorAttachments[0].pixelFormat = MTLPixelFormatInvalid;
|
||||
pdesc.depthAttachmentPixelFormat = ConvertPixelFormat(GSTexture::Format::DepthStencil);
|
||||
}
|
||||
const u32 scmask = ShaderConvertWriteMask(conv);
|
||||
else
|
||||
{
|
||||
pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(shader.OutputFormat());
|
||||
pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid;
|
||||
}
|
||||
NSString* name = shader_name;
|
||||
if (shader.VariableWriteMask())
|
||||
name = [name stringByAppendingString:[NSString stringWithFormat:@" Mask=%x", shader.Mask()]];
|
||||
if (shader.Biln())
|
||||
name = [name stringByAppendingString:@" Biln"];
|
||||
if (shader.Float32Output())
|
||||
name = [name stringByAppendingString:shader.DepthOutput() ? @" → Depth" : @" → Float"];
|
||||
|
||||
const u32 scmask = shader.Mask();
|
||||
MTLColorWriteMask mask = MTLColorWriteMaskNone;
|
||||
if (scmask & 1) mask |= MTLColorWriteMaskRed;
|
||||
if (scmask & 2) mask |= MTLColorWriteMaskGreen;
|
||||
if (scmask & 4) mask |= MTLColorWriteMaskBlue;
|
||||
if (scmask & 8) mask |= MTLColorWriteMaskAlpha;
|
||||
pdesc.colorAttachments[0].writeMask = mask;
|
||||
m_convert_pipeline[i] = MakePipeline(pdesc, vs_convert, LoadShader(name), name);
|
||||
setFnConstantB(m_fn_constants, shader.Biln(), GSMTLConstantIndex_BILN);
|
||||
setFnConstantB(m_fn_constants, shader.DepthOutput(), GSMTLConstantIndex_DEPTH_OUT);
|
||||
m_convert_pipeline[shader.Index()] = MakePipeline(pdesc, vs_convert, LoadShader(shader_name), name);
|
||||
}
|
||||
pdesc.colorAttachments[0].writeMask = MTLColorWriteMaskAll;
|
||||
pdesc.depthAttachmentPixelFormat = MTLPixelFormatInvalid;
|
||||
for (size_t i = 0; i < std::size(m_present_pipeline); i++)
|
||||
{
|
||||
PresentShader conv = static_cast<PresentShader>(i);
|
||||
NSString* name = [NSString stringWithCString:shaderName(conv) encoding:NSUTF8StringEncoding];
|
||||
NSString* name = [NSString stringWithCString:ShaderEntryPoint(conv) encoding:NSUTF8StringEncoding];
|
||||
pdesc.colorAttachments[0].pixelFormat = layer_px_fmt;
|
||||
m_present_pipeline[i] = MakePipeline(pdesc, vs_convert, LoadShader(name), [NSString stringWithFormat:@"present_%s", shaderName(conv) + 3]);
|
||||
m_present_pipeline[i] = MakePipeline(pdesc, vs_convert, LoadShader(name), [NSString stringWithFormat:@"present_%s", ShaderEntryPoint(conv) + 3]);
|
||||
}
|
||||
|
||||
pdesc.colorAttachments[0].pixelFormat = ConvertPixelFormat(GSTexture::Format::Color);
|
||||
for (size_t i = 0; i < std::size(m_convert_pipeline_copy_mask); i++)
|
||||
{
|
||||
MTLColorWriteMask mask = MTLColorWriteMaskNone;
|
||||
if (i & 1) mask |= MTLColorWriteMaskRed;
|
||||
if (i & 2) mask |= MTLColorWriteMaskGreen;
|
||||
if (i & 4) mask |= MTLColorWriteMaskBlue;
|
||||
if (i & 8) mask |= MTLColorWriteMaskAlpha;
|
||||
NSString* name = [NSString stringWithFormat:@"copy_%s%s%s%s%s",
|
||||
i & 1 ? "r" : "", i & 2 ? "g" : "", i & 4 ? "b" : "", i & 8 ? "a" : "", i & 16 ? "_rta" : ""];
|
||||
pdesc.colorAttachments[0].writeMask = mask;
|
||||
m_convert_pipeline_copy_mask[i] = MakePipeline(pdesc, vs_convert, i & 16 ? ps_copy_rta_correct : ps_copy, name);
|
||||
}
|
||||
|
||||
pdesc.colorAttachments[0].blendingEnabled = YES;
|
||||
pdesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
|
||||
pdesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
|
||||
@@ -1601,7 +1581,7 @@ void GSDeviceMTL::BeginStretchRect(NSString* name, GSTexture* dTex, MTLLoadActio
|
||||
MRESetDSS(dsel);
|
||||
}
|
||||
|
||||
void GSDeviceMTL::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, id<MTLRenderPipelineState> pipeline, bool linear, LoadAction load_action, const void* frag_uniform, size_t frag_uniform_len)
|
||||
void GSDeviceMTL::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, id<MTLRenderPipelineState> pipeline, std::optional<Filter> filter, LoadAction load_action, const void* frag_uniform, size_t frag_uniform_len)
|
||||
{
|
||||
FlushClears(sTex);
|
||||
|
||||
@@ -1622,7 +1602,8 @@ void GSDeviceMTL::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTextu
|
||||
if (frag_uniform && frag_uniform_len)
|
||||
[m_current_render.encoder setFragmentBytes:frag_uniform length:frag_uniform_len atIndex:GSMTLBufferIndexUniforms];
|
||||
|
||||
MRESetSampler(linear ? SamplerSelector::Linear() : SamplerSelector::Point());
|
||||
if (filter)
|
||||
MRESetSampler(*filter == Biln ? SamplerSelector::Linear() : SamplerSelector::Point());
|
||||
|
||||
DrawStretchRect(sRect, dRect, GSVector2(static_cast<float>(ds.x), static_cast<float>(ds.y)));
|
||||
}
|
||||
@@ -1667,18 +1648,15 @@ void GSDeviceMTL::RenderCopy(GSTexture* sTex, id<MTLRenderPipelineState> pipelin
|
||||
}
|
||||
|
||||
void GSDeviceMTL::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear)
|
||||
ShaderConvertSelector shader, Filter filter)
|
||||
{ @autoreleasepool {
|
||||
|
||||
const LoadAction load_action = (cms.wrgba == 0xf) ? LoadAction::DontCareIfFull : LoadAction::Load;
|
||||
id<MTLRenderPipelineState> pipeline;
|
||||
if (HasVariableWriteMask(shader))
|
||||
pipeline = m_convert_pipeline_copy_mask[GetShaderIndexForMask(shader, cms.wrgba)];
|
||||
else
|
||||
pipeline = m_convert_pipeline[static_cast<int>(shader)];
|
||||
pxAssertRel(pipeline, fmt::format("No pipeline for {}", shaderName(shader)).c_str());
|
||||
const LoadAction load_action = (shader.Mask() == 0xf) ? LoadAction::DontCareIfFull : LoadAction::Load;
|
||||
id<MTLRenderPipelineState> pipeline = GetConvertPipeline(shader);
|
||||
pxAssertRel(pipeline, fmt::format("No pipeline for {}", ShaderEntryPoint(shader.Shader())).c_str());
|
||||
std::optional<Filter> filter_if_needed = shader.SupportsBilinear() ? std::nullopt : std::make_optional(filter);
|
||||
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, pipeline, linear, load_action, nullptr, 0);
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, pipeline, filter_if_needed, load_action, nullptr, 0);
|
||||
}}
|
||||
|
||||
static_assert(sizeof(DisplayConstantBuffer) == sizeof(GSMTLPresentPSUniform));
|
||||
@@ -1691,7 +1669,7 @@ static_assert(offsetof(DisplayConstantBuffer, SourceResolution) == offsetof(G
|
||||
static_assert(offsetof(DisplayConstantBuffer, RcpSourceResolution) == offsetof(GSMTLPresentPSUniform, rcp_source_resolution));
|
||||
static_assert(offsetof(DisplayConstantBuffer, TimeAndPad.x) == offsetof(GSMTLPresentPSUniform, time));
|
||||
|
||||
void GSDeviceMTL::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear)
|
||||
void GSDeviceMTL::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, Filter filter)
|
||||
{ @autoreleasepool {
|
||||
GSVector2i ds = dTex ? dTex->GetSize() : GetWindowSize();
|
||||
DisplayConstantBuffer cb;
|
||||
@@ -1702,26 +1680,26 @@ void GSDeviceMTL::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
|
||||
|
||||
if (dTex)
|
||||
{
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, pipe, linear, LoadAction::DontCareIfFull, &cb, sizeof(cb));
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, pipe, filter, LoadAction::DontCareIfFull, &cb, sizeof(cb));
|
||||
}
|
||||
else
|
||||
{
|
||||
// !dTex → Use current draw encoder
|
||||
[m_current_render.encoder setRenderPipelineState:pipe];
|
||||
[m_current_render.encoder setFragmentSamplerState:m_sampler_hw[linear ? SamplerSelector::Linear().key : SamplerSelector::Point().key] atIndex:0];
|
||||
[m_current_render.encoder setFragmentSamplerState:m_sampler_hw[filter == Biln ? SamplerSelector::Linear().key : SamplerSelector::Point().key] atIndex:0];
|
||||
[m_current_render.encoder setFragmentTexture:static_cast<GSTextureMTL*>(sTex)->GetTexture() atIndex:0];
|
||||
[m_current_render.encoder setFragmentBytes:&cb length:sizeof(cb) atIndex:GSMTLBufferIndexUniforms];
|
||||
DrawStretchRect(sRect, dRect, GSVector2(static_cast<float>(ds.x), static_cast<float>(ds.y)));
|
||||
}
|
||||
}}
|
||||
|
||||
void GSDeviceMTL::DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader)
|
||||
void GSDeviceMTL::DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader)
|
||||
{ @autoreleasepool {
|
||||
BeginStretchRect(@"MultiStretchRect", dTex, MTLLoadActionLoad);
|
||||
|
||||
id<MTLRenderPipelineState> pipeline = nullptr;
|
||||
GSTexture* sTex = rects[0].src;
|
||||
bool linear = rects[0].linear;
|
||||
Filter filter = rects[0].filter;
|
||||
u8 wmask = rects[0].wmask.wrgba;
|
||||
|
||||
const GSVector2 ds(static_cast<float>(dTex->GetWidth()), static_cast<float>(dTex->GetHeight()));
|
||||
@@ -1737,16 +1715,14 @@ void GSDeviceMTL::DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_r
|
||||
const u32 end = i * 4;
|
||||
const u32 vertex_count = end - start;
|
||||
const u32 index_count = vertex_count + (vertex_count >> 1); // 6 indices per 4 vertices
|
||||
pxAssert(HasVariableWriteMask(shader) || wmask == 0xf);
|
||||
id<MTLRenderPipelineState> new_pipeline = wmask == 0xf ? m_convert_pipeline[static_cast<int>(shader)]
|
||||
: m_convert_pipeline_copy_mask[GetShaderIndexForMask(shader, wmask)];
|
||||
id<MTLRenderPipelineState> new_pipeline = GetConvertPipeline(shader.SetMask(wmask));
|
||||
if (new_pipeline != pipeline)
|
||||
{
|
||||
pipeline = new_pipeline;
|
||||
pxAssertRel(pipeline, fmt::format("No pipeline for {}", shaderName(shader)).c_str());
|
||||
pxAssertRel(pipeline, fmt::format("No pipeline for {}", ShaderEntryPoint(shader.Shader())).c_str());
|
||||
MRESetPipeline(pipeline);
|
||||
}
|
||||
MRESetSampler(linear ? SamplerSelector::Linear() : SamplerSelector::Point());
|
||||
MRESetSampler(filter == Biln ? SamplerSelector::Linear() : SamplerSelector::Point());
|
||||
MRESetTexture(sTex, GSMTLTextureIndexNonHW);
|
||||
[enc drawIndexedPrimitives:MTLPrimitiveTypeTriangle
|
||||
indexCount:index_count
|
||||
@@ -1762,11 +1738,11 @@ void GSDeviceMTL::DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_r
|
||||
for (u32 i = 0; i < num_rects; i++)
|
||||
{
|
||||
const MultiStretchRect& rect = rects[i];
|
||||
if (rect.src != sTex || rect.linear != linear || rect.wmask.wrgba != wmask)
|
||||
if (rect.src != sTex || rect.filter != filter || rect.wmask.wrgba != wmask)
|
||||
{
|
||||
flush(i);
|
||||
sTex = rect.src;
|
||||
linear = rect.linear;
|
||||
filter = rect.filter;
|
||||
wmask = rect.wmask.wrgba;
|
||||
}
|
||||
*write++ = CalcStrechRectPoints(rect.src_rect, rect.dst_rect, ds);
|
||||
@@ -1790,27 +1766,27 @@ void GSDeviceMTL::UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX,
|
||||
void GSDeviceMTL::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM)
|
||||
{ @autoreleasepool {
|
||||
const ShaderConvert shader = ((SPSM & 0xE) == 0) ? ShaderConvert::RGBA_TO_8I : ShaderConvert::RGB5A1_TO_8I;
|
||||
id<MTLRenderPipelineState> pipeline = m_convert_pipeline[static_cast<int>(shader)];
|
||||
id<MTLRenderPipelineState> pipeline = GetConvertPipeline(shader);
|
||||
if (!pipeline)
|
||||
[NSException raise:@"StretchRect Missing Pipeline" format:@"No pipeline for %d", static_cast<int>(shader)];
|
||||
|
||||
GSMTLIndexedConvertPSUniform uniform = { sScale, SBW, DBW, SPSM };
|
||||
|
||||
const GSVector4 dRect(0, 0, dTex->GetWidth(), dTex->GetHeight());
|
||||
DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, pipeline, false, LoadAction::DontCareIfFull, &uniform, sizeof(uniform));
|
||||
DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, pipeline, Nearest, LoadAction::DontCareIfFull, &uniform, sizeof(uniform));
|
||||
}}
|
||||
|
||||
void GSDeviceMTL::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min, const GSVector4& dRect)
|
||||
{ @autoreleasepool {
|
||||
const ShaderConvert shader = ShaderConvert::DOWNSAMPLE_COPY;
|
||||
id<MTLRenderPipelineState> pipeline = m_convert_pipeline[static_cast<int>(shader)];
|
||||
id<MTLRenderPipelineState> pipeline = GetConvertPipeline(shader);
|
||||
if (!pipeline)
|
||||
[NSException raise:@"StretchRect Missing Pipeline" format:@"No pipeline for %d", static_cast<int>(shader)];
|
||||
|
||||
GSMTLDownsamplePSUniform uniform = { {static_cast<uint>(clamp_min.x), static_cast<uint>(clamp_min.x)}, downsample_factor,
|
||||
static_cast<float>(downsample_factor * downsample_factor), (GSConfig.UserHacks_NativeScaling > GSNativeScaling::Aggressive) ? 2.0f : 1.0f };
|
||||
|
||||
DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, pipeline, false, LoadAction::DontCareIfFull, &uniform, sizeof(uniform));
|
||||
DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, pipeline, Nearest, LoadAction::DontCareIfFull, &uniform, sizeof(uniform));
|
||||
}}
|
||||
|
||||
static id<MTLTexture> CreateDSAsRTTexture(id<MTLDevice> dev, NSUInteger width, NSUInteger height, MTLStorageMode storage, NSString* name)
|
||||
@@ -1847,7 +1823,7 @@ void GSDeviceMTL::BeginDSAsRT(GSTexture* ds, const GSVector4i& drawarea)
|
||||
return;
|
||||
if (m_ds_as_rt_gstexture)
|
||||
Recycle(m_ds_as_rt_gstexture);
|
||||
m_ds_as_rt_gstexture = CreateRenderTarget(needed_width, needed_height, GSTexture::Format::Float32, false, true);
|
||||
m_ds_as_rt_gstexture = CreateRenderTarget(needed_width, needed_height, GSTexture::Format::DepthColor, false, true);
|
||||
m_ds_as_rt_texture = static_cast<GSTextureMTL*>(m_ds_as_rt_gstexture)->GetTexture();
|
||||
@autoreleasepool
|
||||
{
|
||||
@@ -2029,7 +2005,7 @@ void GSDeviceMTL::MRESetHWPipelineState(GSHWDrawConfig::VSSelector vssel, GSHWDr
|
||||
MTLRenderPipelineColorAttachmentDescriptor* color1 = [[pdesc colorAttachments] objectAtIndexedSubscript:1];
|
||||
[color1 setPixelFormat:MTLPixelFormatR32Float];
|
||||
}
|
||||
NSString* pname = [NSString stringWithFormat:@"HW Render %x.%x.%llx.%x", vssel_mtl.key, pssel.key_hi, pssel.key_lo, extras.fullkey];
|
||||
NSString* pname = [NSString stringWithFormat:@"HW Render %x.%x.%llx.%llx", vssel_mtl.key, pssel.key_hi, pssel.key_lo, extras.fullkey];
|
||||
auto pipeline = MakePipeline(pdesc, vs, ps, pname);
|
||||
|
||||
[m_current_render.encoder setRenderPipelineState:pipeline];
|
||||
@@ -2518,7 +2494,7 @@ void GSDeviceMTL::SendHWDraw(GSHWDrawConfig& config, id<MTLRenderCommandEncoder>
|
||||
|
||||
for (u32 n = 0, p = 0; n < draw_list_size; n++)
|
||||
{
|
||||
const size_t count = (*config.drawlist)[n] * indices_per_prim;
|
||||
const size_t count = config.drawlist->at(n) * indices_per_prim;
|
||||
textureBarrier(enc);
|
||||
EncodeDraw(enc, topology, count, buffer, off, p);
|
||||
p += count;
|
||||
|
||||
@@ -155,6 +155,8 @@ enum GSMTLAttributes
|
||||
|
||||
enum GSMTLFnConstants
|
||||
{
|
||||
GSMTLConstantIndex_BILN,
|
||||
GSMTLConstantIndex_DEPTH_OUT,
|
||||
GSMTLConstantIndex_CAS_SHARPEN_ONLY,
|
||||
GSMTLConstantIndex_FRAMEBUFFER_FETCH,
|
||||
GSMTLConstantIndex_DEPTH_FEEDBACK,
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
|
||||
using namespace metal;
|
||||
|
||||
constant bool BILN [[function_constant(GSMTLConstantIndex_BILN)]];
|
||||
constant bool DEPTH_OUT [[function_constant(GSMTLConstantIndex_DEPTH_OUT)]];
|
||||
constant bool COLOR_OUT = !DEPTH_OUT;
|
||||
|
||||
struct ConvertVSIn
|
||||
{
|
||||
vector_float2 position [[attribute(0)]];
|
||||
@@ -65,7 +69,7 @@ fragment float4 ps_copy(ConvertShaderData data [[stage_in]], ConvertPSRes res)
|
||||
return res.sample(data.t);
|
||||
}
|
||||
|
||||
fragment ushort ps_convert_rgba8_16bits(ConvertShaderData data [[stage_in]], ConvertPSRes res)
|
||||
fragment ushort ps_convert_rgb5a1_16bits(ConvertShaderData data [[stage_in]], ConvertPSRes res)
|
||||
{
|
||||
float4 c = res.sample(data.t);
|
||||
uint4 cu = uint4(c * 255.f + 0.5f);
|
||||
@@ -156,17 +160,17 @@ fragment float4 ps_filter_transparency(ConvertShaderData data [[stage_in]], Conv
|
||||
return float4(c.rgb, 1.0);
|
||||
}
|
||||
|
||||
fragment uint ps_convert_float32_32bits(ConvertShaderData data [[stage_in]], ConvertPSDepthRes res)
|
||||
fragment uint ps_convert_depth32_32bits(ConvertShaderData data [[stage_in]], ConvertPSDepthRes res)
|
||||
{
|
||||
return uint(0x1p32 * res.sample(data.t));
|
||||
}
|
||||
|
||||
fragment float4 ps_convert_float32_rgba8(ConvertShaderData data [[stage_in]], ConvertPSDepthRes res)
|
||||
fragment float4 ps_convert_depth32_rgba8(ConvertShaderData data [[stage_in]], ConvertPSDepthRes res)
|
||||
{
|
||||
return convert_depth32_rgba8(res.sample(data.t)) / 255.f;
|
||||
}
|
||||
|
||||
fragment float4 ps_convert_float16_rgb5a1(ConvertShaderData data [[stage_in]], ConvertPSDepthRes res)
|
||||
fragment float4 ps_convert_depth16_rgb5a1(ConvertShaderData data [[stage_in]], ConvertPSDepthRes res)
|
||||
{
|
||||
return convert_depth16_rgba8(res.sample(data.t)) / 255.f;
|
||||
}
|
||||
@@ -176,17 +180,6 @@ fragment float ps_convert_float32_depth_to_color(ConvertShaderData data [[stage_
|
||||
return res.sample(data.t);
|
||||
}
|
||||
|
||||
struct DepthOut
|
||||
{
|
||||
float depth [[depth(any)]];
|
||||
DepthOut(float depth): depth(depth) {}
|
||||
};
|
||||
|
||||
fragment DepthOut ps_depth_copy(ConvertShaderData data [[stage_in]], ConvertPSDepthRes res)
|
||||
{
|
||||
return res.sample(data.t);
|
||||
}
|
||||
|
||||
fragment float4 ps_downsample_copy(ConvertShaderData data [[stage_in]],
|
||||
texture2d<float> texture [[texture(GSMTLTextureIndexNonHW)]],
|
||||
constant GSMTLDownsamplePSUniform& uniform [[buffer(GSMTLBufferIndexUniforms)]])
|
||||
@@ -225,6 +218,23 @@ static float rgb5a1_to_depth16(half4 unorm)
|
||||
return float(out) * 0x1p-32f;
|
||||
}
|
||||
|
||||
struct DepthOrColorOut
|
||||
{
|
||||
float color [[color(0), function_constant(COLOR_OUT)]];
|
||||
float depth [[depth(any), function_constant(DEPTH_OUT)]];
|
||||
DepthOrColorOut(float value): color(value), depth(value) {}
|
||||
};
|
||||
|
||||
struct ConvertPSDepthOrColorRes
|
||||
{
|
||||
texture2d<float> texture [[texture(GSMTLTextureIndexNonHW)]];
|
||||
sampler s [[sampler(0)]];
|
||||
float sample(float2 coord)
|
||||
{
|
||||
return texture.sample(s, coord).x;
|
||||
}
|
||||
};
|
||||
|
||||
struct ConvertToDepthRes
|
||||
{
|
||||
texture2d<half> texture [[texture(GSMTLTextureIndexNonHW)]];
|
||||
@@ -252,59 +262,51 @@ struct ConvertToDepthRes
|
||||
float depthBR = convert(texture.read(coords.zw));
|
||||
return mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y);
|
||||
}
|
||||
|
||||
template <float (&convert)(half4)>
|
||||
float sample_maybe_biln(float2 coord)
|
||||
{
|
||||
if (BILN)
|
||||
return sample_biln<convert>(coord);
|
||||
else
|
||||
return convert(sample(coord));
|
||||
}
|
||||
};
|
||||
|
||||
fragment DepthOut ps_convert_float32_float24(ConvertShaderData data [[stage_in]], ConvertPSDepthRes res)
|
||||
fragment DepthOrColorOut ps_depth_copy(ConvertShaderData data [[stage_in]], ConvertPSDepthOrColorRes res)
|
||||
{
|
||||
return res.sample(data.t);
|
||||
}
|
||||
|
||||
static float depth32_to_depth24(float d)
|
||||
{
|
||||
return float(uint(d * exp2(32.0f)) & 0xffffff) * exp2(-32.0f);
|
||||
}
|
||||
|
||||
fragment DepthOrColorOut ps_convert_depth32_depth24(ConvertShaderData data [[stage_in]], ConvertPSDepthOrColorRes res)
|
||||
{
|
||||
// Truncates depth value to 24bits
|
||||
uint val = uint(res.sample(data.t) * 0x1p32) & 0xFFFFFF;
|
||||
return float(val) * 0x1p-32f;
|
||||
return depth32_to_depth24(res.sample(data.t));
|
||||
}
|
||||
|
||||
fragment DepthOut ps_convert_float32_color_to_depth(ConvertShaderData data [[stage_in]], ConvertPSRes res)
|
||||
fragment DepthOrColorOut ps_convert_rgba8_depth32(ConvertShaderData data [[stage_in]], ConvertToDepthRes res)
|
||||
{
|
||||
return res.sample(data.t).x;
|
||||
return res.sample_maybe_biln<rgba8_to_depth32>(data.t);
|
||||
}
|
||||
|
||||
|
||||
fragment DepthOut ps_convert_rgba8_float32(ConvertShaderData data [[stage_in]], ConvertToDepthRes res)
|
||||
fragment DepthOrColorOut ps_convert_rgba8_depth24(ConvertShaderData data [[stage_in]], ConvertToDepthRes res)
|
||||
{
|
||||
return rgba8_to_depth32(res.sample(data.t));
|
||||
return res.sample_maybe_biln<rgba8_to_depth24>(data.t);
|
||||
}
|
||||
|
||||
fragment DepthOut ps_convert_rgba8_float24(ConvertShaderData data [[stage_in]], ConvertToDepthRes res)
|
||||
fragment DepthOrColorOut ps_convert_rgba8_depth16(ConvertShaderData data [[stage_in]], ConvertToDepthRes res)
|
||||
{
|
||||
return rgba8_to_depth24(res.sample(data.t));
|
||||
return res.sample_maybe_biln<rgba8_to_depth16>(data.t);
|
||||
}
|
||||
|
||||
fragment DepthOut ps_convert_rgba8_float16(ConvertShaderData data [[stage_in]], ConvertToDepthRes res)
|
||||
fragment DepthOrColorOut ps_convert_rgb5a1_depth16(ConvertShaderData data [[stage_in]], ConvertToDepthRes res)
|
||||
{
|
||||
return rgba8_to_depth16(res.sample(data.t));
|
||||
}
|
||||
|
||||
fragment DepthOut ps_convert_rgb5a1_float16(ConvertShaderData data [[stage_in]], ConvertToDepthRes res)
|
||||
{
|
||||
return rgb5a1_to_depth16(res.sample(data.t));
|
||||
}
|
||||
|
||||
fragment DepthOut ps_convert_rgba8_float32_biln(ConvertShaderData data [[stage_in]], ConvertToDepthRes res)
|
||||
{
|
||||
return res.sample_biln<rgba8_to_depth32>(data.t);
|
||||
}
|
||||
|
||||
fragment DepthOut ps_convert_rgba8_float24_biln(ConvertShaderData data [[stage_in]], ConvertToDepthRes res)
|
||||
{
|
||||
return res.sample_biln<rgba8_to_depth24>(data.t);
|
||||
}
|
||||
|
||||
fragment DepthOut ps_convert_rgba8_float16_biln(ConvertShaderData data [[stage_in]], ConvertToDepthRes res)
|
||||
{
|
||||
return res.sample_biln<rgba8_to_depth16>(data.t);
|
||||
}
|
||||
|
||||
fragment DepthOut ps_convert_rgb5a1_float16_biln(ConvertShaderData data [[stage_in]], ConvertToDepthRes res)
|
||||
{
|
||||
return res.sample_biln<rgb5a1_to_depth16>(data.t);
|
||||
return res.sample_maybe_biln<rgb5a1_to_depth16>(data.t);
|
||||
}
|
||||
|
||||
fragment float4 ps_convert_rgb5a1_8i(ConvertShaderData data [[stage_in]], DirectReadTextureIn<float> res,
|
||||
|
||||
@@ -45,7 +45,6 @@ namespace GLState
|
||||
u32 draw_buffers;
|
||||
|
||||
GLuint tex_unit[8];
|
||||
GLuint64 tex_handle[8];
|
||||
|
||||
u32 UpdateDrawBuffers()
|
||||
{
|
||||
@@ -90,6 +89,5 @@ namespace GLState
|
||||
draw_buffers = 0;
|
||||
|
||||
std::fill(std::begin(tex_unit), std::end(tex_unit), 0);
|
||||
std::fill(std::begin(tex_handle), std::end(tex_handle), 0);
|
||||
}
|
||||
} // namespace GLState
|
||||
|
||||
@@ -49,7 +49,6 @@ namespace GLState
|
||||
extern bool ds_written; // Depth Stencil written
|
||||
|
||||
extern GLuint tex_unit[8]; // shader input texture
|
||||
extern GLuint64 tex_handle[8]; // shader input texture
|
||||
|
||||
extern u32 UpdateDrawBuffers();
|
||||
extern void Clear();
|
||||
|
||||
@@ -87,6 +87,12 @@ namespace Emulate_DSA
|
||||
glTexSubImage2D(GL_TEXTURE_2D, level, xoffset, yoffset, width, height, format, type, pixels);
|
||||
}
|
||||
|
||||
static void GLAPIENTRY CopyTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
|
||||
{
|
||||
BindTextureUnit(7, texture);
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, level, xoffset, yoffset, x, y, width, height);
|
||||
}
|
||||
|
||||
static void GLAPIENTRY CompressedTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset,
|
||||
GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data)
|
||||
{
|
||||
@@ -126,6 +132,7 @@ namespace Emulate_DSA
|
||||
glCreateTextures = CreateTexture;
|
||||
glTextureStorage2D = TextureStorage;
|
||||
glTextureSubImage2D = TextureSubImage;
|
||||
glCopyTextureSubImage2D = CopyTextureSubImage;
|
||||
glCompressedTextureSubImage2D = CompressedTextureSubImage;
|
||||
glGetTextureImage = GetTexureImage;
|
||||
glTextureParameteri = TextureParameteri;
|
||||
@@ -414,40 +421,56 @@ bool GSDeviceOGL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
{
|
||||
GL_PUSH("GSDeviceOGL::Convert");
|
||||
|
||||
|
||||
|
||||
m_convert.vs = GetShaderSource("vs_main", GL_VERTEX_SHADER, *convert_glsl);
|
||||
|
||||
for (size_t i = 0; i < std::size(m_convert.ps); i++)
|
||||
m_convert.ps.resize(ShaderConvertSelector::NUM_TOTAL_SHADERS);
|
||||
for (u32 i = 0; i < ShaderConvertSelector::NUM_TOTAL_SHADERS; i++)
|
||||
{
|
||||
const char* name = shaderName(static_cast<ShaderConvert>(i));
|
||||
const std::string ps(GetShaderSource(name, GL_FRAGMENT_SHADER, *convert_glsl));
|
||||
if (!m_shader_cache.GetProgram(&m_convert.ps[i], m_convert.vs, ps))
|
||||
return false;
|
||||
m_convert.ps[i].SetFormattedName("Convert pipe %s", name);
|
||||
const ShaderConvertSelector shader = ShaderConvertSelector::Get(i);
|
||||
|
||||
if (static_cast<ShaderConvert>(i) == ShaderConvert::RGBA_TO_8I || static_cast<ShaderConvert>(i) == ShaderConvert::RGB5A1_TO_8I)
|
||||
const char* name = shader.EntryPoint();
|
||||
|
||||
std::string macro;
|
||||
macro += fmt::format("#define HAS_BILN {}\n", static_cast<int>(shader.Biln()));
|
||||
macro += fmt::format("#define HAS_STENCIL_OUTPUT {}\n", static_cast<int>(shader.StencilOutput()));
|
||||
macro += fmt::format("#define HAS_INTEGER_OUTPUT {}\n", static_cast<int>(shader.IntegerOutputBpp() != 0));
|
||||
macro += fmt::format("#define HAS_DEPTH_OUTPUT {}\n", static_cast<int>(shader.DepthOutput()));
|
||||
macro += fmt::format("#define HAS_FLOAT32_INPUT {}\n", static_cast<int>(shader.Float32Input()));
|
||||
macro += fmt::format("#define HAS_FLOAT32_OUTPUT {}\n", static_cast<int>(shader.Float32Output()));
|
||||
|
||||
const std::string ps(GetShaderSource(name, GL_FRAGMENT_SHADER, *convert_glsl, macro));
|
||||
|
||||
GLProgram& prog = m_convert.ps[i];
|
||||
|
||||
if (!m_shader_cache.GetProgram(&prog, m_convert.vs, ps))
|
||||
return false;
|
||||
|
||||
prog.SetFormattedName("Convert pipeline (%s, mask=%x, depth=%d, biln=%d)",
|
||||
shader.Name(), shader.Mask(), static_cast<int>(shader.DepthOutput()),
|
||||
static_cast<int>(shader.Biln()));
|
||||
|
||||
if (shader.Shader() == ShaderConvert::RGBA_TO_8I || shader.Shader() == ShaderConvert::RGB5A1_TO_8I)
|
||||
{
|
||||
m_convert.ps[i].RegisterUniform("SBW");
|
||||
m_convert.ps[i].RegisterUniform("DBW");
|
||||
m_convert.ps[i].RegisterUniform("PSM");
|
||||
m_convert.ps[i].RegisterUniform("ScaleFactor");
|
||||
prog.RegisterUniform("SBW");
|
||||
prog.RegisterUniform("DBW");
|
||||
prog.RegisterUniform("PSM");
|
||||
prog.RegisterUniform("ScaleFactor");
|
||||
}
|
||||
else if (static_cast<ShaderConvert>(i) == ShaderConvert::YUV)
|
||||
else if (shader.Shader() == ShaderConvert::YUV)
|
||||
{
|
||||
m_convert.ps[i].RegisterUniform("EMOD");
|
||||
prog.RegisterUniform("EMOD");
|
||||
}
|
||||
else if (static_cast<ShaderConvert>(i) == ShaderConvert::CLUT_4 || static_cast<ShaderConvert>(i) == ShaderConvert::CLUT_8)
|
||||
else if (shader.Shader() == ShaderConvert::CLUT_4 || shader.Shader() == ShaderConvert::CLUT_8)
|
||||
{
|
||||
m_convert.ps[i].RegisterUniform("offset");
|
||||
m_convert.ps[i].RegisterUniform("scale");
|
||||
prog.RegisterUniform("offset");
|
||||
prog.RegisterUniform("scale");
|
||||
}
|
||||
else if (static_cast<ShaderConvert>(i) == ShaderConvert::DOWNSAMPLE_COPY)
|
||||
else if (shader.Shader() == ShaderConvert::DOWNSAMPLE_COPY)
|
||||
{
|
||||
m_convert.ps[i].RegisterUniform("ClampMin");
|
||||
m_convert.ps[i].RegisterUniform("DownsampleFactor");
|
||||
m_convert.ps[i].RegisterUniform("Weight");
|
||||
m_convert.ps[i].RegisterUniform("StepMultiplier");
|
||||
prog.RegisterUniform("ClampMin");
|
||||
prog.RegisterUniform("DownsampleFactor");
|
||||
prog.RegisterUniform("Weight");
|
||||
prog.RegisterUniform("StepMultiplier");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,7 +505,7 @@ bool GSDeviceOGL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
|
||||
for (size_t i = 0; i < std::size(m_present); i++)
|
||||
{
|
||||
const char* name = shaderName(static_cast<PresentShader>(i));
|
||||
const char* name = ShaderEntryPoint(static_cast<PresentShader>(i));
|
||||
const std::string ps(GetShaderSource(name, GL_FRAGMENT_SHADER, *shader));
|
||||
if (!m_shader_cache.GetProgram(&m_present[i], present_vs, ps))
|
||||
return false;
|
||||
@@ -586,7 +609,7 @@ bool GSDeviceOGL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
for (size_t i = 0; i < std::size(m_date.primid_ps); i++)
|
||||
{
|
||||
const std::string ps(GetShaderSource(
|
||||
fmt::format("ps_stencil_image_init_{}", i),
|
||||
fmt::format("ps_primid_image_init_{}", i),
|
||||
GL_FRAGMENT_SHADER, *convert_glsl));
|
||||
m_shader_cache.GetProgram(&m_date.primid_ps[i], m_convert.vs, ps);
|
||||
m_date.primid_ps[i].SetFormattedName("PrimID Destination Alpha Init %d", i);
|
||||
@@ -603,7 +626,8 @@ bool GSDeviceOGL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
// This extension allow FS depth to range from -1 to 1. So
|
||||
// gl_position.z could range from [0, 1]
|
||||
// Change depth convention
|
||||
glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
|
||||
if (GLAD_GL_ARB_clip_control)
|
||||
glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
|
||||
|
||||
// ****************************************************************
|
||||
// HW renderer shader
|
||||
@@ -634,7 +658,7 @@ bool GSDeviceOGL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
|
||||
// Basic to ensure structures are correctly packed
|
||||
static_assert(sizeof(VSSelector) == 1, "Wrong VSSelector size");
|
||||
static_assert(sizeof(PSSelector) == 12, "Wrong PSSelector size");
|
||||
static_assert(sizeof(PSSelector) == 16, "Wrong PSSelector size");
|
||||
static_assert(sizeof(PSSamplerSelector) == 1, "Wrong PSSamplerSelector size");
|
||||
static_assert(sizeof(OMDepthStencilSelector) == 1, "Wrong OMDepthStencilSelector size");
|
||||
static_assert(sizeof(OMColorMaskSelector) == 1, "Wrong OMColorMaskSelector size");
|
||||
@@ -753,17 +777,16 @@ bool GSDeviceOGL::CheckFeatures()
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GLAD_GL_VERSION_4_3 && !GLAD_GL_ARB_copy_image && !GLAD_GL_EXT_copy_image)
|
||||
if (!GLAD_GL_VERSION_4_3 && !GLAD_GL_ARB_copy_image && !GLAD_GL_EXT_copy_image && !GLAD_GL_NV_copy_image)
|
||||
{
|
||||
Host::ReportFormattedErrorAsync(
|
||||
"GS", "GL_ARB_copy_image is not supported, this is required for the OpenGL renderer.");
|
||||
return false;
|
||||
Host::AddOSDMessage(
|
||||
"GL_ARB_copy_image is not supported, copies will be slower.", Host::OSD_ERROR_DURATION);
|
||||
}
|
||||
|
||||
if (!GLAD_GL_VERSION_4_5 && !GLAD_GL_ARB_clip_control)
|
||||
{
|
||||
Host::ReportFormattedErrorAsync(
|
||||
"GS", "GL_ARB_clip_control is not supported, this is required for the OpenGL renderer.");
|
||||
return false;
|
||||
Host::AddOSDMessage(
|
||||
"GL_ARB_clip_control is not supported, depth will be less accurate.", Host::OSD_ERROR_DURATION);
|
||||
}
|
||||
|
||||
if (!GLAD_GL_ARB_viewport_array)
|
||||
@@ -885,6 +908,11 @@ bool GSDeviceOGL::CheckFeatures()
|
||||
|
||||
m_features.aa1 = GSConfig.HWAA1 && m_features.vs_expand && m_features.feedback_loops();
|
||||
|
||||
if (GSConfig.HWROV)
|
||||
{
|
||||
Console.Warning("GL: ROV is not implemented for GL and will be disabled.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -942,8 +970,9 @@ void GSDeviceOGL::DestroyResources()
|
||||
for (GLProgram& prog : m_present)
|
||||
prog.Destroy();
|
||||
|
||||
for (GLProgram& prog : m_convert.ps)
|
||||
for (auto& prog : m_convert.ps)
|
||||
prog.Destroy();
|
||||
|
||||
delete m_convert.dss;
|
||||
delete m_convert.dss_write;
|
||||
|
||||
@@ -1271,7 +1300,7 @@ void GSDeviceOGL::CommitClear(GSTexture* t, bool use_write_fbo)
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
if (T->GetType() == GSTexture::Type::DepthStencil)
|
||||
if (T->IsDepthStencil())
|
||||
{
|
||||
const float d = T->GetClearDepth();
|
||||
if (GLState::depth_mask)
|
||||
@@ -1290,7 +1319,7 @@ void GSDeviceOGL::CommitClear(GSTexture* t, bool use_write_fbo)
|
||||
const u32 old_color_mask = GLState::wrgba;
|
||||
OMSetColorMaskState();
|
||||
|
||||
const GSVector4 c_unorm = T->GetUNormClearColor();
|
||||
const GSVector4 c_unorm = T->GetClearForFormat();
|
||||
|
||||
if (T->IsIntegerFormat())
|
||||
{
|
||||
@@ -1315,8 +1344,9 @@ void GSDeviceOGL::CommitClear(GSTexture* t, bool use_write_fbo)
|
||||
if (use_write_fbo)
|
||||
{
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
|
||||
(t->GetType() == GSTexture::Type::RenderTarget) ? GL_COLOR_ATTACHMENT0 :
|
||||
(m_features.framebuffer_fetch ? GL_DEPTH_ATTACHMENT : GL_DEPTH_STENCIL_ATTACHMENT),
|
||||
(t->GetType() == GSTexture::Type::RenderTarget) ?
|
||||
GL_COLOR_ATTACHMENT0 :
|
||||
(m_features.framebuffer_fetch ? GL_DEPTH_ATTACHMENT : GL_DEPTH_STENCIL_ATTACHMENT),
|
||||
GL_TEXTURE_2D, 0, 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLState::fbo);
|
||||
}
|
||||
@@ -1407,7 +1437,7 @@ GSTexture* GSDeviceOGL::InitPrimDateTexture(GSTexture* rt, const GSVector4i& are
|
||||
return nullptr;
|
||||
|
||||
GL_PUSH("PrimID Destination Alpha Clear");
|
||||
DoStretchRect(rt, GSVector4(area) / GSVector4(rtsize).xyxy(), tex, GSVector4(area), m_date.primid_ps[static_cast<u8>(datm)], false);
|
||||
DoStretchRect(rt, GSVector4(area) / GSVector4(rtsize).xyxy(), tex, GSVector4(area), m_date.primid_ps[static_cast<u8>(datm)], Nearest);
|
||||
return tex;
|
||||
}
|
||||
|
||||
@@ -1422,9 +1452,9 @@ std::string GSDeviceOGL::GenGlslHeader(const std::string_view entry, GLenum type
|
||||
{
|
||||
std::string header;
|
||||
|
||||
// Intel's GL driver doesn't like the readonly qualifier with 3.3 GLSL.
|
||||
if (m_features.vs_expand && GLAD_GL_VERSION_4_3)
|
||||
{
|
||||
// Intel's GL driver doesn't like the readonly qualifier with 3.3 GLSL.
|
||||
header = "#version 430 core\n";
|
||||
}
|
||||
else
|
||||
@@ -1468,6 +1498,11 @@ std::string GSDeviceOGL::GenGlslHeader(const std::string_view entry, GLenum type
|
||||
header += "#define DEPTH_FEEDBACK_SUPPORT 2\n"; // Depth as RT
|
||||
}
|
||||
|
||||
if (GLAD_GL_ARB_clip_control)
|
||||
header += "#define HAS_CLIP_CONTROL 1\n";
|
||||
else
|
||||
header += "#define HAS_CLIP_CONTROL 0\n";
|
||||
|
||||
// Allow to puts several shader in 1 files
|
||||
switch (type)
|
||||
{
|
||||
@@ -1505,7 +1540,7 @@ std::string GSDeviceOGL::GetVSSource(VSSelector sel)
|
||||
std::string macro = fmt::format("#define VS_FST {}\n", static_cast<u32>(sel.fst))
|
||||
+ fmt::format("#define VS_IIP {}\n", static_cast<u32>(sel.iip))
|
||||
+ fmt::format("#define VS_POINT_SIZE {}\n", static_cast<u32>(sel.point_size))
|
||||
+ fmt::format("#define VS_EXPAND {}\n", static_cast<int>(sel.expand));
|
||||
+ fmt::format("#define VS_EXPAND {}\n", static_cast<int>(sel.expand));
|
||||
|
||||
std::string src = GenGlslHeader("vs_main", GL_VERTEX_SHADER, macro);
|
||||
src += m_shader_tfx_vgs;
|
||||
@@ -1514,7 +1549,7 @@ std::string GSDeviceOGL::GetVSSource(VSSelector sel)
|
||||
|
||||
std::string GSDeviceOGL::GetPSSource(const PSSelector& sel)
|
||||
{
|
||||
DevCon.WriteLn("GL: Compiling new pixel shader with selector 0x%" PRIX64 "%08X", sel.key_hi, sel.key_lo);
|
||||
DevCon.WriteLn("GL: Compiling new pixel shader with selector 0x%016" PRIX64 "_%016" PRIX64, sel.key_hi, sel.key_lo);
|
||||
|
||||
std::string macro = fmt::format("#define PS_FST {}\n", sel.fst)
|
||||
+ fmt::format("#define PS_WMS {}\n", sel.wms)
|
||||
@@ -1575,7 +1610,9 @@ std::string GSDeviceOGL::GetPSSource(const PSSelector& sel)
|
||||
+ fmt::format("#define PS_ZTST {}\n", sel.ztst)
|
||||
+ fmt::format("#define PS_AA1 {}\n", static_cast<u32>(sel.aa1))
|
||||
+ fmt::format("#define PS_ABE {}\n", sel.abe)
|
||||
+ fmt::format("#define PS_ANISOTROPIC_FILTERING {}", sel.sw_aniso)
|
||||
+ fmt::format("#define PS_ANISOTROPIC_FILTERING {}\n", sel.sw_aniso)
|
||||
+ fmt::format("#define PS_ROV_COLOR {}\n", 0)
|
||||
+ fmt::format("#define PS_ROV_DEPTH {}\n", 0)
|
||||
;
|
||||
|
||||
std::string src = GenGlslHeader("ps_main", GL_FRAGMENT_SHADER, macro);
|
||||
@@ -1584,7 +1621,7 @@ std::string GSDeviceOGL::GetPSSource(const PSSelector& sel)
|
||||
}
|
||||
|
||||
// Copy a sub part of texture (same as below but force a conversion)
|
||||
void GSDeviceOGL::BlitRect(GSTexture* sTex, const GSVector4i& r, const GSVector2i& dsize, bool at_origin, bool linear)
|
||||
void GSDeviceOGL::BlitRect(GSTexture* sTex, const GSVector4i& r, const GSVector2i& dsize, bool at_origin, Filter filter)
|
||||
{
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
|
||||
@@ -1598,12 +1635,12 @@ void GSDeviceOGL::BlitRect(GSTexture* sTex, const GSVector4i& r, const GSVector2
|
||||
|
||||
const GSVector4 float_r(r);
|
||||
|
||||
m_convert.ps[static_cast<int>(ShaderConvert::COPY)].Bind();
|
||||
GetConvertProgram(ShaderConvert::COPY).Bind();
|
||||
OMSetDepthStencilState(m_convert.dss);
|
||||
OMSetBlendState();
|
||||
OMSetColorMaskState();
|
||||
PSSetShaderResource(0, sTex);
|
||||
PSSetSamplerState(linear ? m_convert.ln : m_convert.pt);
|
||||
PSSetShaderResource(TEXTURE_TEXTURE, sTex);
|
||||
PSSetSamplerState(filter == Biln ? m_convert.ln : m_convert.pt);
|
||||
DrawStretchRect(float_r / (GSVector4(sTex->GetSize()).xyxy()), float_r, dsize);
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
@@ -1651,24 +1688,51 @@ void GSDeviceOGL::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r
|
||||
glCopyImageSubDataEXT(sid, GL_TEXTURE_2D, 0, r.x, r.y, 0, did, GL_TEXTURE_2D,
|
||||
0, destX, destY, 0, r.width(), r.height(), 1);
|
||||
}
|
||||
else if (GLAD_GL_NV_copy_image)
|
||||
{
|
||||
glCopyImageSubDataNV(sid, GL_TEXTURE_2D, 0, r.x, r.y, 0, did, GL_TEXTURE_2D,
|
||||
0, destX, destY, 0, r.width(), r.height(), 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool draw_in_depth = sTex->IsDepthStencil();
|
||||
const GLenum attachment = draw_in_depth ? GL_DEPTH_STENCIL_ATTACHMENT : GL_COLOR_ATTACHMENT0;
|
||||
|
||||
// Bind attachments.
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, attachment, GL_TEXTURE_2D, sid, 0);
|
||||
glReadBuffer(draw_in_depth ? GL_NONE : GL_COLOR_ATTACHMENT0);
|
||||
|
||||
// Do copy.
|
||||
glCopyTextureSubImage2D(did, 0, destX, destY, r.x, r.y, r.width(), r.height());
|
||||
|
||||
// Unbind attachments.
|
||||
if (draw_in_depth)
|
||||
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, attachment, GL_TEXTURE_2D, 0, 0);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
dTex->SetState(GSTexture::State::Dirty);
|
||||
}
|
||||
|
||||
void GSDeviceOGL::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
OMColorMaskSelector cms, ShaderConvert shader, bool linear)
|
||||
ShaderConvertSelector shader, Filter filter)
|
||||
{
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_convert.ps[static_cast<int>(shader)], false, cms, linear);
|
||||
const u8 mask = shader.Mask();
|
||||
shader = shader.SetMask(); // Mask is handled separately from program.
|
||||
filter = shader.SupportsBilinear() ? Nearest : filter; // Don't allow HW bilinear if SW bilinear is needed.
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, GetConvertProgram(shader), false, OMColorMaskSelector(mask), filter);
|
||||
}
|
||||
|
||||
void GSDeviceOGL::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
const GLProgram& ps, bool linear)
|
||||
const GLProgram& ps, Filter filter)
|
||||
{
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, ps, false, OMColorMaskSelector(), linear);
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, ps, false, OMColorMaskSelector(), filter);
|
||||
}
|
||||
|
||||
void GSDeviceOGL::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
const GLProgram& ps, bool alpha_blend, OMColorMaskSelector cms, bool linear)
|
||||
const GLProgram& ps, bool alpha_blend, OMColorMaskSelector cms, Filter filter)
|
||||
{
|
||||
CommitClear(sTex, true);
|
||||
|
||||
@@ -1702,8 +1766,8 @@ void GSDeviceOGL::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTextu
|
||||
// Texture
|
||||
// ************************************
|
||||
|
||||
PSSetShaderResource(0, sTex);
|
||||
PSSetSamplerState(linear ? m_convert.ln : m_convert.pt);
|
||||
PSSetShaderResource(TEXTURE_TEXTURE, sTex);
|
||||
PSSetSamplerState(filter == Biln ? m_convert.ln : m_convert.pt);
|
||||
|
||||
// ************************************
|
||||
// Draw
|
||||
@@ -1711,7 +1775,7 @@ void GSDeviceOGL::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTextu
|
||||
DrawStretchRect(sRect, dRect, dTex->GetSize());
|
||||
}
|
||||
|
||||
void GSDeviceOGL::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear)
|
||||
void GSDeviceOGL::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, Filter filter)
|
||||
{
|
||||
CommitClear(sTex, true);
|
||||
|
||||
@@ -1737,8 +1801,8 @@ void GSDeviceOGL::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
|
||||
OMSetBlendState(false);
|
||||
OMSetColorMaskState();
|
||||
|
||||
PSSetShaderResource(0, sTex);
|
||||
PSSetSamplerState(linear ? m_convert.ln : m_convert.pt);
|
||||
PSSetShaderResource(TEXTURE_TEXTURE, sTex);
|
||||
PSSetSamplerState(filter == Biln ? m_convert.ln : m_convert.pt);
|
||||
|
||||
// Flip y axis only when we render in the backbuffer
|
||||
// By default everything is render in the wrong order (ie dx).
|
||||
@@ -1754,7 +1818,7 @@ void GSDeviceOGL::UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX,
|
||||
CommitClear(sTex, false);
|
||||
|
||||
const ShaderConvert shader = (dSize == 16) ? ShaderConvert::CLUT_4 : ShaderConvert::CLUT_8;
|
||||
GLProgram& prog = m_convert.ps[static_cast<int>(shader)];
|
||||
GLProgram& prog = GetConvertProgram(shader);
|
||||
prog.Bind();
|
||||
prog.Uniform3ui(0, offsetX, offsetY, dOffset);
|
||||
prog.Uniform1f(1, sScale);
|
||||
@@ -1764,7 +1828,7 @@ void GSDeviceOGL::UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX,
|
||||
OMSetColorMaskState();
|
||||
OMSetRenderTargets(dTex, nullptr, nullptr);
|
||||
|
||||
PSSetShaderResource(0, sTex);
|
||||
PSSetShaderResource(TEXTURE_TEXTURE, sTex);
|
||||
PSSetSamplerState(m_convert.pt);
|
||||
|
||||
const GSVector4 dRect(0, 0, dSize, 1);
|
||||
@@ -1776,7 +1840,7 @@ void GSDeviceOGL::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 off
|
||||
CommitClear(sTex, false);
|
||||
|
||||
const ShaderConvert shader = ((SPSM & 0xE) == 0) ? ShaderConvert::RGBA_TO_8I : ShaderConvert::RGB5A1_TO_8I;
|
||||
GLProgram& prog = m_convert.ps[static_cast<int>(shader)];
|
||||
GLProgram& prog = GetConvertProgram(shader);
|
||||
prog.Bind();
|
||||
prog.Uniform1ui(0, SBW);
|
||||
prog.Uniform1ui(1, DBW);
|
||||
@@ -1788,7 +1852,7 @@ void GSDeviceOGL::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 off
|
||||
OMSetColorMaskState();
|
||||
OMSetRenderTargets(dTex, nullptr, nullptr);
|
||||
|
||||
PSSetShaderResource(0, sTex);
|
||||
PSSetShaderResource(TEXTURE_TEXTURE, sTex);
|
||||
PSSetSamplerState(m_convert.pt);
|
||||
|
||||
const GSVector4 dRect(0, 0, dTex->GetWidth(), dTex->GetHeight());
|
||||
@@ -1800,7 +1864,7 @@ void GSDeviceOGL::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u3
|
||||
CommitClear(sTex, false);
|
||||
|
||||
constexpr ShaderConvert shader = ShaderConvert::DOWNSAMPLE_COPY;
|
||||
GLProgram& prog = m_convert.ps[static_cast<int>(shader)];
|
||||
GLProgram& prog = GetConvertProgram(shader);
|
||||
prog.Bind();
|
||||
prog.Uniform2iv(0, clamp_min.v);
|
||||
prog.Uniform1i(1, downsample_factor);
|
||||
@@ -1812,7 +1876,7 @@ void GSDeviceOGL::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u3
|
||||
OMSetColorMaskState();
|
||||
OMSetRenderTargets(dTex, nullptr, nullptr);
|
||||
|
||||
PSSetShaderResource(0, sTex);
|
||||
PSSetShaderResource(TEXTURE_TEXTURE, sTex);
|
||||
PSSetSamplerState(m_convert.pt);
|
||||
|
||||
//const GSVector4 dRect = GSVector4(dTex->GetRect());
|
||||
@@ -1846,22 +1910,24 @@ void GSDeviceOGL::DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect
|
||||
}
|
||||
|
||||
void GSDeviceOGL::DrawMultiStretchRects(
|
||||
const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader)
|
||||
const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader)
|
||||
{
|
||||
shader = shader.SetMask(); // Mask is handled separately from program.
|
||||
|
||||
IASetVAO(m_vao);
|
||||
IASetPrimitiveTopology(GL_TRIANGLE_STRIP);
|
||||
OMSetDepthStencilState(HasDepthOutput(shader) ? m_convert.dss_write : m_convert.dss);
|
||||
OMSetDepthStencilState(shader.DepthOutput() ? m_convert.dss_write : m_convert.dss);
|
||||
OMSetBlendState(false);
|
||||
OMSetColorMaskState();
|
||||
if (!dTex->IsDepthStencil())
|
||||
OMSetRenderTargets(dTex, nullptr, nullptr);
|
||||
else
|
||||
OMSetRenderTargets(nullptr, nullptr, dTex);
|
||||
m_convert.ps[static_cast<int>(shader)].Bind();
|
||||
GetConvertProgram(shader).Bind();
|
||||
|
||||
const GSVector2 ds(static_cast<float>(dTex->GetWidth()), static_cast<float>(dTex->GetHeight()));
|
||||
GSTexture* last_tex = rects[0].src;
|
||||
bool last_linear = rects[0].linear;
|
||||
Filter last_filter = rects[0].filter;
|
||||
u8 last_wmask = rects[0].wmask.wrgba;
|
||||
|
||||
u32 first = 0;
|
||||
@@ -1869,7 +1935,7 @@ void GSDeviceOGL::DrawMultiStretchRects(
|
||||
|
||||
for (u32 i = 1; i < num_rects; i++)
|
||||
{
|
||||
if (rects[i].src == last_tex && rects[i].linear == last_linear && rects[i].wmask.wrgba == last_wmask)
|
||||
if (rects[i].src == last_tex && rects[i].filter == last_filter && rects[i].wmask.wrgba == last_wmask)
|
||||
{
|
||||
count++;
|
||||
continue;
|
||||
@@ -1877,7 +1943,7 @@ void GSDeviceOGL::DrawMultiStretchRects(
|
||||
|
||||
DoMultiStretchRects(rects + first, count, ds);
|
||||
last_tex = rects[i].src;
|
||||
last_linear = rects[i].linear;
|
||||
last_filter = rects[i].filter;
|
||||
last_wmask = rects[i].wmask.wrgba;
|
||||
first += count;
|
||||
count = 1;
|
||||
@@ -1936,13 +2002,13 @@ void GSDeviceOGL::DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rec
|
||||
m_vertex_stream_buffer->Unmap(vcount * sizeof(GSVertexPT1));
|
||||
m_index_stream_buffer->Unmap(icount * sizeof(u16));
|
||||
|
||||
PSSetShaderResource(0, rects[0].src);
|
||||
PSSetSamplerState(rects[0].linear ? m_convert.ln : m_convert.pt);
|
||||
PSSetShaderResource(TEXTURE_TEXTURE, rects[0].src);
|
||||
PSSetSamplerState(rects[0].filter == Biln ? m_convert.ln : m_convert.pt);
|
||||
OMSetColorMaskState(rects[0].wmask);
|
||||
DrawIndexedPrimitive();
|
||||
}
|
||||
|
||||
void GSDeviceOGL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear)
|
||||
void GSDeviceOGL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const Filter filter)
|
||||
{
|
||||
GL_PUSH("DoMerge");
|
||||
|
||||
@@ -1961,20 +2027,20 @@ void GSDeviceOGL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||
{
|
||||
// 2nd output is enabled and selected. Copy it to destination so we can blend it with 1st output
|
||||
// Note: value outside of dRect must contains the background color (c)
|
||||
StretchRect(sTex[1], sRect[1], dTex, PMODE.SLBG ? dRect[2] : dRect[1], ShaderConvert::COPY, linear);
|
||||
StretchRect(sTex[1], sRect[1], dTex, PMODE.SLBG ? dRect[2] : dRect[1], ShaderConvert::COPY, filter);
|
||||
}
|
||||
|
||||
// Upload constant to select YUV algo
|
||||
if (feedback_write_2 || feedback_write_1)
|
||||
{
|
||||
// Write result to feedback loop
|
||||
m_convert.ps[static_cast<int>(ShaderConvert::YUV)].Bind();
|
||||
m_convert.ps[static_cast<int>(ShaderConvert::YUV)].Uniform2i(0, EXTBUF.EMODA, EXTBUF.EMODC);
|
||||
GetConvertProgram(ShaderConvert::YUV).Bind();
|
||||
GetConvertProgram(ShaderConvert::YUV).Uniform2i(0, EXTBUF.EMODA, EXTBUF.EMODC);
|
||||
}
|
||||
|
||||
// Save 2nd output
|
||||
if (feedback_write_2)
|
||||
StretchRect(dTex, full_r, sTex[2], dRect[2], ShaderConvert::YUV, linear);
|
||||
StretchRect(dTex, full_r, sTex[2], dRect[2], ShaderConvert::YUV, filter);
|
||||
|
||||
// Restore background color to process the normal merge
|
||||
if (feedback_write_2_but_blend_bg)
|
||||
@@ -1991,27 +2057,27 @@ void GSDeviceOGL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||
// Blend with a constant alpha
|
||||
m_merge_obj.ps[1].Bind();
|
||||
m_merge_obj.ps[1].Uniform4fv(0, GSVector4::unorm8(c).v);
|
||||
DoStretchRect(sTex[0], sRect[0], dTex, dRect[0], m_merge_obj.ps[1], true, OMColorMaskSelector(), linear);
|
||||
DoStretchRect(sTex[0], sRect[0], dTex, dRect[0], m_merge_obj.ps[1], true, OMColorMaskSelector(), filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Blend with 2 * input alpha
|
||||
DoStretchRect(sTex[0], sRect[0], dTex, dRect[0], m_merge_obj.ps[0], true, OMColorMaskSelector(), linear);
|
||||
DoStretchRect(sTex[0], sRect[0], dTex, dRect[0], m_merge_obj.ps[0], true, OMColorMaskSelector(), filter);
|
||||
}
|
||||
}
|
||||
|
||||
if (feedback_write_1)
|
||||
StretchRect(dTex, full_r, sTex[2], dRect[2], ShaderConvert::YUV, linear);
|
||||
StretchRect(dTex, full_r, sTex[2], dRect[2], ShaderConvert::YUV, filter);
|
||||
}
|
||||
|
||||
void GSDeviceOGL::DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb)
|
||||
void GSDeviceOGL::DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, Filter filter, const InterlaceConstantBuffer& cb)
|
||||
{
|
||||
OMSetColorMaskState();
|
||||
|
||||
m_interlace.ps[static_cast<int>(shader)].Bind();
|
||||
m_interlace.ps[static_cast<int>(shader)].Uniform4fv(0, cb.ZrH.F32);
|
||||
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_interlace.ps[static_cast<int>(shader)], linear);
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_interlace.ps[static_cast<int>(shader)], filter);
|
||||
}
|
||||
|
||||
bool GSDeviceOGL::CompileFXAAProgram()
|
||||
@@ -2050,7 +2116,7 @@ void GSDeviceOGL::DoFXAA(GSTexture* sTex, GSTexture* dTex)
|
||||
const GSVector4 sRect(0, 0, 1, 1);
|
||||
const GSVector4 dRect(0, 0, s.x, s.y);
|
||||
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_fxaa.ps, true);
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_fxaa.ps, Biln);
|
||||
}
|
||||
|
||||
bool GSDeviceOGL::CompileShadeBoostProgram()
|
||||
@@ -2084,7 +2150,7 @@ void GSDeviceOGL::DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float par
|
||||
const GSVector4 sRect(0, 0, 1, 1);
|
||||
const GSVector4 dRect(0, 0, s.x, s.y);
|
||||
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_shadeboost.ps, false);
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_shadeboost.ps, Nearest);
|
||||
}
|
||||
|
||||
void GSDeviceOGL::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSVector4i& bbox)
|
||||
@@ -2100,7 +2166,7 @@ void GSDeviceOGL::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GS
|
||||
constexpr GLint clear_color = 0;
|
||||
glClearBufferiv(GL_STENCIL, 0, &clear_color);
|
||||
}
|
||||
m_convert.ps[SetDATMShader(datm)].Bind();
|
||||
GetConvertProgram(SetDATMShader(datm)).Bind();
|
||||
|
||||
// om
|
||||
|
||||
@@ -2127,7 +2193,7 @@ void GSDeviceOGL::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GS
|
||||
|
||||
// Texture
|
||||
|
||||
PSSetShaderResource(0, rt);
|
||||
PSSetShaderResource(TEXTURE_TEXTURE, rt);
|
||||
PSSetSamplerState(m_convert.pt);
|
||||
|
||||
DrawPrimitive();
|
||||
@@ -2286,7 +2352,7 @@ bool GSDeviceOGL::DoCAS(GSTexture* sTex, GSTexture* dTex, bool sharpen_only, con
|
||||
prog.Uniform4uiv(1, &constants[4]);
|
||||
prog.Uniform2iv(2, reinterpret_cast<const s32*>(&constants[8]));
|
||||
|
||||
PSSetShaderResource(0, sTex);
|
||||
PSSetShaderResource(TEXTURE_TEXTURE, sTex);
|
||||
glBindImageTexture(0, static_cast<GSTextureOGL*>(dTex)->GetID(), 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
|
||||
|
||||
static const int threadGroupWorkRegionDim = 16;
|
||||
@@ -2684,6 +2750,9 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
|
||||
const GSVector2i rtsize = (config.rt ? config.rt : config.ds)->GetSize();
|
||||
GSTexture* colclip_rt = g_gs_device->GetColorClipTexture();
|
||||
GSTexture* draw_rt = config.rt;
|
||||
GSTexture* draw_ds = config.ds;
|
||||
GSTexture* draw_ds_as_rt = m_ds_as_rt;
|
||||
GSTexture* draw_rt_clone = nullptr;
|
||||
GSTexture* draw_ds_clone = nullptr;
|
||||
GSTexture* primid_texture = nullptr;
|
||||
@@ -2704,7 +2773,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
const GSVector2i size = config.rt->GetSize();
|
||||
const GSVector4 dRect(config.colclip_update_area);
|
||||
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
|
||||
StretchRect(colclip_rt, sRect, config.rt, dRect, ShaderConvert::COLCLIP_RESOLVE, false);
|
||||
StretchRect(colclip_rt, sRect, config.rt, dRect, ShaderConvert::COLCLIP_RESOLVE, Nearest);
|
||||
Recycle(colclip_rt);
|
||||
|
||||
g_gs_device->SetColorClipTexture(nullptr);
|
||||
@@ -2738,8 +2807,10 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
|
||||
const GSVector4 dRect = GSVector4((config.colclip_mode == GSHWDrawConfig::ColClipMode::ConvertOnly) ? GSVector4i::loadh(rtsize) : config.drawarea);
|
||||
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
|
||||
StretchRect(config.rt, sRect, colclip_rt, dRect, ShaderConvert::COLCLIP_INIT, false);
|
||||
StretchRect(config.rt, sRect, colclip_rt, dRect, ShaderConvert::COLCLIP_INIT, Nearest);
|
||||
}
|
||||
|
||||
draw_rt = colclip_rt ? colclip_rt : config.rt;
|
||||
}
|
||||
|
||||
// Destination Alpha Setup
|
||||
@@ -2798,13 +2869,13 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
IASetPrimitiveTopology(topology);
|
||||
|
||||
if (config.tex && (m_features.texture_barrier || config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_NONE))
|
||||
PSSetShaderResource(0, config.tex);
|
||||
PSSetShaderResource(TEXTURE_TEXTURE, config.tex);
|
||||
if (config.pal)
|
||||
PSSetShaderResource(1, config.pal);
|
||||
PSSetShaderResource(TEXTURE_PALETTE, config.pal);
|
||||
if (m_features.texture_barrier && (config.require_one_barrier || config.require_full_barrier))
|
||||
PSSetShaderResource(2, colclip_rt ? colclip_rt : config.rt);
|
||||
PSSetShaderResource(TEXTURE_RT, colclip_rt ? colclip_rt : config.rt);
|
||||
if (m_features.texture_barrier && (config.require_one_barrier || config.require_full_barrier) && config.ps.IsFeedbackLoopDepth())
|
||||
PSSetShaderResource(4, m_features.depth_feedback ? config.ds : m_ds_as_rt);
|
||||
PSSetShaderResource(TEXTURE_DEPTH, m_features.depth_feedback ? config.ds : m_ds_as_rt);
|
||||
|
||||
SetupSampler(config.sampler);
|
||||
|
||||
@@ -2874,10 +2945,10 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
psel.ps.date = 3;
|
||||
config.alpha_second_pass.ps.date = 3;
|
||||
SetupPipeline(psel);
|
||||
PSSetShaderResource(3, primid_texture);
|
||||
PSSetShaderResource(TEXTURE_PRIMID, primid_texture);
|
||||
}
|
||||
|
||||
if (m_ds_as_rt)
|
||||
if (draw_ds_as_rt)
|
||||
{
|
||||
// We must clear the blend equation of any dual source blending factors or
|
||||
// it may interact badly with MRTs, even if blending is disabled.
|
||||
@@ -2896,28 +2967,22 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
OMSetBlendState();
|
||||
}
|
||||
|
||||
GSTexture* draw_rt = colclip_rt ? colclip_rt : config.rt;
|
||||
GSTexture* draw_ds_as_rt = m_ds_as_rt;
|
||||
GSTexture* draw_ds = config.ds;
|
||||
|
||||
// Clear texture binding when it's bound to RT or DS.
|
||||
if (!config.tex && ((draw_rt && static_cast<GSTextureOGL*>(draw_rt)->GetID() == GLState::tex_unit[0]) ||
|
||||
(draw_ds && static_cast<GSTextureOGL*>(draw_ds)->GetID() == GLState::tex_unit[0])))
|
||||
PSSetShaderResource(0, nullptr);
|
||||
PSSetShaderResource(TEXTURE_TEXTURE, nullptr);
|
||||
|
||||
// Avoid changing framebuffer just to switch from rt+depth to rt and vice versa.
|
||||
bool fb_optimization_needs_barrier = false;
|
||||
if (!draw_rt && GLState::rt && GLState::ds == draw_ds && config.tex != GLState::rt &&
|
||||
GLState::rt->GetSize() == draw_ds->GetSize() && !draw_ds_as_rt)
|
||||
if (!(draw_rt || draw_ds_as_rt) && draw_ds && GLState::rt && GLState::rt->GetSize() == draw_ds->GetSize())
|
||||
{
|
||||
draw_rt = GLState::rt;
|
||||
fb_optimization_needs_barrier = !GLState::rt_written;
|
||||
fb_optimization_needs_barrier = !GLState::rt_written && GLState::ds == draw_ds;
|
||||
}
|
||||
else if (!draw_ds && GLState::ds && GLState::rt == draw_rt && config.tex != GLState::ds &&
|
||||
GLState::ds->GetSize() == draw_rt->GetSize() && !draw_ds_as_rt)
|
||||
else if (!(draw_ds || draw_ds_as_rt) && draw_rt && GLState::ds && GLState::ds->GetSize() == draw_rt->GetSize())
|
||||
{
|
||||
draw_ds = GLState::ds;
|
||||
fb_optimization_needs_barrier = !GLState::ds_written;
|
||||
fb_optimization_needs_barrier = !GLState::ds_written && GLState::rt == draw_rt;
|
||||
}
|
||||
|
||||
// Be careful of the rt already being bound and the blend using the RT without a barrier.
|
||||
@@ -3025,7 +3090,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
const GSVector2i size = config.rt->GetSize();
|
||||
const GSVector4 dRect(config.colclip_update_area);
|
||||
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
|
||||
StretchRect(colclip_rt, sRect, config.rt, dRect, ShaderConvert::COLCLIP_RESOLVE, false);
|
||||
StretchRect(colclip_rt, sRect, config.rt, dRect, ShaderConvert::COLCLIP_RESOLVE, Nearest);
|
||||
Recycle(colclip_rt);
|
||||
|
||||
g_gs_device->SetColorClipTexture(nullptr);
|
||||
@@ -3033,6 +3098,57 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
}
|
||||
}
|
||||
|
||||
void GSDeviceOGL::FeedbackCopyAndBind(const GSHWDrawConfig& config,
|
||||
GSTexture* rt, GSTexture* rt_clone, GSTexture* ds, GSTexture* ds_clone, const GSVector4i& copyarea)
|
||||
{
|
||||
if (rt_clone)
|
||||
{
|
||||
CopyRect(rt, rt_clone, copyarea, copyarea.left, copyarea.top);
|
||||
PSSetShaderResource(2, rt_clone);
|
||||
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_RT)
|
||||
PSSetShaderResource(0, rt_clone);
|
||||
}
|
||||
if (ds_clone)
|
||||
{
|
||||
CopyRect(ds, ds_clone, copyarea, copyarea.left, copyarea.top);
|
||||
PSSetShaderResource(4, ds_clone);
|
||||
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_DEPTH)
|
||||
PSSetShaderResource(0, ds_clone);
|
||||
}
|
||||
}
|
||||
|
||||
// Choose the best copy area based on the hazards and whether we need RT and/or DS copies.
|
||||
void GSDeviceOGL::FeedbackCopyAndBind(const GSHWDrawConfig& config,
|
||||
GSTexture* rt, GSTexture* rt_clone, GSTexture* ds, GSTexture* ds_clone,
|
||||
const GSVector4i& copyarea, const GSVector4i& samplearea)
|
||||
{
|
||||
const GSVector4i rtsize = (rt ? rt : ds)->GetRect();
|
||||
|
||||
if (config.tex_hazard != GSHWDrawConfig::TEX_HAZARD_NONE)
|
||||
{
|
||||
const GSVector4i union_rect = config.drawarea.runion(config.samplearea);
|
||||
const u32 size_union = union_rect.width() * union_rect.height();
|
||||
const u32 size_indiv = config.drawarea.width() * config.drawarea.height() +
|
||||
config.samplearea.width() * config.samplearea.height();
|
||||
|
||||
// Do an individual copy if the union is larger than the sum of individual areas.
|
||||
if (size_union > size_indiv)
|
||||
{
|
||||
FeedbackCopyAndBind(config, rt, rt_clone, ds, ds_clone, ProcessCopyArea(rtsize, config.drawarea));
|
||||
FeedbackCopyAndBind(config, rt, rt_clone, ds, ds_clone, ProcessCopyArea(rtsize, config.samplearea));
|
||||
}
|
||||
else
|
||||
{
|
||||
FeedbackCopyAndBind(config, rt, rt_clone, ds, ds_clone, ProcessCopyArea(rtsize, union_rect));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No RT/DS hazards so just need the draw area.
|
||||
FeedbackCopyAndBind(config, rt, rt_clone, ds, ds_clone, ProcessCopyArea(rtsize, config.drawarea));
|
||||
}
|
||||
}
|
||||
|
||||
void GSDeviceOGL::SendHWDraw(const GSHWDrawConfig& config,
|
||||
GSTexture* draw_rt_clone, GSTexture* draw_rt, GSTexture* draw_ds_clone, GSTexture* draw_ds,
|
||||
const bool one_barrier, const bool full_barrier)
|
||||
@@ -3042,27 +3158,6 @@ void GSDeviceOGL::SendHWDraw(const GSHWDrawConfig& config,
|
||||
Console.Warning("OpenGL: Possible unnecessary barrier detected.");
|
||||
#endif
|
||||
|
||||
auto CopyAndBind = [&](GSVector4i drawarea) {
|
||||
if (draw_rt_clone)
|
||||
{
|
||||
CopyRect(draw_rt, draw_rt_clone, drawarea, drawarea.left, drawarea.top);
|
||||
if ((one_barrier || full_barrier))
|
||||
PSSetShaderResource(2, draw_rt_clone);
|
||||
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_RT)
|
||||
PSSetShaderResource(0, draw_rt_clone);
|
||||
}
|
||||
if (draw_ds_clone)
|
||||
{
|
||||
CopyRect(draw_ds, draw_ds_clone, drawarea, drawarea.left, drawarea.top);
|
||||
if ((one_barrier || full_barrier))
|
||||
PSSetShaderResource(4, draw_ds_clone);
|
||||
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_DEPTH)
|
||||
PSSetShaderResource(0, draw_ds_clone);
|
||||
}
|
||||
};
|
||||
|
||||
const GSVector4i rtsize(0, 0, (draw_rt ? draw_rt : draw_ds)->GetWidth(), (draw_rt ? draw_rt : draw_ds)->GetHeight());
|
||||
|
||||
if (full_barrier)
|
||||
{
|
||||
pxAssert(config.drawlist && !config.drawlist->empty());
|
||||
@@ -3075,9 +3170,12 @@ void GSDeviceOGL::SendHWDraw(const GSHWDrawConfig& config,
|
||||
else
|
||||
pxAssert(config.drawlist_bbox && static_cast<u32>(config.drawlist_bbox->size()) == draw_list_size);
|
||||
|
||||
if (!m_features.texture_barrier && config.tex_hazard != config.TEX_HAZARD_NONE)
|
||||
FeedbackCopyAndBind(config, draw_rt, draw_rt_clone, draw_ds, draw_ds_clone, config.samplearea);
|
||||
|
||||
for (u32 n = 0, p = 0; n < draw_list_size; n++)
|
||||
{
|
||||
const u32 count = (*config.drawlist)[n] * indices_per_prim;
|
||||
const u32 count = config.drawlist->at(n) * indices_per_prim;
|
||||
|
||||
if (m_features.texture_barrier)
|
||||
{
|
||||
@@ -3085,8 +3183,8 @@ void GSDeviceOGL::SendHWDraw(const GSHWDrawConfig& config,
|
||||
}
|
||||
else
|
||||
{
|
||||
const GSVector4i original_bbox = (*config.drawlist_bbox)[n].rintersect(config.drawarea);
|
||||
CopyAndBind(ProcessCopyArea(rtsize, original_bbox));
|
||||
const GSVector4i bbox = config.drawlist_bbox->at(n).rintersect(config.drawarea);
|
||||
FeedbackCopyAndBind(config, draw_rt, draw_rt_clone, draw_ds, draw_ds_clone, bbox);
|
||||
}
|
||||
|
||||
Draw(config, p, count);
|
||||
@@ -3106,28 +3204,7 @@ void GSDeviceOGL::SendHWDraw(const GSHWDrawConfig& config,
|
||||
else
|
||||
{
|
||||
// Optimization: For alpha second pass we can reuse the copy snapshot from the first pass.
|
||||
if (config.tex_hazard)
|
||||
{
|
||||
const GSVector4i union_rect = config.drawarea.runion(config.samplearea);
|
||||
const u32 size_union = union_rect.width() * union_rect.height();
|
||||
const u32 size_indiv = config.drawarea.width() * config.drawarea.height() +
|
||||
config.samplearea.width() * config.samplearea.height();
|
||||
|
||||
// Do an individual copy if the union is larger than the sum of individual areas.
|
||||
if (size_union > size_indiv)
|
||||
{
|
||||
CopyAndBind(ProcessCopyArea(rtsize, config.drawarea));
|
||||
CopyAndBind(ProcessCopyArea(rtsize, config.samplearea));
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyAndBind(ProcessCopyArea(rtsize, union_rect));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyAndBind(ProcessCopyArea(rtsize, config.drawarea));
|
||||
}
|
||||
FeedbackCopyAndBind(config, draw_rt, draw_rt_clone, draw_ds, draw_ds_clone, config.drawarea, config.samplearea);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -115,6 +115,15 @@ public:
|
||||
using OMDepthStencilSelector = GSHWDrawConfig::DepthStencilSelector;
|
||||
using OMColorMaskSelector = GSHWDrawConfig::ColorMaskSelector;
|
||||
|
||||
enum TextureUnit : u32
|
||||
{
|
||||
TEXTURE_TEXTURE,
|
||||
TEXTURE_PALETTE,
|
||||
TEXTURE_RT,
|
||||
TEXTURE_PRIMID,
|
||||
TEXTURE_DEPTH,
|
||||
};
|
||||
|
||||
struct alignas(16) ProgramSelector
|
||||
{
|
||||
PSSelector ps;
|
||||
@@ -124,7 +133,7 @@ public:
|
||||
__fi bool operator==(const ProgramSelector& p) const { return BitEqual(*this, p); }
|
||||
__fi bool operator!=(const ProgramSelector& p) const { return !BitEqual(*this, p); }
|
||||
};
|
||||
static_assert(sizeof(ProgramSelector) == 16, "Program selector is 16 bytes");
|
||||
static_assert(sizeof(ProgramSelector) == 32, "Program selector is 32 bytes");
|
||||
|
||||
struct ProgramSelectorHash
|
||||
{
|
||||
@@ -182,13 +191,23 @@ private:
|
||||
struct
|
||||
{
|
||||
std::string vs;
|
||||
GLProgram ps[static_cast<int>(ShaderConvert::Count)]; // program object
|
||||
std::vector<GLProgram> ps; // program object
|
||||
GLuint ln = 0; // sampler object
|
||||
GLuint pt = 0; // sampler object
|
||||
GSDepthStencilOGL* dss = nullptr;
|
||||
GSDepthStencilOGL* dss_write = nullptr;
|
||||
} m_convert;
|
||||
|
||||
GLProgram& GetConvertProgram(ShaderConvertSelector shader)
|
||||
{
|
||||
return m_convert.ps[shader.Index()];
|
||||
}
|
||||
|
||||
GLProgram& GetConvertProgram(ShaderConvert shader)
|
||||
{
|
||||
return m_convert.ps[ShaderConvertSelector(shader).Index()];
|
||||
}
|
||||
|
||||
GLProgram m_present[static_cast<int>(PresentShader::Count)];
|
||||
|
||||
struct
|
||||
@@ -253,8 +272,8 @@ private:
|
||||
|
||||
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
|
||||
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) override;
|
||||
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) override;
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const Filter filter) override;
|
||||
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, Filter filter, const InterlaceConstantBuffer& cb) override;
|
||||
|
||||
bool CompileFXAAProgram();
|
||||
void DoFXAA(GSTexture* sTex, GSTexture* dTex) override;
|
||||
@@ -279,9 +298,9 @@ private:
|
||||
void SetIndexBuffer(std::unique_ptr<GLStreamBuffer>& buffer, const void* index, size_t count);
|
||||
|
||||
protected:
|
||||
using GSDevice::DoStretchRect; // Suppress overloaded virtual function warning
|
||||
virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear) override;
|
||||
|
||||
ShaderConvertSelector shader, Filter filter) override;
|
||||
public:
|
||||
GSDeviceOGL();
|
||||
virtual ~GSDeviceOGL();
|
||||
@@ -339,19 +358,24 @@ public:
|
||||
void InsertDebugMessage(DebugMessageCategory category, const char* fmt, ...) override;
|
||||
|
||||
// BlitRect *does* mess with GL state, be sure to re-bind.
|
||||
void BlitRect(GSTexture* sTex, const GSVector4i& r, const GSVector2i& dsize, bool at_origin, bool linear);
|
||||
void BlitRect(GSTexture* sTex, const GSVector4i& r, const GSVector2i& dsize, bool at_origin, Filter filter);
|
||||
|
||||
void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GLProgram& ps, bool linear);
|
||||
void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GLProgram& ps, bool alpha_blend, OMColorMaskSelector cms, bool linear);
|
||||
void PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear) override;
|
||||
void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GLProgram& ps, Filter filter);
|
||||
void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GLProgram& ps, bool alpha_blend, OMColorMaskSelector cms, Filter filter);
|
||||
void PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, Filter filter) override;
|
||||
void UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) override;
|
||||
void ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) override;
|
||||
void FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32 downsample_factor, const GSVector2i& clamp_min, const GSVector4& dRect) override;
|
||||
|
||||
void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) override;
|
||||
void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader) override;
|
||||
void DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, const GSVector2& ds);
|
||||
|
||||
void RenderHW(GSHWDrawConfig& config) override;
|
||||
void FeedbackCopyAndBind(const GSHWDrawConfig& config,
|
||||
GSTexture* rt, GSTexture* rt_clone, GSTexture* ds, GSTexture* ds_clone, const GSVector4i& copyarea);
|
||||
void FeedbackCopyAndBind(const GSHWDrawConfig& config,
|
||||
GSTexture* rt, GSTexture* rt_clone, GSTexture* ds, GSTexture* ds_clone,
|
||||
const GSVector4i& copyarea, const GSVector4i& samplearea);
|
||||
void SendHWDraw(const GSHWDrawConfig& config,
|
||||
GSTexture* draw_rt_clone, GSTexture* draw_rt, GSTexture* draw_ds_clone, GSTexture* draw_ds,
|
||||
const bool one_barrier, const bool full_barrier);
|
||||
|
||||
@@ -30,26 +30,25 @@ GSTextureOGL::GSTextureOGL(Type type, int width, int height, int levels, Format
|
||||
m_type = type;
|
||||
m_texture_id = 0;
|
||||
m_mipmap_levels = 1;
|
||||
int gl_fmt = 0;
|
||||
|
||||
// Bunch of constant parameter
|
||||
switch (m_format)
|
||||
{
|
||||
// 1 Channel integer
|
||||
case Format::PrimID:
|
||||
gl_fmt = GL_R32F;
|
||||
m_gl_format = GL_R32F;
|
||||
m_int_format = GL_RED;
|
||||
m_int_type = GL_INT;
|
||||
m_int_shift = 2;
|
||||
break;
|
||||
case Format::UInt32:
|
||||
gl_fmt = GL_R32UI;
|
||||
m_gl_format = GL_R32UI;
|
||||
m_int_format = GL_RED_INTEGER;
|
||||
m_int_type = GL_UNSIGNED_INT;
|
||||
m_int_shift = 2;
|
||||
break;
|
||||
case Format::UInt16:
|
||||
gl_fmt = GL_R16UI;
|
||||
m_gl_format = GL_R16UI;
|
||||
m_int_format = GL_RED_INTEGER;
|
||||
m_int_type = GL_UNSIGNED_SHORT;
|
||||
m_int_shift = 1;
|
||||
@@ -57,15 +56,15 @@ GSTextureOGL::GSTextureOGL(Type type, int width, int height, int levels, Format
|
||||
|
||||
// 1 Channel normalized
|
||||
case Format::UNorm8:
|
||||
gl_fmt = GL_R8;
|
||||
m_gl_format = GL_R8;
|
||||
m_int_format = GL_RED;
|
||||
m_int_type = GL_UNSIGNED_BYTE;
|
||||
m_int_shift = 0;
|
||||
break;
|
||||
|
||||
// 1 channel float
|
||||
case Format::Float32:
|
||||
gl_fmt = GL_R32F;
|
||||
case Format::DepthColor:
|
||||
m_gl_format = GL_R32F;
|
||||
m_int_format = GL_RED;
|
||||
m_int_type = GL_FLOAT;
|
||||
m_int_shift = 2;
|
||||
@@ -75,7 +74,7 @@ GSTextureOGL::GSTextureOGL(Type type, int width, int height, int levels, Format
|
||||
case Format::Color:
|
||||
case Format::ColorHQ:
|
||||
case Format::ColorHDR:
|
||||
gl_fmt = GL_RGBA8;
|
||||
m_gl_format = GL_RGBA8;
|
||||
m_int_format = GL_RGBA;
|
||||
m_int_type = GL_UNSIGNED_BYTE;
|
||||
m_int_shift = 2;
|
||||
@@ -83,7 +82,7 @@ GSTextureOGL::GSTextureOGL(Type type, int width, int height, int levels, Format
|
||||
|
||||
// 4 channel float
|
||||
case Format::ColorClip:
|
||||
gl_fmt = GL_RGBA16;
|
||||
m_gl_format = GL_RGBA16;
|
||||
m_int_format = GL_RGBA;
|
||||
m_int_type = GL_UNSIGNED_SHORT;
|
||||
m_int_shift = 3;
|
||||
@@ -94,14 +93,14 @@ GSTextureOGL::GSTextureOGL(Type type, int width, int height, int levels, Format
|
||||
{
|
||||
if (!g_gs_device->Features().framebuffer_fetch)
|
||||
{
|
||||
gl_fmt = GL_DEPTH32F_STENCIL8;
|
||||
m_gl_format = GL_DEPTH32F_STENCIL8;
|
||||
m_int_format = GL_DEPTH_STENCIL;
|
||||
m_int_type = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
|
||||
m_int_shift = 3; // 4 bytes for depth + 4 bytes for stencil by texels
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_fmt = GL_DEPTH_COMPONENT32F;
|
||||
m_gl_format = GL_DEPTH_COMPONENT32F;
|
||||
m_int_format = GL_DEPTH_COMPONENT;
|
||||
m_int_type = GL_FLOAT;
|
||||
m_int_shift = 2;
|
||||
@@ -110,28 +109,28 @@ GSTextureOGL::GSTextureOGL(Type type, int width, int height, int levels, Format
|
||||
break;
|
||||
|
||||
case Format::BC1:
|
||||
gl_fmt = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
|
||||
m_gl_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
|
||||
m_int_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
|
||||
m_int_type = GL_UNSIGNED_BYTE;
|
||||
m_int_shift = 1;
|
||||
break;
|
||||
|
||||
case Format::BC2:
|
||||
gl_fmt = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||||
m_gl_format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||||
m_int_format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||||
m_int_type = GL_UNSIGNED_BYTE;
|
||||
m_int_shift = 1;
|
||||
break;
|
||||
|
||||
case Format::BC3:
|
||||
gl_fmt = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
m_gl_format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
m_int_format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
m_int_type = GL_UNSIGNED_BYTE;
|
||||
m_int_shift = 1;
|
||||
break;
|
||||
|
||||
case Format::BC7:
|
||||
gl_fmt = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
|
||||
m_gl_format = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
|
||||
m_int_format = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
|
||||
m_int_type = GL_UNSIGNED_BYTE;
|
||||
m_int_shift = 1;
|
||||
@@ -157,7 +156,7 @@ GSTextureOGL::GSTextureOGL(Type type, int width, int height, int levels, Format
|
||||
glTextureParameteri(m_texture_id, GL_TEXTURE_SWIZZLE_A, GL_RED);
|
||||
}
|
||||
|
||||
glTextureStorage2D(m_texture_id, m_mipmap_levels, gl_fmt, m_size.x, m_size.y);
|
||||
glTextureStorage2D(m_texture_id, m_mipmap_levels, m_gl_format, m_size.x, m_size.y);
|
||||
}
|
||||
|
||||
GSTextureOGL::~GSTextureOGL()
|
||||
@@ -335,6 +334,8 @@ void GSTextureOGL::SetDebugName(std::string_view name)
|
||||
|
||||
if (glObjectLabel)
|
||||
glObjectLabel(GL_TEXTURE, m_texture_id, static_cast<GLsizei>(name.length()), static_cast<const GLchar*>(name.data()));
|
||||
|
||||
m_debug_name = name;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,6 +22,7 @@ private:
|
||||
u32 m_map_offset = 0;
|
||||
|
||||
// internal opengl format/type/alignment
|
||||
GLenum m_gl_format = 0;
|
||||
GLenum m_int_format = 0;
|
||||
GLenum m_int_type = 0;
|
||||
u32 m_int_shift = 0;
|
||||
@@ -33,6 +34,7 @@ public:
|
||||
__fi GLenum GetIntFormat() const { return m_int_format; }
|
||||
__fi GLenum GetIntType() const { return m_int_type; }
|
||||
__fi u32 GetIntShift() const { return m_int_shift; }
|
||||
__fi u32 GetGLFormat() const { return m_gl_format; }
|
||||
|
||||
void* GetNativeHandle() const override;
|
||||
|
||||
@@ -55,6 +57,7 @@ public:
|
||||
}
|
||||
|
||||
__fi u32 GetID() { return m_texture_id; }
|
||||
__fi u32 GetGLFormat() { return m_gl_format; }
|
||||
};
|
||||
|
||||
class GSDownloadTextureOGL final : public GSDownloadTexture
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -46,6 +46,7 @@ public:
|
||||
bool vk_khr_driver_properties : 1;
|
||||
bool vk_khr_shader_non_semantic_info : 1;
|
||||
bool vk_ext_attachment_feedback_loop_layout : 1;
|
||||
bool vk_ext_fragment_shader_interlock : 1;
|
||||
};
|
||||
|
||||
// Global state accessors
|
||||
@@ -61,8 +62,8 @@ public:
|
||||
// The interaction between raster order attachment access and fbfetch is unclear.
|
||||
__fi bool UseFeedbackLoopLayout() const
|
||||
{
|
||||
return (m_optional_extensions.vk_ext_attachment_feedback_loop_layout &&
|
||||
!m_optional_extensions.vk_ext_rasterization_order_attachment_access);
|
||||
return m_optional_extensions.vk_ext_attachment_feedback_loop_layout &&
|
||||
!m_optional_extensions.vk_ext_rasterization_order_attachment_access;
|
||||
}
|
||||
|
||||
// Helpers for getting constants
|
||||
@@ -301,6 +302,25 @@ public:
|
||||
FeedbackLoopFlag_ReadAndWriteDepth = 4,
|
||||
};
|
||||
|
||||
enum class ResourceType
|
||||
{
|
||||
SRV, // Shader resource view (read only)
|
||||
UAV, // Unordered access (read/write)
|
||||
};
|
||||
|
||||
static constexpr GSTextureVK::Layout GetResourceLayout(ResourceType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
pxFailRel("Impossible.");
|
||||
case ResourceType::SRV:
|
||||
return GSTextureVK::Layout::ShaderReadOnly;
|
||||
case ResourceType::UAV:
|
||||
return GSTextureVK::Layout::ReadWriteImage;
|
||||
}
|
||||
}
|
||||
|
||||
struct alignas(8) PipelineSelector
|
||||
{
|
||||
GSHWDrawConfig::PSSelector ps;
|
||||
@@ -334,7 +354,7 @@ public:
|
||||
__fi bool IsDepthFeedbackLoop() const { return ((feedback_loop_flags & FeedbackLoopFlag_ReadAndWriteDepth) != 0); }
|
||||
__fi bool IsTestingAndSamplingDepth() const { return ((feedback_loop_flags & (FeedbackLoopFlag_ReadDepth | FeedbackLoopFlag_ReadAndWriteDepth)) != 0); }
|
||||
};
|
||||
static_assert(sizeof(PipelineSelector) == 24, "Pipeline selector is 24 bytes");
|
||||
static_assert(sizeof(PipelineSelector) == 32, "Pipeline selector is 32 bytes");
|
||||
|
||||
struct PipelineSelectorHash
|
||||
{
|
||||
@@ -368,6 +388,8 @@ public:
|
||||
TFX_TEXTURE_RT,
|
||||
TFX_TEXTURE_PRIMID,
|
||||
TFX_TEXTURE_DEPTH,
|
||||
TFX_TEXTURE_RT_ROV,
|
||||
TFX_TEXTURE_DEPTH_ROV,
|
||||
|
||||
NUM_TFX_TEXTURES
|
||||
};
|
||||
@@ -398,18 +420,27 @@ private:
|
||||
|
||||
std::unordered_map<u32, VkSampler> m_samplers;
|
||||
|
||||
std::array<VkPipeline, static_cast<int>(ShaderConvert::Count)> m_convert{};
|
||||
std::vector<VkPipeline> m_convert;
|
||||
std::array<VkPipeline, static_cast<int>(PresentShader::Count)> m_present{};
|
||||
std::array<VkPipeline, 32> m_color_copy{};
|
||||
std::array<VkPipeline, 2> m_merge{};
|
||||
std::array<VkPipeline, NUM_INTERLACE_SHADERS> m_interlace{};
|
||||
VkPipeline m_colclip_setup_pipelines[2][2] = {}; // [depth][feedback_loop]
|
||||
VkPipeline m_colclip_finish_pipelines[2][2] = {}; // [depth][feedback_loop]
|
||||
VkRenderPass m_date_image_setup_render_passes[2][2] = {}; // [depth][clear]
|
||||
VkPipeline m_date_image_setup_pipelines[2][4] = {}; // [depth][datm]
|
||||
VkRenderPass m_primid_image_setup_render_passes[2][2] = {}; // [depth][clear]
|
||||
VkPipeline m_primid_image_setup_pipelines[2][4] = {}; // [depth][datm]
|
||||
VkPipeline m_fxaa_pipeline = {};
|
||||
VkPipeline m_shadeboost_pipeline = {};
|
||||
|
||||
VkPipeline GetConvertPipeline(ShaderConvertSelector shader) const
|
||||
{
|
||||
return m_convert[shader.Index()];
|
||||
}
|
||||
|
||||
VkPipeline GetConvertPipeline(ShaderConvert shader) const
|
||||
{
|
||||
return m_convert[ShaderConvertSelector(shader).Index()];
|
||||
}
|
||||
|
||||
std::unordered_map<u32, VkShaderModule> m_tfx_vertex_shaders;
|
||||
std::unordered_map<GSHWDrawConfig::PSSelector, VkShaderModule, GSHWDrawConfig::PSSelectorHash>
|
||||
m_tfx_fragment_shaders;
|
||||
@@ -441,9 +472,9 @@ private:
|
||||
GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
|
||||
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE,
|
||||
const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) final;
|
||||
const GSRegEXTBUF& EXTBUF, u32 c, const Filter filter) final;
|
||||
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) final;
|
||||
ShaderInterlace shader, Filter filter, const InterlaceConstantBuffer& cb) final;
|
||||
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) final;
|
||||
void DoFXAA(GSTexture* sTex, GSTexture* dTex) final;
|
||||
|
||||
@@ -482,9 +513,11 @@ private:
|
||||
void DestroyResources();
|
||||
|
||||
protected:
|
||||
using GSDevice::DoStretchRect; // Suppress overloaded virtual function warning
|
||||
virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
GSHWDrawConfig::ColorMaskSelector cms, ShaderConvert shader, bool linear) override;
|
||||
|
||||
ShaderConvertSelector shader, Filter filter) override;
|
||||
virtual void DoStretchRect(GSTexture* sTex, const GSVector4& sRect, const GSVector4& dRect,
|
||||
PresentShader shader, Filter filter) override;
|
||||
public:
|
||||
GSDeviceVK();
|
||||
~GSDeviceVK() override;
|
||||
@@ -548,19 +581,19 @@ public:
|
||||
void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY) override;
|
||||
|
||||
void PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
PresentShader shader, float shaderTime, bool linear) override;
|
||||
PresentShader shader, float shaderTime, Filter filter) override;
|
||||
void DrawMultiStretchRects(
|
||||
const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) override;
|
||||
void DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTextureVK* dTex, ShaderConvert shader);
|
||||
const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvertSelector shader) override;
|
||||
void DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTextureVK* dTex, ShaderConvertSelector shader);
|
||||
|
||||
void BeginRenderPassForStretchRect(
|
||||
GSTextureVK* dTex, const GSVector4i& dtex_rc, const GSVector4i& dst_rc, bool allow_discard = true);
|
||||
void DoStretchRect(GSTextureVK* sTex, const GSVector4& sRect, GSTextureVK* dTex, const GSVector4& dRect,
|
||||
VkPipeline pipeline, bool linear, bool allow_discard);
|
||||
VkPipeline pipeline, Filter filter, bool allow_discard);
|
||||
void DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect, const GSVector2i& ds);
|
||||
|
||||
void BlitRect(GSTexture* sTex, const GSVector4i& sRect, u32 sLevel, GSTexture* dTex, const GSVector4i& dRect,
|
||||
u32 dLevel, bool linear);
|
||||
u32 dLevel, Filter filter);
|
||||
|
||||
void UpdateCLUTTexture(
|
||||
GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) override;
|
||||
@@ -575,11 +608,12 @@ public:
|
||||
void IASetIndexBuffer(const void* index, size_t count);
|
||||
void VSSetIndexBuffer(const void* index, size_t count);
|
||||
|
||||
void PSSetShaderResource(int i, GSTexture* sr, bool check_state);
|
||||
void PSSetUnorderedAccess(GSTexture* rt, GSTexture* ds, bool write_rt, bool write_ds);
|
||||
void PSSetShaderResource(int i, GSTexture* sr, bool check_state, ResourceType type = ResourceType::SRV);
|
||||
void PSSetSampler(GSHWDrawConfig::SamplerSelector sel);
|
||||
|
||||
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i& scissor,
|
||||
FeedbackLoopFlag feedback_loop = FeedbackLoopFlag_None);
|
||||
FeedbackLoopFlag feedback_loop = FeedbackLoopFlag_None, const GSVector2i& viewport_size = {});
|
||||
|
||||
void SetVSConstantBuffer(const GSHWDrawConfig::VSConstantBuffer& cb);
|
||||
void SetPSConstantBuffer(const GSHWDrawConfig::PSConstantBuffer& cb);
|
||||
@@ -643,28 +677,31 @@ public:
|
||||
private:
|
||||
enum DIRTY_FLAG : u32
|
||||
{
|
||||
DIRTY_FLAG_TFX_TEXTURE_0 = (1 << 0), // 0, 1, 2, 3, 4
|
||||
DIRTY_FLAG_TFX_UBO = (1 << 5),
|
||||
DIRTY_FLAG_UTILITY_TEXTURE = (1 << 6),
|
||||
DIRTY_FLAG_BLEND_CONSTANTS = (1 << 7),
|
||||
DIRTY_FLAG_LINE_WIDTH = (1 << 8),
|
||||
DIRTY_FLAG_INDEX_BUFFER = (1 << 9),
|
||||
DIRTY_FLAG_VIEWPORT = (1 << 10),
|
||||
DIRTY_FLAG_SCISSOR = (1 << 11),
|
||||
DIRTY_FLAG_PIPELINE = (1 << 12),
|
||||
DIRTY_FLAG_VS_CONSTANT_BUFFER = (1 << 13),
|
||||
DIRTY_FLAG_PS_CONSTANT_BUFFER = (1 << 14),
|
||||
DIRTY_FLAG_VS_PUSH_CONSTANTS = (1 << 15),
|
||||
DIRTY_FLAG_TFX_TEXTURE_0 = (1 << 0), // 0, 1, 2, 3, 4, 5, 6
|
||||
DIRTY_FLAG_TFX_UBO = (1 << 7),
|
||||
DIRTY_FLAG_UTILITY_TEXTURE = (1 << 8),
|
||||
DIRTY_FLAG_BLEND_CONSTANTS = (1 << 9),
|
||||
DIRTY_FLAG_LINE_WIDTH = (1 << 10),
|
||||
DIRTY_FLAG_INDEX_BUFFER = (1 << 11),
|
||||
DIRTY_FLAG_VIEWPORT = (1 << 12),
|
||||
DIRTY_FLAG_SCISSOR = (1 << 13),
|
||||
DIRTY_FLAG_PIPELINE = (1 << 14),
|
||||
DIRTY_FLAG_VS_CONSTANT_BUFFER = (1 << 15),
|
||||
DIRTY_FLAG_PS_CONSTANT_BUFFER = (1 << 16),
|
||||
DIRTY_FLAG_VS_PUSH_CONSTANTS = (1 << 17),
|
||||
|
||||
DIRTY_FLAG_TFX_TEXTURE_TEX = (DIRTY_FLAG_TFX_TEXTURE_0 << 0),
|
||||
DIRTY_FLAG_TFX_TEXTURE_PALETTE = (DIRTY_FLAG_TFX_TEXTURE_0 << 1),
|
||||
DIRTY_FLAG_TFX_TEXTURE_RT = (DIRTY_FLAG_TFX_TEXTURE_0 << 2),
|
||||
DIRTY_FLAG_TFX_TEXTURE_PRIMID = (DIRTY_FLAG_TFX_TEXTURE_0 << 3),
|
||||
DIRTY_FLAG_TFX_TEXTURE_DEPTH = (DIRTY_FLAG_TFX_TEXTURE_0 << 4),
|
||||
DIRTY_FLAG_TFX_TEXTURE_RT_ROV = (DIRTY_FLAG_TFX_TEXTURE_0 << 5),
|
||||
DIRTY_FLAG_TFX_TEXTURE_DEPTH_ROV = (DIRTY_FLAG_TFX_TEXTURE_0 << 6),
|
||||
|
||||
DIRTY_FLAG_TFX_TEXTURES = DIRTY_FLAG_TFX_TEXTURE_TEX | DIRTY_FLAG_TFX_TEXTURE_PALETTE |
|
||||
DIRTY_FLAG_TFX_TEXTURE_RT | DIRTY_FLAG_TFX_TEXTURE_PRIMID |
|
||||
DIRTY_FLAG_TFX_TEXTURE_DEPTH,
|
||||
DIRTY_FLAG_TFX_TEXTURE_DEPTH | DIRTY_FLAG_TFX_TEXTURE_RT_ROV |
|
||||
DIRTY_FLAG_TFX_TEXTURE_DEPTH_ROV,
|
||||
|
||||
DIRTY_BASE_STATE = DIRTY_FLAG_INDEX_BUFFER | DIRTY_FLAG_PIPELINE | DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR |
|
||||
DIRTY_FLAG_BLEND_CONSTANTS | DIRTY_FLAG_LINE_WIDTH,
|
||||
@@ -705,7 +742,7 @@ private:
|
||||
float m_current_line_width = 1.0f;
|
||||
u8 m_blend_constant_color = 0;
|
||||
|
||||
std::array<const GSTextureVK*, NUM_TFX_TEXTURES> m_tfx_textures{};
|
||||
std::array<GSTextureVK*, NUM_TFX_TEXTURES> m_tfx_textures{};
|
||||
VkSampler m_tfx_sampler = VK_NULL_HANDLE;
|
||||
u32 m_tfx_sampler_sel = 0;
|
||||
VkDescriptorSet m_tfx_ubo_descriptor_set = VK_NULL_HANDLE;
|
||||
@@ -721,6 +758,7 @@ private:
|
||||
VkPipeline m_current_pipeline = VK_NULL_HANDLE;
|
||||
|
||||
std::unique_ptr<GSTextureVK> m_null_texture;
|
||||
VkFramebuffer m_null_framebuffer;
|
||||
|
||||
// current pipeline selector - we save this in the struct to avoid re-zeroing it every draw
|
||||
PipelineSelector m_pipeline_selector = {};
|
||||
|
||||
@@ -11,6 +11,24 @@
|
||||
#include "common/Console.h"
|
||||
#include "common/BitUtils.h"
|
||||
|
||||
VkFramebuffer GSTextureVK::CreateNullFramebuffer()
|
||||
{
|
||||
const VkRenderPass rp = GSDeviceVK::GetInstance()->GetRenderPass(
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||
VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, false, false);
|
||||
|
||||
if (!rp)
|
||||
return VK_NULL_HANDLE;
|
||||
|
||||
Vulkan::FramebufferBuilder fbb;
|
||||
fbb.SetSize(16384, 16384, 1);
|
||||
fbb.SetRenderPass(rp);
|
||||
|
||||
return fbb.Create(GSDeviceVK::GetInstance()->GetDevice());
|
||||
}
|
||||
|
||||
static constexpr const VkComponentMapping s_identity_swizzle{VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY};
|
||||
|
||||
@@ -101,7 +119,7 @@ std::unique_ptr<GSTextureVK> GSTextureVK::Create(Type type, Format format, int w
|
||||
pxAssert(levels == 1);
|
||||
ici.usage =
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
|
||||
(GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ? VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT
|
||||
: VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
|
||||
}
|
||||
@@ -239,6 +257,10 @@ void GSTextureVK::Destroy(bool defer)
|
||||
m_image = VK_NULL_HANDLE;
|
||||
m_allocation = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
m_debug_name.clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
VkImageLayout GSTextureVK::GetVkLayout() const
|
||||
@@ -523,6 +545,8 @@ void GSTextureVK::SetDebugName(std::string_view name)
|
||||
|
||||
Vulkan::SetObjectName(GSDeviceVK::GetInstance()->GetDevice(), m_image, "%.*s", static_cast<int>(name.size()), name.data());
|
||||
Vulkan::SetObjectName(GSDeviceVK::GetInstance()->GetDevice(), m_view, "%.*s", static_cast<int>(name.size()), name.data());
|
||||
|
||||
m_debug_name = name;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -547,13 +571,17 @@ void GSTextureVK::CommitClear(VkCommandBuffer cmdbuf)
|
||||
const VkImageSubresourceRange srr = {VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u};
|
||||
vkCmdClearDepthStencilImage(cmdbuf, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cv, 1, &srr);
|
||||
}
|
||||
else
|
||||
else if (IsRenderTarget())
|
||||
{
|
||||
alignas(16) VkClearColorValue cv;
|
||||
GSVector4::store<true>(cv.float32, GetUNormClearColor());
|
||||
GSVector4::store<true>(cv.float32, GetClearForFormat());
|
||||
const VkImageSubresourceRange srr = {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u};
|
||||
vkCmdClearColorImage(cmdbuf, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cv, 1, &srr);
|
||||
}
|
||||
else
|
||||
{
|
||||
pxFailRel("Illegal texture type for clear.");
|
||||
}
|
||||
|
||||
SetState(GSTexture::State::Dirty);
|
||||
}
|
||||
@@ -581,8 +609,22 @@ void GSTextureVK::TransitionToLayout(VkCommandBuffer command_buffer, Layout new_
|
||||
void GSTextureVK::TransitionSubresourcesToLayout(
|
||||
VkCommandBuffer command_buffer, int start_level, int num_levels, Layout old_layout, Layout new_layout)
|
||||
{
|
||||
// Windows RDNA2 drivers don't always correctly transition the layout(?) when ROV is involved.
|
||||
// ReadWriteImage -> Feedback transitions are broken.
|
||||
// ReadWriteImage -> Read only layout -> Feedback transitions are broken.
|
||||
// ReadWriteImage -> General layout -> Feedback transitions are broken.
|
||||
// ReadWriteImage -> Write only layout -> Feedback transitions works fine.
|
||||
// Not every broken transition gives broken rendering, the Shadow of the colossus eagle dump is fine after the 1st frame.
|
||||
// Transition to a write only layout using an extra barrier, then to feedback fixes this issue.
|
||||
if (old_layout == Layout::ReadWriteImage && new_layout != Layout::ColorAttachment && new_layout != Layout::ReadWriteImage)
|
||||
{
|
||||
GL_INS("VK: Doing extra transition for broken RDNA2 feedback transitions");
|
||||
TransitionSubresourcesToLayout(command_buffer, 0, num_levels, old_layout, Layout::ColorAttachment);
|
||||
old_layout = Layout::ColorAttachment;
|
||||
}
|
||||
|
||||
VkImageAspectFlags aspect;
|
||||
if (m_type == Type::DepthStencil)
|
||||
if (IsDepthStencil())
|
||||
{
|
||||
aspect = g_gs_device->Features().stencil_buffer ? (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) :
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
@@ -754,6 +796,14 @@ void GSTextureVK::TransitionSubresourcesToLayout(
|
||||
break;
|
||||
}
|
||||
vkCmdPipelineBarrier(command_buffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
|
||||
// Count as a UAV barrier if we transition to/from UAV.
|
||||
if (IsRenderTargetOrDepthStencil() &&
|
||||
(old_layout == Layout::ReadWriteImage || new_layout == Layout::ReadWriteImage))
|
||||
{
|
||||
g_perfmon.Put(GSPerfMon::Barriers, 1);
|
||||
g_perfmon.Put(GSPerfMon::BarriersROV, 1);
|
||||
}
|
||||
}
|
||||
|
||||
VkFramebuffer GSTextureVK::GetFramebuffer(bool feedback_loop)
|
||||
|
||||
@@ -42,6 +42,8 @@ public:
|
||||
__fi VkImage GetImage() const { return m_image; }
|
||||
__fi VkImageView GetView() const { return m_view; }
|
||||
__fi Layout GetLayout() const { return m_layout; }
|
||||
virtual bool IsUnorderedAccess() const override { return GetLayout() == Layout::ReadWriteImage; }
|
||||
|
||||
__fi VkFormat GetVkFormat() const { return m_vk_format; }
|
||||
|
||||
VkImageLayout GetVkLayout() const;
|
||||
@@ -70,6 +72,8 @@ public:
|
||||
void TransitionSubresourcesToLayout(
|
||||
VkCommandBuffer command_buffer, int start_level, int num_levels, Layout old_layout, Layout new_layout);
|
||||
|
||||
static VkFramebuffer CreateNullFramebuffer();
|
||||
|
||||
/// Framebuffers are lazily allocated.
|
||||
VkFramebuffer GetFramebuffer(bool feedback_loop);
|
||||
|
||||
|
||||
@@ -733,7 +733,7 @@ void Vulkan::DescriptorSetUpdateBuilder::PushUpdate(
|
||||
}
|
||||
|
||||
void Vulkan::DescriptorSetUpdateBuilder::AddImageDescriptorWrite(VkDescriptorSet set, u32 binding, VkImageView view,
|
||||
VkImageLayout layout /*= VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL*/)
|
||||
VkImageLayout layout /*= VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL*/, bool storage_image /*= false*/)
|
||||
{
|
||||
pxAssert(m_num_writes < MAX_WRITES && m_num_image_infos < MAX_IMAGE_INFOS);
|
||||
|
||||
@@ -747,7 +747,7 @@ void Vulkan::DescriptorSetUpdateBuilder::AddImageDescriptorWrite(VkDescriptorSet
|
||||
dw.dstSet = set;
|
||||
dw.dstBinding = binding;
|
||||
dw.descriptorCount = 1;
|
||||
dw.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
||||
dw.descriptorType = storage_image ? VK_DESCRIPTOR_TYPE_STORAGE_IMAGE : VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
||||
dw.pImageInfo = ⅈ
|
||||
}
|
||||
|
||||
|
||||
@@ -241,7 +241,7 @@ namespace Vulkan
|
||||
bool clear = true);
|
||||
|
||||
void AddImageDescriptorWrite(VkDescriptorSet set, u32 binding, VkImageView view,
|
||||
VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, bool storage_image = false);
|
||||
void AddSamplerDescriptorWrite(VkDescriptorSet set, u32 binding, VkSampler sampler);
|
||||
void AddSamplerDescriptorWrites(VkDescriptorSet set, u32 binding, const VkSampler* samplers, u32 num_samplers);
|
||||
void AddCombinedImageSamplerDescriptorWrite(VkDescriptorSet set, u32 binding, VkImageView view,
|
||||
|
||||
@@ -1357,6 +1357,12 @@ bool GameList::DownloadCovers(const std::vector<std::string>& url_templates, boo
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!FileSystem::CreateDirectoryPath(EmuFolders::Covers.c_str(), false))
|
||||
{
|
||||
progress->DisplayError(fmt::format("Failed to create covers directory: {}", EmuFolders::Covers).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> download_urls;
|
||||
{
|
||||
std::unique_lock lock(s_mutex);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user