mirror of
https://github.com/flyinghead/flycast.git
synced 2026-11-08 08:06:48 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a21b79cfbe | ||
|
|
3f4c24d350 | ||
|
|
645f413523 | ||
|
|
08478aa757 | ||
|
|
4aef8667b7 | ||
|
|
9d08da1fc9 | ||
|
|
4408aa7dbe | ||
|
|
d2e8c9465b | ||
|
|
04df0da7cb | ||
|
|
5eeddecb40 | ||
|
|
71aea45811 | ||
|
|
cf690fbb61 | ||
|
|
85b286ec47 | ||
|
|
07d0cf6839 | ||
|
|
5e43b603ac | ||
|
|
a23362cee0 | ||
|
|
040db856f8 | ||
|
|
8d0654c323 | ||
|
|
a045c52146 | ||
|
|
98531e07ea | ||
|
|
5020a267af | ||
|
|
3a21f545d8 | ||
|
|
f35167a0de | ||
|
|
0b6c09da02 | ||
|
|
d9c08bd081 | ||
|
|
927db7f189 | ||
|
|
badf36899e | ||
|
|
962b0bb65c | ||
|
|
6e940e4d08 | ||
|
|
90e9f70a1a | ||
|
|
bfdab4db20 | ||
|
|
f0e4574132 | ||
|
|
6cfbdf6586 | ||
|
|
6b2063b06f | ||
|
|
5875eda4d0 | ||
|
|
02a002d55b | ||
|
|
0305904873 | ||
|
|
ee84567c17 | ||
|
|
528235ce9d | ||
|
|
85a941d6c6 | ||
|
|
0a27b63584 | ||
|
|
6f5f91245b | ||
|
|
234955ac01 | ||
|
|
a5967a283f | ||
|
|
21a4935ec4 | ||
|
|
610e3cf968 | ||
|
|
80cf4406a7 | ||
|
|
cc4e3875f3 | ||
|
|
f7e227a4aa | ||
|
|
bbff377ceb | ||
|
|
f8372c51a7 | ||
|
|
e3e2c3a0d2 | ||
|
|
f96ce85365 | ||
|
|
aa79196d38 | ||
|
|
2b14c3e605 | ||
|
|
41ba110ef4 | ||
|
|
ad42a32260 | ||
|
|
cc408f9688 | ||
|
|
520e96a039 | ||
|
|
db9fbbaebf | ||
|
|
88384ad7d1 | ||
|
|
464b459073 | ||
|
|
aea228c3df | ||
|
|
8fdcea2e20 | ||
|
|
31bd943d67 | ||
|
|
ba78a3aa5b | ||
|
|
1948c66c11 | ||
|
|
3cf7cf0a7f | ||
|
|
a593cddf52 | ||
|
|
cecf16e65e | ||
|
|
cca7ed6bf7 | ||
|
|
f63cf7406a | ||
|
|
e21d666328 | ||
|
|
ab3f5dbc4c | ||
|
|
9d3125c546 | ||
|
|
86a6d7a4f5 | ||
|
|
0f214b1441 | ||
|
|
a0b50cd41d | ||
|
|
1d1754dc98 | ||
|
|
b8464ef6c5 | ||
|
|
692ca52182 | ||
|
|
b4ecaecd45 | ||
|
|
9954768636 | ||
|
|
cbffc5cade | ||
|
|
4bbf5c562e | ||
|
|
329e5ed467 | ||
|
|
19a160695c | ||
|
|
1e195b7237 | ||
|
|
2b37a5dc08 | ||
|
|
8aadf5b097 | ||
|
|
13428ba696 | ||
|
|
52f2ca7ff6 | ||
|
|
174ce8786b | ||
|
|
fc118f295d | ||
|
|
18cfe2f92f | ||
|
|
0d4a7dbac9 | ||
|
|
a370851494 | ||
|
|
7b49cc73ee | ||
|
|
a8c5af8425 | ||
|
|
3441a9ccf0 | ||
|
|
659d21680b | ||
|
|
2da833883b | ||
|
|
c301bf0827 | ||
|
|
1c4303b76d | ||
|
|
170a6ac36e | ||
|
|
92fa4c041d | ||
|
|
f34a9f6eac | ||
|
|
9fb69af355 | ||
|
|
59606d8935 | ||
|
|
bd7f5ec4c1 | ||
|
|
d082993a7a | ||
|
|
640d4162b6 | ||
|
|
66eb08f2d1 | ||
|
|
93fbd67a85 | ||
|
|
cf031717dd | ||
|
|
075ec1cf98 | ||
|
|
8f3b6a2371 | ||
|
|
673fb26d6e | ||
|
|
5fa98da17e | ||
|
|
9b2f33f7bd | ||
|
|
2b70c73f80 | ||
|
|
1aec64cbae | ||
|
|
611946559c | ||
|
|
2997c6396f | ||
|
|
859d5df056 | ||
|
|
8a1902e5a8 | ||
|
|
285655f52d | ||
|
|
fceb170a2a | ||
|
|
4376e89149 | ||
|
|
cbd1d3134e | ||
|
|
fc479dbcc0 | ||
|
|
ae47ac19b8 | ||
|
|
84f6bd3fef | ||
|
|
d3b2da8e3b | ||
|
|
493ccc27d1 | ||
|
|
b37e6dc28d | ||
|
|
8cd6a94e26 | ||
|
|
13df32ba3f | ||
|
|
262a39cafb | ||
|
|
480f2e31b0 | ||
|
|
d0bb0aea97 | ||
|
|
bf3f927a99 | ||
|
|
19818e717f | ||
|
|
b6491a3842 | ||
|
|
c04c696ba6 | ||
|
|
17474bf005 | ||
|
|
756ec0e672 | ||
|
|
3dfdb60139 | ||
|
|
5a409dbe2c | ||
|
|
9ef37d9776 | ||
|
|
ba0a357d48 | ||
|
|
659ffa4406 | ||
|
|
12bba31270 | ||
|
|
dd66e44871 | ||
|
|
c5c87522ca | ||
|
|
5ef80f0a17 | ||
|
|
7372df3aff | ||
|
|
cf514b0d6b | ||
|
|
b232a10167 | ||
|
|
2a465d2f03 | ||
|
|
802f70fedd | ||
|
|
5acfa7d3d6 | ||
|
|
85188bf137 | ||
|
|
bfc44f2b4e | ||
|
|
96aaa8b14a | ||
|
|
53ed006a54 | ||
|
|
171c41df12 | ||
|
|
4b53edb3bd | ||
|
|
62085539a7 | ||
|
|
1c8e558e25 | ||
|
|
568145c247 | ||
|
|
5703bc7df2 | ||
|
|
95a00a165a | ||
|
|
599bc8a823 | ||
|
|
9578841480 | ||
|
|
5387a6b534 | ||
|
|
bf09e96e04 | ||
|
|
b5d8cecd91 | ||
|
|
6d913f42c8 | ||
|
|
1e0a875fa3 | ||
|
|
4d77ce5a66 | ||
|
|
f3a6fb7d8b | ||
|
|
b6f73d96ca | ||
|
|
13f3c8281f | ||
|
|
0107435a73 | ||
|
|
ce674a872a | ||
|
|
51758b965e | ||
|
|
7fec511463 | ||
|
|
1dd006d846 | ||
|
|
2800927fa1 | ||
|
|
f133e3cccb | ||
|
|
b0a520fe18 | ||
|
|
3f30dd01ad | ||
|
|
0c081a9597 | ||
|
|
7176460de3 | ||
|
|
733a1fa73d | ||
|
|
e3809ba058 | ||
|
|
4d3de39c64 | ||
|
|
1765e50703 | ||
|
|
f9feaa313b | ||
|
|
9781d8971a | ||
|
|
a0a9b5bbc5 | ||
|
|
c684faf423 | ||
|
|
cdca559d99 | ||
|
|
d76dff8594 | ||
|
|
223504a206 | ||
|
|
1ab4eb00c0 | ||
|
|
32e3e7d9c5 | ||
|
|
98123b9215 | ||
|
|
9069a49145 | ||
|
|
d417237e64 | ||
|
|
648f33473f | ||
|
|
446619ce85 | ||
|
|
f5fa1f6210 | ||
|
|
976fb99aa3 | ||
|
|
a0529d1cfc | ||
|
|
8001af9743 | ||
|
|
e48b72a859 | ||
|
|
71ba018782 | ||
|
|
59ff44132b | ||
|
|
8a0323ec08 | ||
|
|
4c7df6c7f4 | ||
|
|
676cd3104b | ||
|
|
a40210c55c | ||
|
|
034f90c1e0 | ||
|
|
64223927b8 | ||
|
|
e2c03255bb | ||
|
|
63495d3a6a | ||
|
|
88466ec352 | ||
|
|
1995eb935b | ||
|
|
f6532ca27a | ||
|
|
75dd5305c4 | ||
|
|
76cf989455 | ||
|
|
5b8e932509 | ||
|
|
993b705d8b | ||
|
|
19204882c4 | ||
|
|
605dc59f8d | ||
|
|
2332884d8b | ||
|
|
94f3d80a75 | ||
|
|
0b0e64304e | ||
|
|
5a1a766bd4 | ||
|
|
c15f446ffc | ||
|
|
c88cdde9ec | ||
|
|
40dbf53792 | ||
|
|
0cbf6f6601 | ||
|
|
c8fc873cf9 | ||
|
|
b935bef906 | ||
|
|
c1f0dd81d2 | ||
|
|
5722dc90f0 | ||
|
|
e3c260f4ca | ||
|
|
d1e48c657e | ||
|
|
decf70c87c | ||
|
|
4de9076b49 | ||
|
|
922df88cdd | ||
|
|
f25aeee756 | ||
|
|
2b36953fdc | ||
|
|
1dcf302665 | ||
|
|
1fd95c2886 | ||
|
|
93e1d7fcee | ||
|
|
b2b860bb8e | ||
|
|
0bd88fc9d9 | ||
|
|
20f9450218 | ||
|
|
401c402afc | ||
|
|
77a105d888 | ||
|
|
257c6b729f | ||
|
|
c5c941e928 | ||
|
|
092006fbbe | ||
|
|
6add19fb04 | ||
|
|
02d4b821d7 | ||
|
|
3d00ac338b | ||
|
|
387b9778f3 | ||
|
|
582876b99e | ||
|
|
3b3391c0d1 | ||
|
|
df61b1046a | ||
|
|
8426bcad27 | ||
|
|
d22fa54f7b | ||
|
|
2d56dddf7a | ||
|
|
7da0549b8c | ||
|
|
b821ece052 | ||
|
|
b240da41e0 | ||
|
|
d85baba1d3 | ||
|
|
8a44b909a4 | ||
|
|
5362264b18 | ||
|
|
1858cf3b33 | ||
|
|
1f876cde39 | ||
|
|
7288c7b541 | ||
|
|
2b8f5a7b9d | ||
|
|
c2e1425209 | ||
|
|
c9c1218234 | ||
|
|
11d776aea1 | ||
|
|
1386744fe0 | ||
|
|
da0d012328 | ||
|
|
f88abf9987 | ||
|
|
4a4fa7792f | ||
|
|
73adbc660b | ||
|
|
e0d87eb093 | ||
|
|
85b8c599c4 | ||
|
|
71e9420929 | ||
|
|
a6ac753c64 | ||
|
|
55600c40a9 | ||
|
|
9070c246d4 | ||
|
|
19ccc6a38d | ||
|
|
ad8b41adb0 | ||
|
|
807b8dea91 | ||
|
|
8e8935b9c4 | ||
|
|
9d17fc15a3 | ||
|
|
1cadd4e923 | ||
|
|
ab791d1b9c | ||
|
|
4f206d2773 | ||
|
|
7f9d9b81aa | ||
|
|
19112aecb2 | ||
|
|
b5b0875203 | ||
|
|
9a557978c4 | ||
|
|
7f28b767e4 | ||
|
|
5f5a748031 | ||
|
|
7bcd8c819a | ||
|
|
7209a61583 | ||
|
|
1523fafce0 | ||
|
|
3915c55251 | ||
|
|
5259aa20e6 | ||
|
|
11ecb473b6 | ||
|
|
7982fdac1c | ||
|
|
54d92a11e8 | ||
|
|
5eb302898f | ||
|
|
5b3a414987 | ||
|
|
658e111e3c | ||
|
|
d08f0e6599 | ||
|
|
77a11d2a2e |
No files matched your search
+1
-1
@@ -1,5 +1,5 @@
|
||||
freebsd_instance:
|
||||
image_family: freebsd-13-0
|
||||
image_family: freebsd-13-1
|
||||
|
||||
env:
|
||||
CCACHE_DIR: /tmp/ccache
|
||||
|
||||
@@ -34,6 +34,8 @@ jobs:
|
||||
- name: Gradle
|
||||
working-directory: shell/android-studio
|
||||
run: ./gradlew assembleRelease --parallel
|
||||
env:
|
||||
SENTRY_UPLOAD_URL: ${{ secrets.SENTRY_UPLOAD_URL }}
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
@@ -71,6 +73,24 @@ jobs:
|
||||
run: aws s3 sync shell/android-studio/flycast/build/outputs/apk/release s3://flycast-builds/android/${GITHUB_REF#refs/}-$GITHUB_SHA --acl public-read --exclude='*.json' --follow-symlinks
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
|
||||
- name: Upload to S3 (symbols)
|
||||
run: aws s3 sync symbols s3://flycast-symbols/android --follow-symlinks
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
- name: Setup Sentry CLI
|
||||
uses: mathieu-bour/[email protected]
|
||||
env:
|
||||
SENTRY_TOKEN: ${{ secrets.SENTRY_TOKEN }}
|
||||
with:
|
||||
url: https://sentry.io
|
||||
token: ${{ env.SENTRY_TOKEN }}
|
||||
organization: flycast
|
||||
project: minidump
|
||||
if: ${{ env.SENTRY_TOKEN != '' }}
|
||||
|
||||
- name: Upload symbols to Sentry
|
||||
run: |
|
||||
VERSION=$(git describe --tags --always)
|
||||
sentry-cli releases new "$VERSION"
|
||||
sentry-cli releases set-commits "$VERSION" --auto
|
||||
sentry-cli upload-dif symbols
|
||||
shell: bash
|
||||
env:
|
||||
SENTRY_TOKEN: ${{ secrets.SENTRY_TOKEN }}
|
||||
if: ${{ env.SENTRY_TOKEN != '' }}
|
||||
+57
-13
@@ -20,7 +20,7 @@ jobs:
|
||||
- {name: i686-pc-windows-msvc, os: windows-latest, shell: cmd, arch: x86, cmakeArgs: -G Ninja, buildType: Release}
|
||||
- {name: apple-darwin, os: macos-latest, shell: sh, cmakeArgs: -G Xcode -DAPPLE_BREAKPAD=ON, destDir: osx, buildType: RelWithDebInfo}
|
||||
- {name: apple-ios, os: macos-latest, shell: sh, cmakeArgs: -DCMAKE_SYSTEM_NAME=iOS -G Xcode, destDir: ios, buildType: Release}
|
||||
- {name: x86_64-pc-linux-gnu, os: ubuntu-latest, shell: sh, cmakeArgs: -G Ninja, buildType: Release}
|
||||
- {name: x86_64-pc-linux-gnu, os: ubuntu-20.04, shell: sh, cmakeArgs: -G Ninja, destDir: linux, buildType: RelWithDebInfo}
|
||||
- {name: x86_64-pc-windows-msvc, os: windows-latest, shell: cmd, arch: x64, cmakeArgs: -G Ninja, buildType: Release}
|
||||
- {name: x86_64-w64-mingw32, os: windows-latest, shell: 'msys2 {0}', cmakeArgs: -G Ninja, destDir: win, buildType: RelWithDebInfo}
|
||||
- {name: libretro-x86_64-pc-linux-gnu, os: ubuntu-latest, shell: sh, cmakeArgs: -DLIBRETRO=ON -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -G Ninja, buildType: Release}
|
||||
@@ -29,9 +29,11 @@ jobs:
|
||||
steps:
|
||||
- name: Set up build environment (macOS)
|
||||
run: |
|
||||
# Unlink and re-link to prevent errors when github mac runner images install python outside of brew. See https://github.com/actions/setup-python/issues/577
|
||||
brew list -1 | grep python | while read formula; do brew unlink $formula; brew link --overwrite $formula; done
|
||||
brew update
|
||||
brew install libao ldid ninja pulseaudio
|
||||
VULKAN_VER=1.3.211.0 && aria2c --parameterized-uri=true https://{sdk.lunarg.com/sdk/download/$VULKAN_VER/mac,distfiles.macports.org/MoltenVK}/vulkansdk-macos-$VULKAN_VER.dmg
|
||||
VULKAN_VER=1.3.224.1 && aria2c --parameterized-uri=true https://{sdk.lunarg.com/sdk/download/$VULKAN_VER/mac,distfiles.macports.org/MoltenVK}/vulkansdk-macos-$VULKAN_VER.dmg
|
||||
hdiutil attach ./vulkansdk-macos-*.dmg
|
||||
sudo /Volumes/vulkansdk-macos-*/InstallVulkan.app/Contents/MacOS/InstallVulkan --root $HOME/VulkanSDK --accept-licenses --default-answer --confirm-command install
|
||||
hdiutil detach /Volumes/vulkansdk-macos-*
|
||||
@@ -40,8 +42,10 @@ jobs:
|
||||
|
||||
- name: Set up build environment (Linux)
|
||||
run: |
|
||||
sudo add-apt-repository ppa:christianrauch/libdecoration
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install ccache libao-dev libasound2-dev libevdev-dev libgl1-mesa-dev liblua5.3-dev libminiupnpc-dev libpulse-dev libsdl2-dev libudev-dev libzip-dev ninja-build
|
||||
sudo apt-get -y install ccache libao-dev libasound2-dev libevdev-dev libgl1-mesa-dev liblua5.3-dev libminiupnpc-dev libpulse-dev libsdl2-dev libudev-dev libzip-dev ninja-build libcurl4-openssl-dev
|
||||
sudo apt-get -y install libwayland-dev libdecor-0-dev libaudio-dev libjack-dev libsndio-dev libsamplerate0-dev libx11-dev libxext-dev libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libxkbcommon-dev libdrm-dev libgbm-dev libgles2-mesa-dev libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev fcitx-libs-dev
|
||||
if: runner.os == 'Linux'
|
||||
|
||||
- name: Set up build environment (Windows, MinGW)
|
||||
@@ -68,8 +72,12 @@ jobs:
|
||||
submodules: true
|
||||
|
||||
- name: Compile a universal OpenMP (macOS)
|
||||
run: export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1; brew reinstall --build-from-source --formula ./shell/apple/libomp.rb
|
||||
if: runner.os == 'macOS'
|
||||
run: HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew reinstall --build-from-source --formula ./shell/apple/libomp.rb
|
||||
if: matrix.config.name == 'apple-darwin'
|
||||
|
||||
- name: Compile OpenMP.xcframework (iOS)
|
||||
run: ./shell/apple/emulator-ios/OpenMP/build_ios_openmp.sh --disableSimulator
|
||||
if: matrix.config.name == 'apple-ios'
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
@@ -80,8 +88,10 @@ jobs:
|
||||
|
||||
- name: CMake
|
||||
run: |
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=${{ matrix.config.buildType }} -DCMAKE_INSTALL_PREFIX=artifact ${{ matrix.config.cmakeArgs }}
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=${{ matrix.config.buildType }} -DCMAKE_INSTALL_PREFIX=artifact ${{ matrix.config.cmakeArgs }} -DSENTRY_UPLOAD_URL=${{ env.SENTRY_UPLOAD_URL }}
|
||||
cmake --build build --config ${{ matrix.config.buildType }} --target install
|
||||
env:
|
||||
SENTRY_UPLOAD_URL: ${{ secrets.SENTRY_UPLOAD_URL }}
|
||||
|
||||
- name: Unit Tests
|
||||
run: |
|
||||
@@ -92,13 +102,29 @@ jobs:
|
||||
|
||||
- name: Dump symbols
|
||||
run: |
|
||||
core/deps/breakpad/bin/dump_syms artifact/bin/flycast.exe > flycast.exe.sym 2>/dev/null
|
||||
BUILD_ID=`head -1 flycast.exe.sym | awk '{ print $4 }'`
|
||||
mkdir -p symbols/flycast.exe/$BUILD_ID
|
||||
mv flycast.exe.sym symbols/flycast.exe/$BUILD_ID
|
||||
mkdir -p symbols
|
||||
core/deps/breakpad/bin/dump_syms artifact/bin/flycast.exe > symbols/flycast.sym 2>/dev/null
|
||||
strip artifact/bin/flycast.exe
|
||||
if: matrix.config.name == 'x86_64-w64-mingw32'
|
||||
|
||||
- name: Build breakpad (linux)
|
||||
working-directory: core/deps/breakpad
|
||||
run: |
|
||||
./configure
|
||||
make
|
||||
sudo make install
|
||||
if: matrix.config.name == 'x86_64-pc-linux-gnu'
|
||||
|
||||
- name: Dump symbols and make AppImage (linux)
|
||||
run: |
|
||||
mkdir -p symbols
|
||||
dump_syms artifact/bin/flycast > symbols/flycast.sym 2>/dev/null
|
||||
strip artifact/bin/flycast
|
||||
shell/linux/make-appimage.sh . artifact/bin appimage
|
||||
mv flycast-x86_64.AppImage artifact/bin
|
||||
rm artifact/bin/flycast
|
||||
if: matrix.config.name == 'x86_64-pc-linux-gnu'
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: flycast-${{ matrix.config.name }}
|
||||
@@ -130,7 +156,25 @@ jobs:
|
||||
shell: bash
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
|
||||
- name: Upload symbols to S3 (Windows-MinGW, macOS)
|
||||
run: aws s3 sync symbols s3://flycast-symbols/${{ matrix.config.destDir }} --follow-symlinks
|
||||
- name: Setup Sentry CLI
|
||||
uses: mathieu-bour/[email protected]
|
||||
env:
|
||||
SENTRY_TOKEN: ${{ secrets.SENTRY_TOKEN }}
|
||||
with:
|
||||
url: https://sentry.io
|
||||
token: ${{ env.SENTRY_TOKEN }}
|
||||
organization: flycast
|
||||
project: minidump
|
||||
if: ${{ env.SENTRY_TOKEN != '' }}
|
||||
|
||||
- name: Upload symbols to Sentry (Windows, macOS, Linux)
|
||||
run: |
|
||||
VERSION=$(git describe --tags --always)
|
||||
sentry-cli releases new "$VERSION"
|
||||
sentry-cli releases set-commits "$VERSION" --auto
|
||||
sentry-cli upload-dif symbols
|
||||
shell: bash
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' && (matrix.config.name == 'x86_64-w64-mingw32' || matrix.config.name == 'apple-darwin') }}
|
||||
env:
|
||||
SENTRY_TOKEN: ${{ secrets.SENTRY_TOKEN }}
|
||||
if: ${{ env.SENTRY_TOKEN != '' && (matrix.config.name == 'x86_64-w64-mingw32' || matrix.config.name == 'apple-darwin' || matrix.config.name == 'x86_64-pc-linux-gnu') }}
|
||||
|
||||
@@ -17,11 +17,13 @@ jobs:
|
||||
- name: Setup Java JDK
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 8
|
||||
java-version: 18
|
||||
distribution: zulu
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v3
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
@@ -14,11 +14,13 @@ jobs:
|
||||
- name: Setup Java JDK
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 8
|
||||
java-version: 18
|
||||
distribution: zulu
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v3
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
@@ -2,6 +2,7 @@ build/
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
shell/apple/emulator-ios/OpenMP/OpenMP.xcframework
|
||||
|
||||
# Visual Studio
|
||||
.vs/
|
||||
|
||||
@@ -22,6 +22,12 @@
|
||||
CORE_ARGS: -DLIBRETRO=ON -G Xcode -DCMAKE_BUILD_TYPE=Release
|
||||
EXTRA_PATH: Release
|
||||
|
||||
.core-defs-osx-arm64:
|
||||
extends: .core-defs
|
||||
variables:
|
||||
CORE_ARGS: -DLIBRETRO=ON -G Xcode -DCMAKE_BUILD_TYPE=Release
|
||||
EXTRA_PATH: Release
|
||||
|
||||
.core-defs-android:
|
||||
extends: .core-defs
|
||||
script:
|
||||
@@ -43,6 +49,10 @@ include:
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: 'osx-cmake-x86.yml'
|
||||
|
||||
# MacOS arm64
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: 'osx-cmake-arm64.yml'
|
||||
|
||||
# Linux
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/linux-cmake.yml'
|
||||
@@ -98,6 +108,12 @@ libretro-build-osx-x64:
|
||||
- .libretro-osx-cmake-x86
|
||||
- .core-defs-osx-x64
|
||||
|
||||
# MacOS arm 64-bit
|
||||
libretro-build-osx-arm64:
|
||||
extends:
|
||||
- .libretro-osx-cmake-arm64
|
||||
- .core-defs-osx-arm64
|
||||
|
||||
################################### CELLULAR #################################
|
||||
# Android ARMv7a
|
||||
android-armeabi-v7a:
|
||||
|
||||
+12
@@ -10,3 +10,15 @@
|
||||
[submodule "core/deps/breakpad"]
|
||||
path = core/deps/breakpad
|
||||
url = https://github.com/flyinghead/mingw-breakpad
|
||||
[submodule "core/deps/Vulkan-Headers"]
|
||||
path = core/deps/Vulkan-Headers
|
||||
url = https://github.com/KhronosGroup/Vulkan-Headers.git
|
||||
[submodule "core/deps/VulkanMemoryAllocator"]
|
||||
path = core/deps/VulkanMemoryAllocator
|
||||
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
|
||||
[submodule "core/deps/glslang"]
|
||||
path = core/deps/glslang
|
||||
url = https://github.com/KhronosGroup/glslang.git
|
||||
[submodule "core/deps/oboe"]
|
||||
path = core/deps/oboe
|
||||
url = https://github.com/google/oboe.git
|
||||
+907
-782
File diff suppressed because it is too large.
Load diff
+21
-8
@@ -24,6 +24,7 @@ const u8 RZipHeader[8] = { '#', 'R', 'Z', 'I', 'P', 'v', 1, '#' };
|
||||
bool RZipFile::Open(const std::string& path, bool write)
|
||||
{
|
||||
verify(file == nullptr);
|
||||
this->write = write;
|
||||
|
||||
file = nowide::fopen(path.c_str(), write ? "wb" : "rb");
|
||||
if (file == nullptr)
|
||||
@@ -49,6 +50,17 @@ bool RZipFile::Open(const std::string& path, bool write)
|
||||
chunkIndex = 0;
|
||||
chunkSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxChunkSize = 1024 * 1024;
|
||||
if (std::fwrite(RZipHeader, sizeof(RZipHeader), 1, file) != 1
|
||||
|| std::fwrite(&maxChunkSize, sizeof(maxChunkSize), 1, file) != 1
|
||||
|| std::fwrite(&size, sizeof(size), 1, file) != 1)
|
||||
{
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -57,6 +69,11 @@ void RZipFile::Close()
|
||||
{
|
||||
if (file != nullptr)
|
||||
{
|
||||
if (write)
|
||||
{
|
||||
std::fseek(file, sizeof(RZipHeader) + sizeof(maxChunkSize), SEEK_SET);
|
||||
std::fwrite(&size, sizeof(size), 1, file);
|
||||
}
|
||||
std::fclose(file);
|
||||
file = nullptr;
|
||||
if (chunk != nullptr)
|
||||
@@ -70,6 +87,7 @@ void RZipFile::Close()
|
||||
size_t RZipFile::Read(void *data, size_t length)
|
||||
{
|
||||
verify(file != nullptr);
|
||||
verify(!write);
|
||||
|
||||
u8 *p = (u8 *)data;
|
||||
size_t rv = 0;
|
||||
@@ -99,7 +117,7 @@ size_t RZipFile::Read(void *data, size_t length)
|
||||
delete [] zipped;
|
||||
chunkSize = (u32)tl;
|
||||
}
|
||||
u32 l = std::min(chunkSize - chunkIndex, (u32)length);
|
||||
u32 l = std::min(chunkSize - chunkIndex, (u32)(length - rv));
|
||||
memcpy(p, chunk + chunkIndex, l);
|
||||
p += l;
|
||||
chunkIndex += l;
|
||||
@@ -112,14 +130,9 @@ size_t RZipFile::Read(void *data, size_t length)
|
||||
size_t RZipFile::Write(const void *data, size_t length)
|
||||
{
|
||||
verify(file != nullptr);
|
||||
verify(std::ftell(file) == 0);
|
||||
verify(write);
|
||||
|
||||
maxChunkSize = 1024 * 1024;
|
||||
size = length;
|
||||
if (std::fwrite(RZipHeader, sizeof(RZipHeader), 1, file) != 1
|
||||
|| std::fwrite(&maxChunkSize, sizeof(maxChunkSize), 1, file) != 1
|
||||
|| std::fwrite(&size, sizeof(size), 1, file) != 1)
|
||||
return 0;
|
||||
size += length;
|
||||
const u8 *p = (const u8 *)data;
|
||||
// compression output buffer must be 0.1% larger + 12 bytes
|
||||
uLongf maxZippedSize = maxChunkSize + maxChunkSize / 1000 + 12;
|
||||
|
||||
@@ -41,4 +41,5 @@ private:
|
||||
u8 *chunk = nullptr;
|
||||
u32 chunkSize = 0;
|
||||
u32 chunkIndex = 0;
|
||||
bool write = false;
|
||||
};
|
||||
+12
-22
@@ -121,14 +121,11 @@
|
||||
#define USE_WINCE_HACK
|
||||
#endif
|
||||
|
||||
#define DC_PLATFORM_MASK 7
|
||||
#define DC_PLATFORM_DREAMCAST 0 /* Works, for the most part */
|
||||
#define DC_PLATFORM_DEV_UNIT 1 /* This is missing hardware */
|
||||
#define DC_PLATFORM_NAOMI 2 /* Works, for the most part */
|
||||
#define DC_PLATFORM_NAOMI2 3 /* Needs to be done, 2xsh4 + 2xpvr + custom TNL */
|
||||
#define DC_PLATFORM_ATOMISWAVE 4 /* Works, for the most part */
|
||||
#define DC_PLATFORM_HIKARU 5 /* Needs to be done, 2xsh4, 2x aica , custom vpu */
|
||||
#define DC_PLATFORM_AURORA 6 /* Needs to be done, Uses newer 300 mhz sh4 + 150 mhz pvr mbx SoC */
|
||||
#define DC_PLATFORM_DREAMCAST 0
|
||||
#define DC_PLATFORM_DEV_UNIT 1
|
||||
#define DC_PLATFORM_NAOMI 2
|
||||
#define DC_PLATFORM_NAOMI2 3
|
||||
#define DC_PLATFORM_ATOMISWAVE 4
|
||||
|
||||
//HOST_CPU
|
||||
#define CPU_X86 0x20000001
|
||||
@@ -139,14 +136,12 @@
|
||||
#define CPU_PPC 0x20000006
|
||||
#define CPU_PPC64 0x20000007
|
||||
#define CPU_ARM64 0x20000008
|
||||
#define CPU_MIPS64 0x20000009
|
||||
|
||||
//FEAT_SHREC, FEAT_AREC, FEAT_DSPREC
|
||||
#define DYNAREC_NONE 0x40000001
|
||||
#define DYNAREC_JIT 0x40000002
|
||||
#define DYNAREC_CPP 0x40000003
|
||||
|
||||
|
||||
//automatic
|
||||
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
@@ -222,12 +217,11 @@
|
||||
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
|
||||
#define TARGET_UWP
|
||||
#endif
|
||||
#if !defined(LIBRETRO) && !defined(TARGET_UWP)
|
||||
#define USE_DX9
|
||||
#ifdef HAVE_D3D11
|
||||
#define USE_DX11
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(LIBRETRO) && !defined(TARGET_NO_EXCEPTIONS)
|
||||
#define USE_GGPO
|
||||
#endif
|
||||
@@ -238,15 +232,11 @@
|
||||
#define VRAM_SIZE_MAX (16*1024*1024)
|
||||
#define ARAM_SIZE_MAX (8*1024*1024)
|
||||
|
||||
#define GD_CLOCK 33868800 //GDROM XTAL -- 768fs
|
||||
|
||||
#define AICA_CORE_CLOCK (GD_CLOCK*4/3) //[45158400] GD->PLL 3:4 -> AICA CORE -- 1024fs
|
||||
#define ADAC_CLOCK (AICA_CORE_CLOCK/4) //[11289600] 44100*256, AICA CORE -> PLL 4:1 -> ADAC -- 256fs
|
||||
#define AICA_ARM_CLOCK (AICA_CORE_CLOCK/2) //[22579200] AICA CORE -> PLL 2:1 -> ARM
|
||||
#define AICA_SDRAM_CLOCK (GD_CLOCK*2) //[67737600] GD-> PLL 2 -> SDRAM
|
||||
#define SH4_MAIN_CLOCK (200*1000*1000) //[200000000] XTal(13.5) -> PLL (33.3) -> PLL 1:6 (200)
|
||||
#define SH4_RAM_CLOCK (100*1000*1000) //[100000000] XTal(13.5) -> PLL (33.3) -> PLL 1:3 (100) , also suplied to HOLLY chip
|
||||
#define G2_BUS_CLOCK (25*1000*1000) //[25000000] from Holly, from SH4_RAM_CLOCK w/ 2 2:1 plls
|
||||
#define GD_CLOCK 33868800 //GDROM XTAL -- 768fs
|
||||
#define AICA_CORE_CLOCK (GD_CLOCK * 4 / 3) //[45158400] GD->PLL 3:4 -> AICA CORE -- 1024fs
|
||||
#define AICA_ARM_CLOCK (AICA_CORE_CLOCK / 2) //[22579200] AICA CORE -> PLL 2:1 -> ARM
|
||||
#define SH4_MAIN_CLOCK (200 * 1000 * 1000) //[200000000] XTal(13.5) -> PLL (33.3) -> PLL 1:6 (200)
|
||||
#define G2_BUS_CLOCK (25 * 1000 * 1000) //[25000000] from Holly, from SH4_RAM_CLOCK w/ 2 2:1 plls
|
||||
|
||||
#if defined(GLES) && !defined(GLES3) && !defined(GLES2)
|
||||
// Only use GL ES 2.0 API functions
|
||||
|
||||
+26
-13
@@ -12,43 +12,56 @@
|
||||
static int setconfig(char *arg[], int cl)
|
||||
{
|
||||
int rv=0;
|
||||
for(;;)
|
||||
|
||||
if (cl < 1)
|
||||
{
|
||||
if (cl<1)
|
||||
{
|
||||
WARN_LOG(COMMON, "-config : invalid number of parameters, format is section:key=value");
|
||||
break;
|
||||
}
|
||||
std::string value(arg[1]);
|
||||
WARN_LOG(COMMON, "-config : invalid number of parameters, format is section:key=value,section:key=value,...");
|
||||
return rv;
|
||||
}
|
||||
|
||||
std::string value(arg[1]);
|
||||
for(;;)
|
||||
{
|
||||
auto seppos = value.find(':');
|
||||
if (seppos == std::string::npos)
|
||||
{
|
||||
WARN_LOG(COMMON, "-config : invalid parameter %s, format is section:key=value", value.c_str());
|
||||
WARN_LOG(COMMON, "-config : invalid parameter %s, format is section:key=value,section:key=value,...", value.c_str());
|
||||
break;
|
||||
}
|
||||
auto eqpos = value.find('=', seppos);
|
||||
if (eqpos == std::string::npos)
|
||||
{
|
||||
WARN_LOG(COMMON, "-config : invalid parameter %s, format is section:key=value", value.c_str());
|
||||
WARN_LOG(COMMON, "-config : invalid parameter %s, format is section:key=value,section:key=value,...", value.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
auto commapos = value.find(',', eqpos);
|
||||
|
||||
std::string sect = trim_ws(value.substr(0, seppos));
|
||||
std::string key = trim_ws(value.substr(seppos + 1, eqpos - seppos - 1));
|
||||
value = trim_ws(value.substr(eqpos + 1));
|
||||
auto endofcurrent = (commapos == std::string::npos) ? value.size() : commapos;
|
||||
std::string next = (commapos == std::string::npos) ? "" : trim_ws(value.substr(endofcurrent + 1, value.size() - endofcurrent));
|
||||
value = trim_ws(value.substr(eqpos + 1, endofcurrent - eqpos - 1));
|
||||
|
||||
if (sect.empty() || key.empty())
|
||||
{
|
||||
WARN_LOG(COMMON, "-config : invalid parameter, format is section:key=value");
|
||||
WARN_LOG(COMMON, "-config : invalid parameter, format is section:key=value,section:key=value,...");
|
||||
break;
|
||||
}
|
||||
|
||||
INFO_LOG(COMMON, "Virtual cfg %s:%s=%s", sect.c_str(), key.c_str(), value.c_str());
|
||||
|
||||
cfgSetVirtual(sect, key, value);
|
||||
rv++;
|
||||
|
||||
if (cl>=3 && strcmp(arg[2],",")==0)
|
||||
if (commapos == std::string::npos)
|
||||
rv++;
|
||||
|
||||
if (commapos != std::string::npos)
|
||||
{
|
||||
value = next;
|
||||
continue;
|
||||
}
|
||||
else if (cl>=3 && strcmp(arg[2],",")==0)
|
||||
{
|
||||
cl-=2;
|
||||
arg+=2;
|
||||
|
||||
+18
-3
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
#include "option.h"
|
||||
#include "network/naomi_network.h"
|
||||
#include "debug/gdb_server.h"
|
||||
|
||||
namespace config {
|
||||
|
||||
@@ -36,8 +37,10 @@ Option<bool> FullMMU("Dreamcast.FullMMU");
|
||||
Option<bool> ForceWindowsCE("Dreamcast.ForceWindowsCE");
|
||||
Option<bool> AutoLoadState("Dreamcast.AutoLoadState");
|
||||
Option<bool> AutoSaveState("Dreamcast.AutoSaveState");
|
||||
Option<int> SavestateSlot("Dreamcast.SavestateSlot");
|
||||
Option<int, false> SavestateSlot("Dreamcast.SavestateSlot");
|
||||
Option<bool> ForceFreePlay("ForceFreePlay", true);
|
||||
Option<bool, false> FetchBoxart("FetchBoxart", true);
|
||||
Option<bool, false> BoxartDisplayMode("BoxartDisplayMode", true);
|
||||
|
||||
// Sound
|
||||
|
||||
@@ -102,11 +105,15 @@ Option<bool> ThreadedRendering("rend.ThreadedRendering", true);
|
||||
Option<bool> DupeFrames("rend.DupeFrames", false);
|
||||
Option<int> PerPixelLayers("rend.PerPixelLayers", 32);
|
||||
Option<bool> NativeDepthInterpolation("rend.NativeDepthInterpolation", false);
|
||||
Option<bool> EmulateFramebuffer("rend.EmulateFramebuffer", false);
|
||||
|
||||
// Misc
|
||||
|
||||
Option<bool> SerialConsole("Debug.SerialConsoleEnabled");
|
||||
Option<bool> SerialPTY("Debug.SerialPTY");
|
||||
Option<bool> GDB("Debug.GDBEnabled");
|
||||
Option<int> GDBPort("Debug.GDBPort", debugger::DEFAULT_PORT);
|
||||
Option<bool> GDBWaitForConnection("Debug.GDBWaitForConnection");
|
||||
Option<bool> UseReios("UseReios");
|
||||
Option<bool> FastGDRomLoad("FastGDRomLoad", false);
|
||||
|
||||
@@ -114,6 +121,13 @@ Option<bool> OpenGlChecks("OpenGlChecks", false, "validate");
|
||||
|
||||
Option<std::vector<std::string>, false> ContentPath("Dreamcast.ContentPath");
|
||||
Option<bool, false> HideLegacyNaomiRoms("Dreamcast.HideLegacyNaomiRoms", true);
|
||||
Option<bool, false> UploadCrashLogs("UploadCrashLogs", true);
|
||||
|
||||
// Profiler
|
||||
Option<bool> ProfilerEnabled("Profiler.Enabled");
|
||||
Option<bool> ProfilerDrawToGUI("Profiler.DrawGUI");
|
||||
Option<bool> ProfilerOutputTTY("Profiler.OutputTTY");
|
||||
Option<float> ProfilerFrameWarningTime("Profiler.FrameWarningTime", 1.0f / 55.0f);
|
||||
|
||||
// Network
|
||||
|
||||
@@ -131,6 +145,7 @@ Option<int> GGPOAnalogAxes("GGPOAnalogAxes", 0, "network");
|
||||
Option<bool> GGPOChat("GGPOChat", true, "network");
|
||||
Option<bool> GGPOChatTimeoutToggle("GGPOChatTimeoutToggle", true, "network");
|
||||
Option<int> GGPOChatTimeout("GGPOChatTimeout", 10, "network");
|
||||
Option<bool> NetworkOutput("NetworkOutput", false, "network");
|
||||
|
||||
#ifdef SUPPORT_DISPMANX
|
||||
Option<bool> DispmanxMaintainAspect("maintain_aspect", true, "dispmanx");
|
||||
@@ -166,11 +181,11 @@ std::array<std::array<Option<MapleDeviceType>, 2>, 4> MapleExpansionDevices {
|
||||
Option<MapleDeviceType>("device4.2", MDT_None, "input"),
|
||||
};
|
||||
#ifdef _WIN32
|
||||
Option<bool> UseRawInput("RawInput", false, "input");
|
||||
Option<bool, false> UseRawInput("RawInput", false, "input");
|
||||
#endif
|
||||
|
||||
#ifdef USE_LUA
|
||||
OptionString LuaFileName("LuaFileName", "flycast.lua");
|
||||
Option<std::string, false> LuaFileName("LuaFileName", "flycast.lua");
|
||||
#endif
|
||||
|
||||
} // namespace config
|
||||
+22
-8
@@ -157,8 +157,8 @@ public:
|
||||
T& get() { return value; }
|
||||
void set(T v) { value = v; }
|
||||
|
||||
void override(T v) {
|
||||
verify(PerGameOption);
|
||||
void override(T v)
|
||||
{
|
||||
overriddenDefault = v;
|
||||
overridden = true;
|
||||
value = v;
|
||||
@@ -372,8 +372,10 @@ extern Option<bool> FullMMU;
|
||||
extern Option<bool> ForceWindowsCE;
|
||||
extern Option<bool> AutoLoadState;
|
||||
extern Option<bool> AutoSaveState;
|
||||
extern Option<int> SavestateSlot;
|
||||
extern Option<int, false> SavestateSlot;
|
||||
extern Option<bool> ForceFreePlay;
|
||||
extern Option<bool, false> FetchBoxart;
|
||||
extern Option<bool, false> BoxartDisplayMode;
|
||||
|
||||
// Sound
|
||||
|
||||
@@ -413,10 +415,10 @@ extern AudioVolumeOption AudioVolume;
|
||||
class RendererOption : public Option<RenderType> {
|
||||
public:
|
||||
RendererOption()
|
||||
#ifdef USE_DX9
|
||||
: Option<RenderType>("pvr.rend", RenderType::DirectX9) {}
|
||||
#elif defined(TARGET_UWP)
|
||||
#if defined(USE_DX11)
|
||||
: Option<RenderType>("pvr.rend", RenderType::DirectX11) {}
|
||||
#elif defined(USE_DX9)
|
||||
: Option<RenderType>("pvr.rend", RenderType::DirectX9) {}
|
||||
#else
|
||||
: Option<RenderType>("pvr.rend", RenderType::OpenGL) {}
|
||||
#endif
|
||||
@@ -464,11 +466,15 @@ extern Option<int> TextureFiltering; // 0: default, 1: force nearest, 2: force l
|
||||
extern Option<bool> ThreadedRendering;
|
||||
extern Option<bool> DupeFrames;
|
||||
extern Option<bool> NativeDepthInterpolation;
|
||||
extern Option<bool> EmulateFramebuffer;
|
||||
|
||||
// Misc
|
||||
|
||||
extern Option<bool> SerialConsole;
|
||||
extern Option<bool> SerialPTY;
|
||||
extern Option<bool> GDB;
|
||||
extern Option<int> GDBPort;
|
||||
extern Option<bool> GDBWaitForConnection;
|
||||
extern Option<bool> UseReios;
|
||||
extern Option<bool> FastGDRomLoad;
|
||||
|
||||
@@ -476,6 +482,13 @@ extern Option<bool> OpenGlChecks;
|
||||
|
||||
extern Option<std::vector<std::string>, false> ContentPath;
|
||||
extern Option<bool, false> HideLegacyNaomiRoms;
|
||||
extern Option<bool, false> UploadCrashLogs;
|
||||
|
||||
// Profiling
|
||||
extern Option<bool> ProfilerEnabled;
|
||||
extern Option<bool> ProfilerDrawToGUI;
|
||||
extern Option<bool> ProfilerOutputTTY;
|
||||
extern Option<float> ProfilerFrameWarningTime;
|
||||
|
||||
// Network
|
||||
|
||||
@@ -493,6 +506,7 @@ extern Option<int> GGPOAnalogAxes;
|
||||
extern Option<bool> GGPOChat;
|
||||
extern Option<bool> GGPOChatTimeoutToggle;
|
||||
extern Option<int> GGPOChatTimeout;
|
||||
extern Option<bool> NetworkOutput;
|
||||
|
||||
#ifdef SUPPORT_DISPMANX
|
||||
extern Option<bool> DispmanxMaintainAspect;
|
||||
@@ -510,13 +524,13 @@ extern Option<int> VirtualGamepadVibration;
|
||||
extern std::array<Option<MapleDeviceType>, 4> MapleMainDevices;
|
||||
extern std::array<std::array<Option<MapleDeviceType>, 2>, 4> MapleExpansionDevices;
|
||||
#ifdef _WIN32
|
||||
extern Option<bool> UseRawInput;
|
||||
extern Option<bool, false> UseRawInput;
|
||||
#else
|
||||
constexpr bool UseRawInput = false;
|
||||
#endif
|
||||
|
||||
#ifdef USE_LUA
|
||||
extern OptionString LuaFileName;
|
||||
extern Option<std::string, false> LuaFileName;
|
||||
#endif
|
||||
|
||||
} // namespace config
|
||||
+233
-181
@@ -25,10 +25,13 @@
|
||||
#include "reios/reios.h"
|
||||
#include "cfg/cfg.h"
|
||||
#include "cfg/ini.h"
|
||||
#include "cfg/option.h"
|
||||
#include "emulator.h"
|
||||
|
||||
const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{
|
||||
{ "T36803N", nullptr, { 0xBC2CC }, { 0xC00 } }, // 102 Dalmatians (USA)
|
||||
{ "T36813D 50", nullptr, { 0xBDE8C }, { 0xC00 } }, // 102 Dalmatians (PAL)
|
||||
{ "MK-51064", nullptr, { 0x39EFF4 }, { 0x43700000 } }, // 18 wheeler (USA)
|
||||
{ "MK-5106450", nullptr, { 0x39EFF4 }, { 0x43700000 } }, // 18 wheeler (PAL)
|
||||
{ "HDR-0080", nullptr, { 0x6625C0 }, { 0x43700000 } }, // 18 wheeler (JP)
|
||||
@@ -105,6 +108,7 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{ "HDR-0100", nullptr, { 0x3235D4 }, { 0x00004000 } }, // Ferrari F355 Challenge (JP) vga mode only
|
||||
{ "MK-5115450", nullptr, { 0x3D3B10 }, { 0x43700000 } }, // Fighting Vipers 2 (PAL)
|
||||
{ "HDR-0133", nullptr, { 0x3D3AF0 }, { 0x43700000 } }, // Fighting Vipers 2 (JP)
|
||||
{ "T18805M", nullptr, { 0x1A39C0 }, { 0x3F400000 } }, // Fire Pro Wrestling D (JP)
|
||||
{ "MK-51114", nullptr, { 0x132DD8, 0xA26CA8, 0xA26738, 0xA275B8, 0xA26AD8, 0xA26908 },
|
||||
{ 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000 } }, // Floigan Bros. Ep. 1 (PAL)
|
||||
{ "T34201M", nullptr, { 0x586290, 0x586260 }, { 0x3F400000, 0x43F00000 } }, // Frame Gride (JP)
|
||||
@@ -120,9 +124,10 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
// { "T11001N", nullptr, { 0xC3D6BC, 0xD204A8, 0xD32FC8, 0xC7CF84, 0xD20548 },
|
||||
// { 0x00363031, 0x00000356, 0x00000280, 0x00000280, 0x00000280 } }, // Half-Life. Not working
|
||||
{ "MK-5104150", nullptr, { 0x23FCC4 }, { 0x44558000 } }, // Headhunter (PAL)
|
||||
{ "MK-5100250", nullptr, { 0x4C6708 }, { 0x43700000 } }, // House of the Dead 2, The (PAL)
|
||||
{ "MK-51002", nullptr, { 0x4C6088 }, { 0x43700000 } }, // House of the Dead 2, The (USA)
|
||||
{ "T38706M", nullptr, { 0xC0CFA0 }, { 0x3F400000 } }, // Ikaruga (JP)
|
||||
// gun coords issue
|
||||
//{ "MK-5100250", nullptr, { 0x4C6708 }, { 0x43700000 } }, // House of the Dead 2, The (PAL)
|
||||
//{ "MK-51002", nullptr, { 0x4C6088 }, { 0x43700000 } }, // House of the Dead 2, The (USA)
|
||||
//not working { "T38706M", nullptr, { 0xC0CFA0 }, { 0x3F400000 } }, // Ikaruga (JP)
|
||||
{ "T46001N", nullptr, { 0x1C8A98 }, { 0x3F400000 } }, // Illbleed (USA)
|
||||
{ "T44904D 50", nullptr, { 0x18C15C, 0x18C18C }, { 0x43F00000, 0x3F400000 } }, // Iron Aces (PAL)
|
||||
{ "MK-51058", nullptr, { 0x32E0FC, 0x32E12C }, { 0x43F00000, 0x3F400000 } }, // Jet Grind Radio (USA)
|
||||
@@ -145,7 +150,8 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{ "MK-5102250", "V1.001", { 0x107FDC, 0x11253C }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (v1.001) (PAL)
|
||||
{ "MK-5102250", "V1.009", { 0x106B5C, 0x1111F4 }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (v1.009) (PAL)
|
||||
{ "MK-51012", nullptr, { 0x10A01C, 0x1146FC }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (USA)
|
||||
{ "T0000M", nullptr, { 0x1CAEAC, 0x1CAEDC }, { 0x43F00000, 0x3F400000 } }, // Millenium Racer Y2K Fighters
|
||||
{ "T0000M", "MILLENNIUM RACER - Y2K FIGHTERS ",
|
||||
{ 0x1CAEAC, 0x1CAEDC }, { 0x43F00000, 0x3F400000 } }, // Millenium Racer Y2K Fighters
|
||||
{ "T1221M", nullptr, { 0x426B74 }, { 0x43F00000 } }, // Moero! Justice Gauken (JP)
|
||||
{ "T9701D", nullptr, { 0x31290C }, { 0x3F400000 } }, // Mortal Kombat Gold (PAL)
|
||||
{ "T-9701N", nullptr, { 0x337B8C }, { 0x3FA66666 } }, // Mortal Kombat Gold (USA)
|
||||
@@ -198,9 +204,15 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{ 0x3F400000, 0x43F00000, 0, 0x43F00000, 0 } },
|
||||
// Resident Evil: Code Veronica (USA)
|
||||
// Code 1-4 removes the black bars on top and bottom in FMV
|
||||
{ "T1204N", "RESIDENT EVIL CODE VERONICA ",
|
||||
{ "T1204N", "RESIDENT EVIL CODE VERONICA ",
|
||||
{ 0x329E40, 0x3838D8, 0x3838F8, 0x383918, 0x383938 },
|
||||
{ 0x3F400000, 0x43F00000, 0, 0x43F00000, 0 } },
|
||||
// Biohazard: Code Veronica: Kanzenban (JP)
|
||||
{ "T1240M", "BIOHAZARD CODE VERONICA PLUS ",
|
||||
{ 0x344AE1 }, { 0x003F6000 } },
|
||||
// Resident Evil: Code Veronica X Kanzenban (Eng. translation)
|
||||
{ "T1204N", "RESIDENT EVIL CODE VERONICA X ",
|
||||
{ 0x344AE1 }, { 0x003F6000 } },
|
||||
{ "T8107D 50", nullptr, { 0x0464FC, 0x046210 }, { 0x3A888889, 0x44200000 } }, // Re-Volt (PAL) Code 1 is a render fix
|
||||
{ "MK-5119250", nullptr, { 0x0C5EB4 }, { 0x3A888889 } }, // Rez (PAL)
|
||||
{ "T15122N", nullptr, { 0x8E7A80, 0x8E7AB4 }, { 0x43E10000, 0x3FAAAAAB } }, // Ring, The - Terror's Realm (USA)
|
||||
@@ -275,6 +287,7 @@ const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{ "T-8110D-50", nullptr, { 0x0C6B90, 0x0C6B94 }, { 0x43F00000, 0x43870000 } }, // Vanishing Point (PAL)
|
||||
// { "MK-5109450", nullptr, { 0x244134, 0x7A73B8, 0x7830D8, 0x7A74B8, 0x783138, 0x7A85A0, 0x6C7928, 0x6C7930, 0x6C7948, 0x6C7950 },
|
||||
//crash { 0x43F00000, 0x3F9C932E, 0x3F9C932E, 0x3F9C932E, 0x3F9C932E, 0x3F400000, 0, 0, 0, 0 } }, // Virtua Athlete 2K (PAL)
|
||||
{ "MK-51001", nullptr, { 0x19D518 }, { 0x43700000 } }, // Virtua Fighter 3 TB (NTSC)
|
||||
{ "MK-5100150", nullptr, { 0x19D718 }, { 0x43700000 } }, // Virtua Fighter 3 TB (PAL)
|
||||
{ "HDR-0002", nullptr, { 0x199FB0 }, { 0x43700000 } }, // Virtua Fighter 3 TB (JP)
|
||||
{ "MK-5105450", nullptr, { 0x456378 }, { 0x43700000 } }, // Virtua Tennis (v1.001) (PAL)
|
||||
@@ -310,11 +323,29 @@ const WidescreenCheat CheatManager::naomi_widescreen_cheats[] =
|
||||
{ " 18WHEELER", "18wheelr", { 0x5C64A8 }, { 0x43700000 } },
|
||||
{ "BEACH SPIKERS JAPAN", nullptr, { 0x065A7C }, { 0x44558000 } },
|
||||
{ "GUN SPIKE", nullptr, { 0x21A94 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D", "initd", { 0x155434 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D", "initdexp", { 0x159674 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D", "initdexpo", { 0x159634 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D", "initdo", { 0x14F5F4 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D Ver.2", "initdv2e", { 0x1B4F74 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D Ver.2", "initdv2j", { 0x1B4F34 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D Ver.2", "initdv2jo", { 0x1AD1F4 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D Ver.3", "initdv3e", { 0x1D0B34 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D Ver.3", "initdv3j", { 0x1D7C74 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D Ver.3", "initdv3jb", { 0x1D7774 }, { 0x3FE38E39 } },
|
||||
{ "AIRLINE PILOTS IN JAPAN", "alpilotj", { 0x1D62550 }, { 0x43700000 } },
|
||||
{ "MONKEY BALL JAPAN VERSION", nullptr, { 0x345B4, 0x45244, 0x454CC }, { 0x3FE38E39, 0x3FE38E39, 0x3FE38E39 } },
|
||||
{ "ZOMBIE REVENGE IN JAPAN", "zombrvn", { 0x7A4808 }, { 0x43700000 } },
|
||||
{ "ZOMBIE REVENGE IN JAPAN", "zombrvno", { 0x7A2E50 }, { 0x43700000 } },
|
||||
{ " BIOHAZARD GUN SURVIVOR2", "gunsur2", { 0x42EE80 }, { 0x3F400000 } },
|
||||
{ " BIOHAZARD GUN SURVIVOR2", "gunsur2j", { 0x42EBE0 }, { 0x3F400000 } },
|
||||
{ "SPAWN JAPAN", nullptr, { 0x02DEF8, 0x02E1C0 }, { 0x3A99999A, 0x3A99999A } },
|
||||
// gun coords problem with these 2 cheats
|
||||
// { " CONFIDENTIAL MISSION ---------", nullptr, { 0x24F798 }, { 0x43700000 } },
|
||||
// { "hotd2", nullptr, { 0x9C2AD8 }, { 0x43700000 } },
|
||||
{ "GUN SPIKE", nullptr, { 0xBACD7C }, { 0x440A7C9A } },
|
||||
{ " JAMBO SAFARI ------------", nullptr, { 0x2B1DE0 }, { 0x3FE38E39 } },
|
||||
{ "SOUL SURFER IN JAPAN", nullptr, { 0x8962C8 }, { 0x3FE38E39 } },
|
||||
|
||||
{ nullptr },
|
||||
};
|
||||
@@ -404,6 +435,21 @@ void CheatManager::reset(const std::string& gameId)
|
||||
cheats.emplace_back(Cheat::Type::setValue, "Skip DIMM version check", true, 16, 0x0007f486, 0xe001); // mov #1, r0
|
||||
cheats.back().builtIn = true;
|
||||
}
|
||||
else if (gameId == "Fixed BOOT strapper") // Extreme Hunting 2
|
||||
{
|
||||
setActive(true);
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "skip netbd check ifeq", true, 32, 0x00067b04, 0);
|
||||
cheats.back().builtIn = true;
|
||||
cheats.emplace_back(Cheat::Type::setValue, "skip netbd check", true, 32, 0x00067b04, 1); // 1 skips initNetwork()
|
||||
cheats.back().builtIn = true;
|
||||
cheats.emplace_back(Cheat::Type::setValue, "skip netbd check 2", true, 16, 0x0009acc8, 0x0009); // not acceptable by main board
|
||||
cheats.back().builtIn = true;
|
||||
// ac010000 should be d202 9302, but is changed to 78c0 8c93
|
||||
cheats.emplace_back(Cheat::Type::runNextIfEq, "fix boot ifeq", true, 32, 0x00010000, 0x8c9378c0);
|
||||
cheats.back().builtIn = true;
|
||||
cheats.emplace_back(Cheat::Type::setValue, "fix boot", true, 32, 0x00010000, 0x9302d202);
|
||||
cheats.back().builtIn = true;
|
||||
}
|
||||
}
|
||||
if (config::WidescreenGameHacks)
|
||||
{
|
||||
@@ -600,200 +646,206 @@ void CheatManager::addGameSharkCheat(const std::string& name, const std::string&
|
||||
Cheat conditionCheat;
|
||||
unsigned conditionLimit = 0;
|
||||
|
||||
for (unsigned i = 0; i < codes.size(); i++)
|
||||
{
|
||||
if (i < conditionLimit)
|
||||
cheats.push_back(conditionCheat);
|
||||
Cheat cheat{};
|
||||
cheat.description = name;
|
||||
u32 code = (codes[i] & 0xff000000) >> 24;
|
||||
switch (code)
|
||||
const size_t prevSize = cheats.size();
|
||||
try {
|
||||
for (unsigned i = 0; i < codes.size(); i++)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
if (i < conditionLimit)
|
||||
cheats.push_back(conditionCheat);
|
||||
Cheat cheat{};
|
||||
cheat.description = name;
|
||||
u32 code = (codes[i] & 0xff000000) >> 24;
|
||||
switch (code)
|
||||
{
|
||||
// 8/16/32-bit write
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing value");
|
||||
cheat.type = Cheat::Type::setValue;
|
||||
cheat.size = code == 0 ? 8 : code == 1 ? 16 : 32;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
cheat.value = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
u32 subcode = (codes[i] & 0x00ff0000) >> 16;
|
||||
switch (subcode)
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
{
|
||||
case 0:
|
||||
// 8/16/32-bit write
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing value");
|
||||
cheat.type = Cheat::Type::setValue;
|
||||
cheat.size = code == 0 ? 8 : code == 1 ? 16 : 32;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
cheat.value = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
u32 subcode = (codes[i] & 0x00ff0000) >> 16;
|
||||
switch (subcode)
|
||||
{
|
||||
// Group write
|
||||
int count = codes[i] & 0xffff;
|
||||
if (i + count + 1 >= codes.size())
|
||||
throw FlycastException("Missing values");
|
||||
cheat.type = Cheat::Type::setValue;
|
||||
cheat.size = 32;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
for (int j = 0; j < count; j++)
|
||||
case 0:
|
||||
{
|
||||
if (j == 1)
|
||||
cheat.description += " (cont'd)";
|
||||
// Group write
|
||||
int count = codes[i] & 0xffff;
|
||||
if (i + count + 1 >= codes.size())
|
||||
throw FlycastException("Missing values");
|
||||
cheat.type = Cheat::Type::setValue;
|
||||
cheat.size = 32;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
if (j == 1)
|
||||
cheat.description += " (cont'd)";
|
||||
cheat.value = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
cheat.address += 4;
|
||||
if (j < count - 1 && i < conditionLimit)
|
||||
cheats.push_back(conditionCheat);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
{
|
||||
// 8-bit inc/decrement
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing value");
|
||||
cheat.type = subcode == 1 ? Cheat::Type::increase : Cheat::Type::decrease;
|
||||
cheat.size = 8;
|
||||
cheat.value = codes[i] & 0xff;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
{
|
||||
// 16-bit inc/decrement
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing value");
|
||||
cheat.type = subcode == 3 ? Cheat::Type::increase : Cheat::Type::decrease;
|
||||
cheat.size = 16;
|
||||
cheat.value = codes[i] & 0xffff;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
{
|
||||
// 32-bit inc/decrement
|
||||
if (i + 2 >= codes.size())
|
||||
throw FlycastException("Missing address or value");
|
||||
cheat.type = subcode == 5 ? Cheat::Type::increase : Cheat::Type::decrease;
|
||||
cheat.size = 32;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
cheat.value = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
cheat.address += 4;
|
||||
if (j < count - 1 && i < conditionLimit)
|
||||
cheats.push_back(conditionCheat);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported cheat type");
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
{
|
||||
// 8-bit inc/decrement
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing value");
|
||||
cheat.type = subcode == 1 ? Cheat::Type::increase : Cheat::Type::decrease;
|
||||
cheat.size = 8;
|
||||
cheat.value = codes[i] & 0xff;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
{
|
||||
// 16-bit inc/decrement
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing value");
|
||||
cheat.type = subcode == 3 ? Cheat::Type::increase : Cheat::Type::decrease;
|
||||
cheat.size = 16;
|
||||
cheat.value = codes[i] & 0xffff;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
{
|
||||
// 32-bit inc/decrement
|
||||
if (i + 2 >= codes.size())
|
||||
throw FlycastException("Missing address or value");
|
||||
cheat.type = subcode == 5 ? Cheat::Type::increase : Cheat::Type::decrease;
|
||||
cheat.size = 32;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
cheat.value = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported cheat type");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
// 32-bit repeat write
|
||||
if (i + 2 >= codes.size())
|
||||
throw FlycastException("Missing count or value");
|
||||
cheat.type = Cheat::Type::setValue;
|
||||
cheat.size = 32;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
cheat.repeatCount = codes[++i] >> 16;
|
||||
cheat.repeatAddressIncrement = codes[i] & 0xffff;
|
||||
cheat.value = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
// copy bytes
|
||||
if (i + 2 >= codes.size())
|
||||
throw FlycastException("Missing count or destination address");
|
||||
cheat.type = Cheat::Type::copy;
|
||||
cheat.size = 8;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
cheat.destAddress = codes[++i] & 0x00ffffff;
|
||||
cheat.repeatCount = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
// TODO 7 change decryption type
|
||||
// TODO 0xb delay applying codes
|
||||
// TODO 0xc global enable test
|
||||
case 0xd:
|
||||
{
|
||||
// enable next code if eq/neq/lt/gt
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing count or destination address");
|
||||
cheat.size = 16;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
switch (codes[++i] >> 16)
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
case 0:
|
||||
cheat.type = Cheat::Type::runNextIfEq;
|
||||
break;
|
||||
case 1:
|
||||
cheat.type = Cheat::Type::runNextIfNeq;
|
||||
break;
|
||||
case 2:
|
||||
cheat.type = Cheat::Type::runNextIfLt;
|
||||
break;
|
||||
case 3:
|
||||
cheat.type = Cheat::Type::runNextIfGt;
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported conditional code");
|
||||
// 32-bit repeat write
|
||||
if (i + 2 >= codes.size())
|
||||
throw FlycastException("Missing count or value");
|
||||
cheat.type = Cheat::Type::setValue;
|
||||
cheat.size = 32;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
cheat.repeatCount = codes[++i] >> 16;
|
||||
cheat.repeatAddressIncrement = codes[i] & 0xffff;
|
||||
cheat.value = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
cheat.value = codes[i] & 0xffff;
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 0xe:
|
||||
{
|
||||
// multiline enable codes if eq/neq/lt/gt
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing test address");
|
||||
cheat.size = 16;
|
||||
cheat.value = codes[i] & 0xffff;
|
||||
conditionLimit = i + 1 + ((codes[i] >> 16) & 0xff);
|
||||
switch (codes[++i] >> 24)
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
case 0:
|
||||
cheat.type = Cheat::Type::runNextIfEq;
|
||||
break;
|
||||
case 1:
|
||||
cheat.type = Cheat::Type::runNextIfNeq;
|
||||
break;
|
||||
case 2:
|
||||
cheat.type = Cheat::Type::runNextIfLt;
|
||||
break;
|
||||
case 3:
|
||||
cheat.type = Cheat::Type::runNextIfGt;
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported conditional code");
|
||||
// copy bytes
|
||||
if (i + 2 >= codes.size())
|
||||
throw FlycastException("Missing count or destination address");
|
||||
cheat.type = Cheat::Type::copy;
|
||||
cheat.size = 8;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
cheat.destAddress = codes[++i] & 0x00ffffff;
|
||||
cheat.repeatCount = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
conditionCheat = cheat;
|
||||
break;
|
||||
// TODO 7 change decryption type
|
||||
// TODO 0xb delay applying codes
|
||||
// TODO 0xc global enable test
|
||||
case 0xd:
|
||||
{
|
||||
// enable next code if eq/neq/lt/gt
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing count or destination address");
|
||||
cheat.size = 16;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
switch (codes[++i] >> 16)
|
||||
{
|
||||
case 0:
|
||||
cheat.type = Cheat::Type::runNextIfEq;
|
||||
break;
|
||||
case 1:
|
||||
cheat.type = Cheat::Type::runNextIfNeq;
|
||||
break;
|
||||
case 2:
|
||||
cheat.type = Cheat::Type::runNextIfLt;
|
||||
break;
|
||||
case 3:
|
||||
cheat.type = Cheat::Type::runNextIfGt;
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported conditional code");
|
||||
}
|
||||
cheat.value = codes[i] & 0xffff;
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 0xe:
|
||||
{
|
||||
// multiline enable codes if eq/neq/lt/gt
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing test address");
|
||||
cheat.size = 16;
|
||||
cheat.value = codes[i] & 0xffff;
|
||||
conditionLimit = i + 1 + ((codes[i] >> 16) & 0xff);
|
||||
switch (codes[++i] >> 24)
|
||||
{
|
||||
case 0:
|
||||
cheat.type = Cheat::Type::runNextIfEq;
|
||||
break;
|
||||
case 1:
|
||||
cheat.type = Cheat::Type::runNextIfNeq;
|
||||
break;
|
||||
case 2:
|
||||
cheat.type = Cheat::Type::runNextIfLt;
|
||||
break;
|
||||
case 3:
|
||||
cheat.type = Cheat::Type::runNextIfGt;
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported conditional code");
|
||||
}
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
conditionCheat = cheat;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported cheat type");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported cheat type");
|
||||
}
|
||||
}
|
||||
setActive(!cheats.empty());
|
||||
#ifndef LIBRETRO
|
||||
std::string path = cfgLoadStr("cheats", gameId, "");
|
||||
if (path == "")
|
||||
{
|
||||
path = get_game_save_prefix() + ".cht";
|
||||
cfgSaveStr("cheats", gameId, path);
|
||||
}
|
||||
saveCheatFile(path);
|
||||
std::string path = cfgLoadStr("cheats", gameId, "");
|
||||
if (path == "")
|
||||
{
|
||||
path = get_game_save_prefix() + ".cht";
|
||||
cfgSaveStr("cheats", gameId, path);
|
||||
}
|
||||
saveCheatFile(path);
|
||||
#endif
|
||||
setActive(!cheats.empty());
|
||||
} catch (...) {
|
||||
cheats.erase(cheats.begin() + prevSize, cheats.end());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void CheatManager::saveCheatFile(const std::string& filename)
|
||||
|
||||
+46
-21
@@ -34,6 +34,9 @@
|
||||
#define SIGBUS 7
|
||||
#endif
|
||||
|
||||
#define SWAP_32(a) ((((a) & 0xff) << 24) | (((a) & 0xff00) << 8) | (((a) >> 8) & 0xff00) | (((a) >> 24) & 0xff))
|
||||
#define SWAP_16(a) ((((a) & 0x00ff) << 8) | (((a) & 0xff00) >> 8))
|
||||
|
||||
const std::array<Sh4RegType, 59> Sh4RegList {
|
||||
reg_r0,
|
||||
reg_r1,
|
||||
@@ -82,11 +85,20 @@ public:
|
||||
|
||||
void step()
|
||||
{
|
||||
bool restoreBreakpoint = removeMatchpoint(0, Sh4cntx.pc, 2);
|
||||
bool restoreBreakpoint = removeMatchpoint(Breakpoint::Type::BP_TYPE_SOFTWARE_BREAK, Sh4cntx.pc, 2);
|
||||
u32 savedPc = Sh4cntx.pc;
|
||||
emu.step();
|
||||
if (restoreBreakpoint)
|
||||
insertMatchpoint(0, savedPc, 2);
|
||||
insertMatchpoint(Breakpoint::Type::BP_TYPE_SOFTWARE_BREAK, savedPc, 2);
|
||||
}
|
||||
|
||||
void stepRange(u32 from, u32 to)
|
||||
{
|
||||
bool restoreBreakpoint = removeMatchpoint(Breakpoint::Type::BP_TYPE_SOFTWARE_BREAK, Sh4cntx.pc, 2);
|
||||
u32 savedPc = Sh4cntx.pc;
|
||||
emu.stepRange(from, to);
|
||||
if (restoreBreakpoint)
|
||||
insertMatchpoint(Breakpoint::Type::BP_TYPE_SOFTWARE_BREAK, savedPc, 2);
|
||||
}
|
||||
|
||||
int readAllRegs(u32 **regs)
|
||||
@@ -95,9 +107,9 @@ public:
|
||||
for (u32 i = 0; i < Sh4RegList.size(); i++)
|
||||
{
|
||||
if (Sh4RegList[i] == reg_sr_status)
|
||||
allregs[i] = sh4_sr_GetFull();
|
||||
allregs[i] = SWAP_32(sh4_sr_GetFull());
|
||||
else if (Sh4RegList[i] != NoReg)
|
||||
allregs[i] = *GetRegPtr(Sh4RegList[i]);
|
||||
allregs[i] = SWAP_32(*GetRegPtr(Sh4RegList[i]));
|
||||
}
|
||||
*regs = &allregs[0];
|
||||
return allregs.size();
|
||||
@@ -107,7 +119,7 @@ public:
|
||||
{
|
||||
for (u32 i = 0; i < Sh4RegList.size(); i++)
|
||||
if (Sh4RegList[i] != NoReg)
|
||||
*GetRegPtr(Sh4RegList[i]) = regs[i];
|
||||
*GetRegPtr(Sh4RegList[i]) = SWAP_32(regs[i]);
|
||||
}
|
||||
|
||||
u32 readReg(u32 regNum)
|
||||
@@ -116,9 +128,9 @@ public:
|
||||
return 0;
|
||||
Sh4RegType reg = Sh4RegList[regNum];
|
||||
if (reg == reg_sr_status)
|
||||
return sh4_sr_GetFull();
|
||||
return SWAP_32(sh4_sr_GetFull());
|
||||
if (reg != NoReg)
|
||||
return *GetRegPtr(reg);
|
||||
return SWAP_32(*GetRegPtr(reg));
|
||||
return 0;
|
||||
}
|
||||
void writeReg(u32 regNum, u32 value)
|
||||
@@ -127,9 +139,9 @@ public:
|
||||
return;
|
||||
Sh4RegType reg = Sh4RegList[regNum];
|
||||
if (reg == reg_sr_status)
|
||||
sh4_sr_SetFull(value);
|
||||
sh4_sr_SetFull(SWAP_32(value));
|
||||
else if (reg != NoReg)
|
||||
*GetRegPtr(reg) = value;
|
||||
*GetRegPtr(reg) = SWAP_32(value);
|
||||
}
|
||||
|
||||
const u8 *readMem(u32 addr, u32 len)
|
||||
@@ -141,14 +153,14 @@ public:
|
||||
{
|
||||
if (len >= 4 && (addr & 3) == 0)
|
||||
{
|
||||
*(u32 *)p = ReadMem32_nommu(addr);
|
||||
*(u32 *)p = SWAP_32(ReadMem32_nommu(addr));
|
||||
addr += 4;
|
||||
len -= 4;
|
||||
p += 4;
|
||||
}
|
||||
else if (len >= 2 && (addr & 1) == 0)
|
||||
{
|
||||
*(u16 *)p = ReadMem16_nommu(addr);
|
||||
*(u16 *)p = SWAP_16(ReadMem16_nommu(addr));
|
||||
addr += 2;
|
||||
len -= 2;
|
||||
p += 2;
|
||||
@@ -170,14 +182,14 @@ public:
|
||||
{
|
||||
if (len >= 4 && (addr & 3) == 0)
|
||||
{
|
||||
WriteMem32_nommu(addr, *(u32 *)p);
|
||||
WriteMem32_nommu(addr, SWAP_32(*(u32 *)p));
|
||||
addr += 4;
|
||||
len -= 4;
|
||||
p += 4;
|
||||
}
|
||||
else if (len >= 2 && (addr & 3) == 0)
|
||||
{
|
||||
WriteMem16_nommu(addr, *(u16 *)p);
|
||||
WriteMem16_nommu(addr, SWAP_16(*(u16 *)p));
|
||||
addr += 2;
|
||||
len -= 2;
|
||||
p += 2;
|
||||
@@ -197,10 +209,10 @@ public:
|
||||
return false;
|
||||
}
|
||||
// TODO other matchpoint types
|
||||
if (breakpoints.find(addr) != breakpoints.end())
|
||||
if (breakpoints[type].find(addr) != breakpoints[type].end())
|
||||
return true;
|
||||
breakpoints[addr] = Breakpoint(type, addr);
|
||||
breakpoints[addr].savedOp = ReadMem16_nommu(addr);
|
||||
breakpoints[type][addr] = Breakpoint(type, addr);
|
||||
breakpoints[type][addr].savedOp = ReadMem16_nommu(addr);
|
||||
WriteMem16_nommu(addr, 0xC308); // trapa #0x20
|
||||
return true;
|
||||
}
|
||||
@@ -210,11 +222,11 @@ public:
|
||||
WARN_LOG(COMMON, "removeMatchpoint: length != 2: %d", len);
|
||||
return false;
|
||||
}
|
||||
auto it = breakpoints.find(addr);
|
||||
if (it == breakpoints.end())
|
||||
auto it = breakpoints[type].find(addr);
|
||||
if (it == breakpoints[type].end())
|
||||
return false;
|
||||
WriteMem16_nommu(addr, it->second.savedOp);
|
||||
breakpoints.erase(it);
|
||||
breakpoints[type].erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -295,7 +307,10 @@ public:
|
||||
{
|
||||
verify(!Sh4cntx.CpuRunning);
|
||||
size = stack.size() * 8;
|
||||
return (const u32 *)&stack[0];
|
||||
if (!stack.empty())
|
||||
return (const u32 *)&stack[0];
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void subroutineCall()
|
||||
@@ -313,12 +328,22 @@ public:
|
||||
u32 exception = 0;
|
||||
|
||||
struct Breakpoint {
|
||||
enum Type
|
||||
{
|
||||
BP_TYPE_SOFTWARE_BREAK,
|
||||
BP_TYPE_HARDWARE_BREAK,
|
||||
BP_TYPE_WRITE_WATCHPOINT,
|
||||
BP_TYPE_READ_WATCHPOINT,
|
||||
BP_TYPE_ACCESS_WATCHPOINT,
|
||||
BP_TYPE_COUNT
|
||||
};
|
||||
|
||||
Breakpoint() = default;
|
||||
Breakpoint(u16 type, u32 addr) : addr(addr), type(type) { }
|
||||
u32 addr = 0;
|
||||
u16 type = 0;
|
||||
u16 savedOp = 0;
|
||||
};
|
||||
std::map<u32, Breakpoint> breakpoints;
|
||||
std::map<u32, Breakpoint> breakpoints[Breakpoint::Type::BP_TYPE_COUNT];
|
||||
std::vector<std::pair<u32, u32>> stack;
|
||||
};
|
||||
+81
-19
@@ -22,12 +22,14 @@
|
||||
#include "gdb_server.h"
|
||||
#include "debug_agent.h"
|
||||
#include "network/net_platform.h"
|
||||
#include "cfg/option.h"
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <cassert>
|
||||
|
||||
#define SERVER_PORT 3263
|
||||
#define MAX_PACKET_LEN 4096
|
||||
|
||||
namespace debugger {
|
||||
|
||||
@@ -40,7 +42,7 @@ public:
|
||||
Error(const char *reason) : std::runtime_error(reason) {}
|
||||
};
|
||||
|
||||
void init()
|
||||
void init(int port)
|
||||
{
|
||||
if (VALID(serverSocket))
|
||||
return;
|
||||
@@ -55,7 +57,7 @@ public:
|
||||
struct sockaddr_in serveraddr;
|
||||
memset(&serveraddr, 0, sizeof(serveraddr));
|
||||
serveraddr.sin_family = AF_INET;
|
||||
serveraddr.sin_port = htons(SERVER_PORT);
|
||||
serveraddr.sin_port = htons(port);
|
||||
|
||||
if (::bind(serverSocket, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
|
||||
{
|
||||
@@ -69,10 +71,14 @@ public:
|
||||
}
|
||||
EventManager::listen(Event::Resume, emuEventCallback);
|
||||
EventManager::listen(Event::Terminate, emuEventCallback);
|
||||
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
void term()
|
||||
{
|
||||
if (!initialised)
|
||||
return;
|
||||
EventManager::unlisten(Event::Resume, emuEventCallback);
|
||||
EventManager::unlisten(Event::Terminate, emuEventCallback);
|
||||
stop();
|
||||
@@ -90,12 +96,21 @@ public:
|
||||
|
||||
void run()
|
||||
{
|
||||
if (!initialised || thread.joinable())
|
||||
return;
|
||||
DEBUG_LOG(COMMON, "GdbServer starting");
|
||||
thread = std::thread(&GdbServer::serverThread, this);
|
||||
if (config::GDBWaitForConnection)
|
||||
{
|
||||
DEBUG_LOG(COMMON, "Waiting for GDB connection...");
|
||||
agent.interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
if (!initialised)
|
||||
return;
|
||||
if (thread.joinable())
|
||||
{
|
||||
DEBUG_LOG(COMMON, "GdbServer stopping");
|
||||
@@ -106,7 +121,7 @@ public:
|
||||
}
|
||||
|
||||
bool isRunning() const {
|
||||
return thread.joinable();
|
||||
return initialised && thread.joinable();
|
||||
}
|
||||
|
||||
// called on the emu thread
|
||||
@@ -496,7 +511,12 @@ private:
|
||||
const u32 *data = agent.getStack(len);
|
||||
len /= 4;
|
||||
|
||||
#if _MSC_VER // Non-const array size is a GCC extension
|
||||
assert((len * 9 * 2 + 1) < MAX_PACKET_LEN);
|
||||
char reply[MAX_PACKET_LEN];
|
||||
#else
|
||||
char reply[len * 9 * 2 + 1];
|
||||
#endif
|
||||
char *r = reply;
|
||||
for (u32 i = 0; i < len; i++)
|
||||
{
|
||||
@@ -515,9 +535,13 @@ private:
|
||||
sendPacket("");
|
||||
}
|
||||
else if (pkt.rfind("qSupported", 0) == 0)
|
||||
{
|
||||
// Tell the remote stub about features supported by GDB,
|
||||
// and query the stub for features it supports
|
||||
sendPacket("PacketSize=10000");
|
||||
char qsupported[128];
|
||||
sprintf_s(qsupported, 128, "PacketSize=%i;vContSupported+", MAX_PACKET_LEN);
|
||||
sendPacket(qsupported);
|
||||
}
|
||||
else if (pkt.rfind("qSymbol:", 0) == 0)
|
||||
// Notify the target that GDB is prepared to serve symbol lookup requests
|
||||
sendPacket("OK");
|
||||
@@ -570,11 +594,41 @@ private:
|
||||
if (pkt.rfind("vAttach;", 0) == 0)
|
||||
sendPacket("S05");
|
||||
else if (pkt.rfind("vCont?", 0) == 0)
|
||||
// not supported
|
||||
sendPacket("vCont;s;c");
|
||||
// supported vCont actions - (c)ontinue, (C)ontinue with signal, (s)tep, (S)tep with signal, (r)ange-step
|
||||
sendPacket("vCont;c;C;s;S;t;r");
|
||||
else if (pkt.rfind("vCont", 0) == 0)
|
||||
// not supported
|
||||
WARN_LOG(COMMON, "vCont not supported %s", pkt.c_str());
|
||||
{
|
||||
std::string vContCmd = pkt.substr(strlen("vCont;"));
|
||||
switch (vContCmd[0])
|
||||
{
|
||||
case 'c':
|
||||
case 'C':
|
||||
sendContinue(vContCmd);
|
||||
break;
|
||||
case 's':
|
||||
step(EXCEPT_NONE);
|
||||
break;
|
||||
case 'S':
|
||||
step();
|
||||
case 'r':
|
||||
{
|
||||
u32 from, to;
|
||||
if (sscanf(vContCmd.c_str(), "r%x,%x", &from, &to) == 2)
|
||||
{
|
||||
stepRange(from, to);
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN_LOG(COMMON, "Unsupported vCont:r format %s", pkt.c_str());
|
||||
sendContinue("c");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
WARN_LOG(COMMON, "vCont action not supported %s", pkt[6], pkt.c_str());
|
||||
}
|
||||
}
|
||||
else if (pkt.rfind("vFile:", 0) == 0)
|
||||
// not supported
|
||||
sendPacket("");
|
||||
@@ -599,11 +653,11 @@ private:
|
||||
sendPacket("OK");
|
||||
agent.kill();
|
||||
}
|
||||
else if (pkt.rfind("vMustReplyEmpty", 0) == 0)
|
||||
// Reply empty packet
|
||||
sendPacket("");
|
||||
else
|
||||
{
|
||||
WARN_LOG(COMMON, "unknown v packet: %s", pkt.c_str());
|
||||
sendPacket("");
|
||||
}
|
||||
}
|
||||
|
||||
void restart()
|
||||
@@ -617,6 +671,13 @@ private:
|
||||
sendPacket("S05");
|
||||
}
|
||||
|
||||
void stepRange(u32 from, u32 to)
|
||||
{
|
||||
sendPacket("OK");
|
||||
agent.stepRange(from, to);
|
||||
sendPacket("S05");
|
||||
}
|
||||
|
||||
void insertMatchpoint(const std::string& pkt)
|
||||
{
|
||||
u32 type;
|
||||
@@ -627,22 +688,22 @@ private:
|
||||
sendPacket("E01");
|
||||
}
|
||||
switch (type) {
|
||||
case 0: // soft bp
|
||||
case DebugAgent::Breakpoint::Type::BP_TYPE_SOFTWARE_BREAK: // soft bp
|
||||
if (agent.insertMatchpoint(0, addr, len))
|
||||
sendPacket("OK");
|
||||
else
|
||||
sendPacket("E01");
|
||||
break;
|
||||
case 1: // hardware bp
|
||||
case DebugAgent::Breakpoint::Type::BP_TYPE_HARDWARE_BREAK: // hardware bp
|
||||
sendPacket("");
|
||||
break;
|
||||
case 2: // write watchpoint
|
||||
case DebugAgent::Breakpoint::Type::BP_TYPE_WRITE_WATCHPOINT: // write watchpoint
|
||||
sendPacket("");
|
||||
break;
|
||||
case 3: // read watchpoint
|
||||
case DebugAgent::Breakpoint::Type::BP_TYPE_READ_WATCHPOINT: // read watchpoint
|
||||
sendPacket("");
|
||||
break;
|
||||
case 4: // access watchpoint
|
||||
case DebugAgent::Breakpoint::Type::BP_TYPE_ACCESS_WATCHPOINT: // access watchpoint
|
||||
sendPacket("");
|
||||
break;
|
||||
default:
|
||||
@@ -827,6 +888,7 @@ private:
|
||||
throw Error("I/O error");
|
||||
}
|
||||
|
||||
bool initialised = false;
|
||||
bool stopRequested = false;
|
||||
bool attached = false;
|
||||
bool postDebugTrapNeeded = false;
|
||||
@@ -840,9 +902,9 @@ public:
|
||||
|
||||
static GdbServer gdbServer;
|
||||
|
||||
void init()
|
||||
void init(int port)
|
||||
{
|
||||
gdbServer.init();
|
||||
gdbServer.init(port);
|
||||
}
|
||||
|
||||
void term()
|
||||
|
||||
@@ -23,9 +23,11 @@ namespace debugger {
|
||||
// exception thrown in response to trap
|
||||
struct Stop { };
|
||||
|
||||
static const int DEFAULT_PORT = 3263;
|
||||
|
||||
#ifdef GDB_SERVER
|
||||
|
||||
void init();
|
||||
void init(int port);
|
||||
void term();
|
||||
void run();
|
||||
void debugTrap(u32 event);
|
||||
@@ -33,7 +35,7 @@ struct Stop { };
|
||||
void subroutineReturn();
|
||||
|
||||
#else
|
||||
static inline void init() {}
|
||||
static inline void init(int port) {}
|
||||
static inline void term() {}
|
||||
static inline void run() {}
|
||||
static inline void debugTrap(u32 event) {}
|
||||
|
||||
+1
-1
Submodule core/deps/SDL updated: 8c9beb0c87...f070c83a60.
Submodule
+1
Submodule core/deps/Vulkan-Headers added at b75e5a02b6.
Submodule
+1
Submodule core/deps/VulkanMemoryAllocator added at a6bfc23725.
+1
-1
Submodule core/deps/breakpad updated: d2657e1267...4c3d5fce1a.
@@ -579,26 +579,6 @@ GGPO_API GGPOErrorCode __cdecl ggpo_set_disconnect_timeout(GGPOSession *,
|
||||
GGPO_API GGPOErrorCode __cdecl ggpo_set_disconnect_notify_start(GGPOSession *,
|
||||
int timeout);
|
||||
|
||||
/*
|
||||
* ggpo_log --
|
||||
*
|
||||
* Used to write to the ggpo.net log. In the current versions of the
|
||||
* SDK, a log file is only generated if the "quark.log" environment
|
||||
* variable is set to 1. This will change in future versions of the
|
||||
* SDK.
|
||||
*/
|
||||
GGPO_API void __cdecl ggpo_log(GGPOSession *,
|
||||
const char *fmt, ...);
|
||||
/*
|
||||
* ggpo_logv --
|
||||
*
|
||||
* A varargs compatible version of ggpo_log. See ggpo_log for
|
||||
* more details.
|
||||
*/
|
||||
GGPO_API void __cdecl ggpo_logv(GGPOSession *,
|
||||
const char *fmt,
|
||||
va_list args);
|
||||
|
||||
/*
|
||||
* ggpo_send_message --
|
||||
*
|
||||
|
||||
@@ -20,7 +20,6 @@ struct GGPOSession {
|
||||
virtual GGPOErrorCode IncrementFrame(void) { return GGPO_OK; }
|
||||
virtual GGPOErrorCode DisconnectPlayer(GGPOPlayerHandle handle) { return GGPO_OK; }
|
||||
virtual GGPOErrorCode GetNetworkStats(GGPONetworkStats *stats, GGPOPlayerHandle handle) { return GGPO_OK; }
|
||||
virtual GGPOErrorCode Logv(const char *fmt, va_list list) { ::Logv(fmt, list); return GGPO_OK; }
|
||||
|
||||
virtual GGPOErrorCode SetFrameDelay(GGPOPlayerHandle player, int delay) { return GGPO_ERRORCODE_UNSUPPORTED; }
|
||||
virtual GGPOErrorCode SetDisconnectTimeout(int timeout) { return GGPO_ERRORCODE_UNSUPPORTED; }
|
||||
|
||||
@@ -130,12 +130,12 @@ Peer2PeerBackend::DoPoll(int timeout)
|
||||
total_min_confirmed = PollNPlayers(current_frame);
|
||||
}
|
||||
|
||||
Log("last confirmed frame in p2p backend is %d.\n", total_min_confirmed);
|
||||
Log("last confirmed frame in p2p backend is %d.", total_min_confirmed);
|
||||
if (total_min_confirmed >= 0) {
|
||||
ASSERT(total_min_confirmed != INT_MAX);
|
||||
if (_num_spectators > 0) {
|
||||
while (_next_spectator_frame <= total_min_confirmed) {
|
||||
Log("pushing frame %d to spectators.\n", _next_spectator_frame);
|
||||
Log("pushing frame %d to spectators.", _next_spectator_frame);
|
||||
|
||||
GameInput input;
|
||||
input.frame = _next_spectator_frame;
|
||||
@@ -147,7 +147,7 @@ Peer2PeerBackend::DoPoll(int timeout)
|
||||
_next_spectator_frame++;
|
||||
}
|
||||
}
|
||||
Log("setting confirmed frame in sync to %d.\n", total_min_confirmed);
|
||||
Log("setting confirmed frame in sync to %d.", total_min_confirmed);
|
||||
_sync.SetLastConfirmedFrame(total_min_confirmed);
|
||||
}
|
||||
|
||||
@@ -189,12 +189,12 @@ int Peer2PeerBackend::Poll2Players(int current_frame)
|
||||
if (!_local_connect_status[i].disconnected) {
|
||||
total_min_confirmed = MIN(_local_connect_status[i].last_frame, total_min_confirmed);
|
||||
}
|
||||
Log(" local endp: connected = %d, last_received = %d, total_min_confirmed = %d.\n", !_local_connect_status[i].disconnected, _local_connect_status[i].last_frame, total_min_confirmed);
|
||||
Log(" local endp: connected = %d, last_received = %d, total_min_confirmed = %d.", !_local_connect_status[i].disconnected, _local_connect_status[i].last_frame, total_min_confirmed);
|
||||
if (!queue_connected && !_local_connect_status[i].disconnected) {
|
||||
Log("disconnecting i %d by remote request.\n", i);
|
||||
Log("disconnecting i %d by remote request.", i);
|
||||
DisconnectPlayerQueue(i, total_min_confirmed);
|
||||
}
|
||||
Log(" total_min_confirmed = %d.\n", total_min_confirmed);
|
||||
Log(" total_min_confirmed = %d.", total_min_confirmed);
|
||||
}
|
||||
return total_min_confirmed;
|
||||
}
|
||||
@@ -208,7 +208,7 @@ int Peer2PeerBackend::PollNPlayers(int current_frame)
|
||||
for (queue = 0; queue < _num_players; queue++) {
|
||||
bool queue_connected = true;
|
||||
int queue_min_confirmed = MAX_INT;
|
||||
Log("considering queue %d.\n", queue);
|
||||
Log("considering queue %d.", queue);
|
||||
for (i = 0; i < _num_players; i++) {
|
||||
// we're going to do a lot of logic here in consideration of endpoint i.
|
||||
// keep accumulating the minimum confirmed point for all n*n packets and
|
||||
@@ -218,16 +218,16 @@ int Peer2PeerBackend::PollNPlayers(int current_frame)
|
||||
|
||||
queue_connected = queue_connected && connected;
|
||||
queue_min_confirmed = MIN(last_received, queue_min_confirmed);
|
||||
Log(" endpoint %d: connected = %d, last_received = %d, queue_min_confirmed = %d.\n", i, connected, last_received, queue_min_confirmed);
|
||||
Log(" endpoint %d: connected = %d, last_received = %d, queue_min_confirmed = %d.", i, connected, last_received, queue_min_confirmed);
|
||||
} else {
|
||||
Log(" endpoint %d: ignoring... not running.\n", i);
|
||||
Log(" endpoint %d: ignoring... not running.", i);
|
||||
}
|
||||
}
|
||||
// merge in our local status only if we're still connected!
|
||||
if (!_local_connect_status[queue].disconnected) {
|
||||
queue_min_confirmed = MIN(_local_connect_status[queue].last_frame, queue_min_confirmed);
|
||||
}
|
||||
Log(" local endp: connected = %d, last_received = %d, queue_min_confirmed = %d.\n", !_local_connect_status[queue].disconnected, _local_connect_status[queue].last_frame, queue_min_confirmed);
|
||||
Log(" local endp: connected = %d, last_received = %d, queue_min_confirmed = %d.", !_local_connect_status[queue].disconnected, _local_connect_status[queue].last_frame, queue_min_confirmed);
|
||||
|
||||
if (queue_connected) {
|
||||
total_min_confirmed = MIN(queue_min_confirmed, total_min_confirmed);
|
||||
@@ -236,11 +236,11 @@ int Peer2PeerBackend::PollNPlayers(int current_frame)
|
||||
// so, we need to re-adjust. This can happen when we detect our own disconnect at frame n
|
||||
// and later receive a disconnect notification for frame n-1.
|
||||
if (!_local_connect_status[queue].disconnected || _local_connect_status[queue].last_frame > queue_min_confirmed) {
|
||||
Log("disconnecting queue %d by remote request.\n", queue);
|
||||
Log("disconnecting queue %d by remote request.", queue);
|
||||
DisconnectPlayerQueue(queue, queue_min_confirmed);
|
||||
}
|
||||
}
|
||||
Log(" total_min_confirmed = %d.\n", total_min_confirmed);
|
||||
Log(" total_min_confirmed = %d.", total_min_confirmed);
|
||||
}
|
||||
return total_min_confirmed;
|
||||
}
|
||||
@@ -335,7 +335,7 @@ Peer2PeerBackend::SyncInput(void *values,
|
||||
GGPOErrorCode
|
||||
Peer2PeerBackend::IncrementFrame(void)
|
||||
{
|
||||
Log("End of frame (%d)...\n", _sync.GetFrameCount());
|
||||
Log("End of frame (%d)...", _sync.GetFrameCount());
|
||||
_sync.IncrementFrame();
|
||||
DoPoll(0);
|
||||
PollSyncEvents();
|
||||
@@ -383,7 +383,7 @@ Peer2PeerBackend::OnUdpProtocolPeerEvent(UdpProtocol::Event &evt, int queue)
|
||||
|
||||
_sync.AddRemoteInput(queue, evt.u.input.input);
|
||||
// Notify the other endpoints which frame we received from a peer
|
||||
Log("setting remote connect status for queue %d to %d\n", queue, evt.u.input.input.frame);
|
||||
Log("setting remote connect status for queue %d to %d", queue, evt.u.input.input.frame);
|
||||
_local_connect_status[queue].last_frame = evt.u.input.input.frame;
|
||||
}
|
||||
break;
|
||||
@@ -493,14 +493,14 @@ Peer2PeerBackend::DisconnectPlayer(GGPOPlayerHandle player)
|
||||
int current_frame = _sync.GetFrameCount();
|
||||
// xxx: we should be tracking who the local player is, but for now assume
|
||||
// that if the endpoint is not initalized, this must be the local player.
|
||||
Log("Disconnecting local player %d at frame %d by user request.\n", queue, _local_connect_status[queue].last_frame);
|
||||
Log("Disconnecting local player %d at frame %d by user request.", queue, _local_connect_status[queue].last_frame);
|
||||
for (int i = 0; i < _num_players; i++) {
|
||||
if (_endpoints[i].IsInitialized()) {
|
||||
DisconnectPlayerQueue(i, current_frame);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log("Disconnecting queue %d at frame %d by user request.\n", queue, _local_connect_status[queue].last_frame);
|
||||
Log("Disconnecting queue %d at frame %d by user request.", queue, _local_connect_status[queue].last_frame);
|
||||
DisconnectPlayerQueue(queue, _local_connect_status[queue].last_frame);
|
||||
}
|
||||
return GGPO_OK;
|
||||
@@ -514,16 +514,16 @@ Peer2PeerBackend::DisconnectPlayerQueue(int queue, int syncto)
|
||||
|
||||
_endpoints[queue].Disconnect();
|
||||
|
||||
Log("Changing queue %d local connect status for last frame from %d to %d on disconnect request (current: %d).\n",
|
||||
Log("Changing queue %d local connect status for last frame from %d to %d on disconnect request (current: %d).",
|
||||
queue, _local_connect_status[queue].last_frame, syncto, framecount);
|
||||
|
||||
_local_connect_status[queue].disconnected = 1;
|
||||
_local_connect_status[queue].last_frame = syncto;
|
||||
|
||||
if (syncto != GameInput::NullFrame && syncto < framecount) {
|
||||
Log("adjusting simulation to account for the fact that %d disconnected @ %d.\n", queue, syncto);
|
||||
Log("adjusting simulation to account for the fact that %d disconnected @ %d.", queue, syncto);
|
||||
_sync.AdjustSimulation(syncto);
|
||||
Log("finished adjusting simulation.\n");
|
||||
Log("finished adjusting simulation.");
|
||||
}
|
||||
|
||||
info.code = GGPO_EVENTCODE_DISCONNECTED_FROM_PEER;
|
||||
|
||||
@@ -92,7 +92,7 @@ SpectatorBackend::SyncInput(void *values,
|
||||
GGPOErrorCode
|
||||
SpectatorBackend::IncrementFrame(void)
|
||||
{
|
||||
Log("End of frame (%d)...\n", _next_input_to_send - 1);
|
||||
Log("End of frame (%d)...", _next_input_to_send - 1);
|
||||
DoPoll(0);
|
||||
PollUdpProtocolEvents();
|
||||
|
||||
|
||||
@@ -83,7 +83,6 @@ SyncTestBackend::SyncInput(void *values,
|
||||
int size,
|
||||
int *disconnect_flags)
|
||||
{
|
||||
BeginLog(false);
|
||||
if (_rollingback) {
|
||||
_last_input = _saved_frames.front().input;
|
||||
} else {
|
||||
@@ -105,8 +104,7 @@ SyncTestBackend::IncrementFrame(void)
|
||||
_sync.IncrementFrame();
|
||||
_current_input.erase();
|
||||
|
||||
Log("End of frame(%d)...\n", _sync.GetFrameCount());
|
||||
EndLog();
|
||||
DEBUG_LOG(NETWORK, "End of frame(%d)...", _sync.GetFrameCount());
|
||||
|
||||
if (_rollingback) {
|
||||
return GGPO_OK;
|
||||
@@ -171,47 +169,9 @@ SyncTestBackend::RaiseSyncError(const char *fmt, ...)
|
||||
#ifdef _WIN32
|
||||
OutputDebugStringA(buf);
|
||||
#endif
|
||||
EndLog();
|
||||
// DebugBreak();
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
SyncTestBackend::Logv(char *fmt, va_list list)
|
||||
{
|
||||
if (_logfp) {
|
||||
vfprintf(_logfp, fmt, list);
|
||||
}
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
void
|
||||
SyncTestBackend::BeginLog(int saving)
|
||||
{
|
||||
EndLog();
|
||||
|
||||
char filename[MAX_PATH];
|
||||
#ifdef _WIN32
|
||||
CreateDirectoryA("synclogs", NULL);
|
||||
#else
|
||||
mkdir("synclogs", 0755);
|
||||
#endif
|
||||
snprintf(filename, ARRAY_SIZE(filename), "synclogs/%s-%04d-%s.log",
|
||||
saving ? "state" : "log",
|
||||
_sync.GetFrameCount(),
|
||||
_rollingback ? "replay" : "original");
|
||||
|
||||
_logfp = fopen(filename, "w");
|
||||
}
|
||||
|
||||
void
|
||||
SyncTestBackend::EndLog()
|
||||
{
|
||||
if (_logfp) {
|
||||
fprintf(_logfp, "Closing log file.\n");
|
||||
fclose(_logfp);
|
||||
_logfp = NULL;
|
||||
}
|
||||
}
|
||||
void
|
||||
SyncTestBackend::LogSaveStates(SavedInfo &info)
|
||||
{
|
||||
|
||||
@@ -24,7 +24,6 @@ public:
|
||||
virtual GGPOErrorCode AddLocalInput(GGPOPlayerHandle player, void *values, int size);
|
||||
virtual GGPOErrorCode SyncInput(void *values, int size, int *disconnect_flags);
|
||||
virtual GGPOErrorCode IncrementFrame(void);
|
||||
virtual GGPOErrorCode Logv(char *fmt, va_list list);
|
||||
|
||||
protected:
|
||||
struct SavedInfo {
|
||||
@@ -36,8 +35,6 @@ protected:
|
||||
};
|
||||
|
||||
void RaiseSyncError(const char *fmt, ...);
|
||||
void BeginLog(int saving);
|
||||
void EndLog();
|
||||
void LogSaveStates(SavedInfo &info);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "game_input.h"
|
||||
|
||||
#include "ggpo_types.h"
|
||||
#include "log.h"
|
||||
|
||||
void
|
||||
GameInput::init(int iframe, char *ibits, int isize, int offset)
|
||||
@@ -65,25 +64,23 @@ GameInput::log(char *prefix, bool show_frame) const
|
||||
size_t c = strlen(prefix);
|
||||
strcpy(buf, prefix);
|
||||
desc(buf + c, ARRAY_SIZE(buf) - c, show_frame);
|
||||
strcat(buf, "\n");
|
||||
Log(buf);
|
||||
Log("%s", buf);
|
||||
}
|
||||
|
||||
bool
|
||||
GameInput::equal(GameInput &other, bool bitsonly)
|
||||
{
|
||||
if (!bitsonly && frame != other.frame) {
|
||||
Log("frames don't match: %d, %d\n", frame, other.frame);
|
||||
Log("frames don't match: %d, %d", frame, other.frame);
|
||||
}
|
||||
if (size != other.size) {
|
||||
Log("sizes don't match: %d, %d\n", size, other.size);
|
||||
}
|
||||
if (memcmp(bits, other.bits, size)) {
|
||||
Log("bits don't match\n");
|
||||
Log("sizes don't match: %d, %d", size, other.size);
|
||||
}
|
||||
bool match = memcmp(bits, other.bits, size) == 0;
|
||||
if (!match)
|
||||
Log("bits don't match");
|
||||
ASSERT(size && other.size);
|
||||
return (bitsonly || frame == other.frame) &&
|
||||
size == other.size &&
|
||||
memcmp(bits, other.bits, size) == 0;
|
||||
size == other.size && match;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ typedef short int16;
|
||||
typedef int int32;
|
||||
|
||||
#include "ggponet.h"
|
||||
#include "log/Log.h"
|
||||
#include <stdexcept>
|
||||
|
||||
class GGPOException : public std::runtime_error {
|
||||
@@ -61,8 +62,6 @@ public:
|
||||
# error Unsupported platform
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
|
||||
/*
|
||||
* Macros
|
||||
*/
|
||||
@@ -70,16 +69,14 @@ public:
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
char assert_buf[1024]; \
|
||||
snprintf(assert_buf, sizeof(assert_buf) - 1, "Assertion: %s @ %s:%d (pid:%ld)", #x, __FILE__, __LINE__, (long)GGPOPlatform::GetProcessID()); \
|
||||
Log("%s\n", assert_buf); \
|
||||
Log("\n"); \
|
||||
Log("\n"); \
|
||||
Log("\n"); \
|
||||
GGPOPlatform::AssertFailed(assert_buf); \
|
||||
exit(0); \
|
||||
snprintf(assert_buf, sizeof(assert_buf) - 1, "Assertion: %s @ %s:%d", #x, __FILE__, __LINE__); \
|
||||
GGPOPlatform::AssertFailed(assert_buf); \
|
||||
throw GGPOException(assert_buf, GGPO_ERRORCODE_GENERAL_FAILURE); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define Log(...) DEBUG_LOG(NETWORK, __VA_ARGS__)
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
#endif
|
||||
|
||||
@@ -48,7 +48,7 @@ InputQueue::Init(int id, int input_size)
|
||||
int
|
||||
InputQueue::GetLastConfirmedFrame()
|
||||
{
|
||||
Log("returning last confirmed frame %d.\n", _last_added_frame);
|
||||
Log("input q%d | returning last confirmed frame %d.", _id, _last_added_frame);
|
||||
return _last_added_frame;
|
||||
}
|
||||
|
||||
@@ -67,21 +67,21 @@ InputQueue::DiscardConfirmedFrames(int frame)
|
||||
frame = MIN(frame, _last_frame_requested);
|
||||
}
|
||||
|
||||
Log("discarding confirmed frames up to %d (last_added:%d length:%d [head:%d tail:%d]).\n",
|
||||
Log("input q%d | discarding confirmed frames up to %d (last_added:%d length:%d [head:%d tail:%d]).", _id,
|
||||
frame, _last_added_frame, _length, _head, _tail);
|
||||
if (frame >= _last_added_frame) {
|
||||
_tail = _head;
|
||||
} else {
|
||||
int offset = frame - _inputs[_tail].frame + 1;
|
||||
|
||||
Log("difference of %d frames.\n", offset);
|
||||
Log("input q%d | difference of %d frames.", _id, offset);
|
||||
ASSERT(offset >= 0);
|
||||
|
||||
_tail = (_tail + offset) % INPUT_QUEUE_LENGTH;
|
||||
_length -= offset;
|
||||
}
|
||||
|
||||
Log("after discarding, new tail is %d (frame:%d).\n", _tail, _inputs[_tail].frame);
|
||||
Log("input q%d | after discarding, new tail is %d (frame:%d).", _id, _tail, _inputs[_tail].frame);
|
||||
ASSERT(_length >= 0);
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ InputQueue::ResetPrediction(int frame)
|
||||
{
|
||||
ASSERT(_first_incorrect_frame == GameInput::NullFrame || frame <= _first_incorrect_frame);
|
||||
|
||||
Log("resetting all prediction errors back to frame %d.\n", frame);
|
||||
Log("input q%d | resetting all prediction errors back to frame %d.", _id, frame);
|
||||
|
||||
/*
|
||||
* There's nothing really to do other than reset our prediction
|
||||
@@ -116,7 +116,7 @@ InputQueue::GetConfirmedInput(int requested_frame, GameInput *input)
|
||||
bool
|
||||
InputQueue::GetInput(int requested_frame, GameInput *input)
|
||||
{
|
||||
Log("requesting input frame %d.\n", requested_frame);
|
||||
Log("input q%d | requesting input frame %d.", _id, requested_frame);
|
||||
|
||||
/*
|
||||
* No one should ever try to grab any input when we have a prediction
|
||||
@@ -144,7 +144,7 @@ InputQueue::GetInput(int requested_frame, GameInput *input)
|
||||
offset = (offset + _tail) % INPUT_QUEUE_LENGTH;
|
||||
ASSERT(_inputs[offset].frame == requested_frame);
|
||||
*input = _inputs[offset];
|
||||
Log("returning confirmed frame number %d.\n", input->frame);
|
||||
Log("input q%d | returning confirmed frame number %d.", _id, input->frame);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -154,13 +154,13 @@ InputQueue::GetInput(int requested_frame, GameInput *input)
|
||||
* same thing they did last time.
|
||||
*/
|
||||
if (requested_frame == 0) {
|
||||
Log("basing new prediction frame from nothing, you're client wants frame 0.\n");
|
||||
Log("input q%d | basing new prediction frame from nothing, you're client wants frame 0.", _id);
|
||||
_prediction.erase();
|
||||
} else if (_last_added_frame == GameInput::NullFrame) {
|
||||
Log("basing new prediction frame from nothing, since we have no frames yet.\n");
|
||||
Log("input q%d | basing new prediction frame from nothing, since we have no frames yet.", _id);
|
||||
_prediction.erase();
|
||||
} else {
|
||||
Log("basing new prediction frame from previously added frame (queue entry:%d, frame:%d).\n",
|
||||
Log("input q%d | basing new prediction frame from previously added frame (queue entry:%d, frame:%d).", _id,
|
||||
PREVIOUS_FRAME(_head), _inputs[PREVIOUS_FRAME(_head)].frame);
|
||||
_prediction = _inputs[PREVIOUS_FRAME(_head)];
|
||||
}
|
||||
@@ -176,7 +176,7 @@ InputQueue::GetInput(int requested_frame, GameInput *input)
|
||||
*/
|
||||
*input = _prediction;
|
||||
input->frame = requested_frame;
|
||||
Log("returning prediction frame number %d (%d).\n", input->frame, _prediction.frame);
|
||||
Log("input q%d | returning prediction frame number %d (%d).", _id, input->frame, _prediction.frame);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -186,7 +186,7 @@ InputQueue::AddInput(GameInput &input)
|
||||
{
|
||||
int new_frame;
|
||||
|
||||
Log("adding input frame number %d to queue.\n", input.frame);
|
||||
Log("input q%d | adding input frame number %d to queue.", _id, input.frame);
|
||||
|
||||
/*
|
||||
* These next two lines simply verify that inputs are passed in
|
||||
@@ -216,7 +216,7 @@ InputQueue::AddInput(GameInput &input)
|
||||
void
|
||||
InputQueue::AddDelayedInputToQueue(GameInput &input, int frame_number)
|
||||
{
|
||||
Log("adding delayed input frame number %d to queue.\n", frame_number);
|
||||
Log("input q%d | adding delayed input frame number %d to queue.", _id, frame_number);
|
||||
|
||||
if (input.size != _prediction.size)
|
||||
throw GGPOException("Input size differs from peer", GGPO_ERRORCODE_INPUT_SIZE_DIFF);
|
||||
@@ -246,7 +246,7 @@ InputQueue::AddDelayedInputToQueue(GameInput &input, int frame_number)
|
||||
* in GetFirstIncorrectFrame()
|
||||
*/
|
||||
if (_first_incorrect_frame == GameInput::NullFrame && !_prediction.equal(input, true)) {
|
||||
Log("frame %d does not match prediction. marking error.\n", frame_number);
|
||||
Log("input q%d | frame %d does not match prediction. marking error.", _id, frame_number);
|
||||
_first_incorrect_frame = frame_number;
|
||||
}
|
||||
|
||||
@@ -257,7 +257,7 @@ InputQueue::AddDelayedInputToQueue(GameInput &input, int frame_number)
|
||||
* count up.
|
||||
*/
|
||||
if (_prediction.frame == _last_frame_requested && _first_incorrect_frame == GameInput::NullFrame) {
|
||||
Log("prediction is correct! dumping out of prediction mode.\n");
|
||||
Log("input q%d | prediction is correct! dumping out of prediction mode.", _id);
|
||||
_prediction.frame = GameInput::NullFrame;
|
||||
} else {
|
||||
_prediction.frame++;
|
||||
@@ -269,7 +269,7 @@ InputQueue::AddDelayedInputToQueue(GameInput &input, int frame_number)
|
||||
int
|
||||
InputQueue::AdvanceQueueHead(int frame)
|
||||
{
|
||||
Log("advancing queue head to frame %d.\n", frame);
|
||||
Log("input q%d | advancing queue head to frame %d.", _id, frame);
|
||||
|
||||
int expected_frame = _first_frame ? 0 : _inputs[PREVIOUS_FRAME(_head)].frame + 1;
|
||||
|
||||
@@ -281,7 +281,7 @@ InputQueue::AdvanceQueueHead(int frame)
|
||||
* time we shoved a frame into the system. In this case, there's
|
||||
* no room on the queue. Toss it.
|
||||
*/
|
||||
Log("Dropping input frame %d (expected next frame to be %d).\n",
|
||||
Log("input q%d | Dropping input frame %d (expected next frame to be %d).", _id,
|
||||
frame, expected_frame);
|
||||
return GameInput::NullFrame;
|
||||
}
|
||||
@@ -293,7 +293,7 @@ InputQueue::AdvanceQueueHead(int frame)
|
||||
* last frame in the queue several times in order to fill the space
|
||||
* left.
|
||||
*/
|
||||
Log("Adding padding frame %d to account for change in frame delay.\n",
|
||||
Log("input q%d | Adding padding frame %d to account for change in frame delay.", _id,
|
||||
expected_frame);
|
||||
GameInput &last_frame = _inputs[PREVIOUS_FRAME(_head)];
|
||||
AddDelayedInputToQueue(last_frame, expected_frame);
|
||||
@@ -303,19 +303,3 @@ InputQueue::AdvanceQueueHead(int frame)
|
||||
ASSERT(frame == 0 || frame == _inputs[PREVIOUS_FRAME(_head)].frame + 1);
|
||||
return frame;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InputQueue::Log(const char *fmt, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
size_t offset;
|
||||
va_list args;
|
||||
|
||||
offset = snprintf(buf, ARRAY_SIZE(buf), "input q%d | ", _id);
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf + offset, ARRAY_SIZE(buf) - offset - 1, fmt, args);
|
||||
buf[ARRAY_SIZE(buf)-1] = '\0';
|
||||
::Log(buf);
|
||||
va_end(args);
|
||||
}
|
||||
@@ -34,7 +34,6 @@ public:
|
||||
protected:
|
||||
int AdvanceQueueHead(int frame);
|
||||
void AddDelayedInputToQueue(GameInput &input, int i);
|
||||
void Log(const char *fmt, ...);
|
||||
|
||||
protected:
|
||||
int _id;
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "ggpo_types.h"
|
||||
#include "log/Log.h"
|
||||
#include "log/LogManager.h"
|
||||
#include <string>
|
||||
|
||||
void Log(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
Logv(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Logv(const char* fmt, va_list args)
|
||||
{
|
||||
std::string copy;
|
||||
if (fmt[strlen(fmt) - 1] == '\n') {
|
||||
copy = fmt;
|
||||
copy.pop_back();
|
||||
fmt = copy.c_str();
|
||||
}
|
||||
if (LogManager::GetInstance())
|
||||
LogManager::GetInstance()->Log(LogTypes::LDEBUG, LogTypes::NETWORK, __FILE__, __LINE__, fmt, args);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _LOG_H
|
||||
#define _LOG_H
|
||||
|
||||
extern void Log(const char *fmt, ...);
|
||||
extern void Logv(const char *fmt, va_list list);
|
||||
|
||||
#endif
|
||||
@@ -23,22 +23,6 @@ struct Init
|
||||
};
|
||||
static Init init;
|
||||
|
||||
void
|
||||
ggpo_log(GGPOSession *ggpo, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ggpo_logv(ggpo, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
ggpo_logv(GGPOSession *ggpo, const char *fmt, va_list args)
|
||||
{
|
||||
if (ggpo)
|
||||
ggpo->Logv(fmt, args);
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
ggpo_start_session(GGPOSession **session,
|
||||
GGPOSessionCallbacks *cb,
|
||||
@@ -59,7 +43,7 @@ ggpo_start_session(GGPOSession **session,
|
||||
verification_size);
|
||||
return GGPO_OK;
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_start_session: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_start_session: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -74,7 +58,7 @@ ggpo_add_player(GGPOSession *ggpo,
|
||||
try {
|
||||
return ggpo->AddPlayer(player, handle);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_add_player: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_add_player: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -93,7 +77,7 @@ ggpo_start_synctest(GGPOSession **ggpo,
|
||||
*ggpo = (GGPOSession *)new SyncTestBackend(cb, game, frames, num_players);
|
||||
return GGPO_OK;
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_start_synctest: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_start_synctest: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -108,7 +92,7 @@ ggpo_set_frame_delay(GGPOSession *ggpo,
|
||||
try {
|
||||
return ggpo->SetFrameDelay(player, frame_delay);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_set_frame_delay: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_set_frame_delay: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -121,7 +105,7 @@ ggpo_idle(GGPOSession *ggpo, int timeout)
|
||||
try {
|
||||
return ggpo->DoPoll(timeout);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_idle: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_idle: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -137,7 +121,7 @@ ggpo_add_local_input(GGPOSession *ggpo,
|
||||
try {
|
||||
return ggpo->AddLocalInput(player, values, size);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_add_local_input: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_add_local_input: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -153,7 +137,7 @@ ggpo_synchronize_input(GGPOSession *ggpo,
|
||||
try {
|
||||
return ggpo->SyncInput(values, size, disconnect_flags);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_synchronize_input: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_synchronize_input: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -166,7 +150,7 @@ GGPOErrorCode ggpo_disconnect_player(GGPOSession *ggpo,
|
||||
try {
|
||||
return ggpo->DisconnectPlayer(player);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_disconnect_player: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_disconnect_player: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -179,7 +163,7 @@ ggpo_advance_frame(GGPOSession *ggpo)
|
||||
try {
|
||||
return ggpo->IncrementFrame();
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_advance_frame: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_advance_frame: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -194,7 +178,7 @@ ggpo_get_network_stats(GGPOSession *ggpo,
|
||||
try {
|
||||
return ggpo->GetNetworkStats(stats, player);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_get_network_stats: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_get_network_stats: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -218,7 +202,7 @@ ggpo_set_disconnect_timeout(GGPOSession *ggpo, int timeout)
|
||||
try {
|
||||
return ggpo->SetDisconnectTimeout(timeout);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_set_disconnect_timeout: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_set_disconnect_timeout: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -231,7 +215,7 @@ ggpo_set_disconnect_notify_start(GGPOSession *ggpo, int timeout)
|
||||
try {
|
||||
return ggpo->SetDisconnectNotifyStart(timeout);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_set_disconnect_notify_start: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_set_disconnect_notify_start: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
@@ -259,7 +243,7 @@ GGPOErrorCode ggpo_start_spectating(GGPOSession **session,
|
||||
verification_size);
|
||||
return GGPO_OK;
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_start_spectating: %s", e.what());
|
||||
ERROR_LOG(NETWORK, "GGPOException in ggpo_start_spectating: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ CreateSocket(uint16 bind_port, int retries)
|
||||
for (port = bind_port; port <= bind_port + retries; port++) {
|
||||
sin.sin_port = htons(port);
|
||||
if (bind(s, (sockaddr *)&sin, sizeof sin) == 0) {
|
||||
Log("Udp bound to port: %d.\n", port);
|
||||
Log("Udp bound to port: %d.", port);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,7 @@ Udp::Init(uint16 port, Poll *poll, Callbacks *callbacks)
|
||||
_callbacks = callbacks;
|
||||
poll->RegisterLoop(this);
|
||||
|
||||
Log("binding udp socket to port %d.\n", port);
|
||||
Log("binding udp socket to port %d.", port);
|
||||
_socket = CreateSocket(port, 0);
|
||||
if (_socket == INVALID_SOCKET)
|
||||
throw GGPOException("Socket creation or bind failed", GGPO_ERRORCODE_NETWORK_ERROR);
|
||||
@@ -76,11 +76,11 @@ Udp::SendTo(char *buffer, int len, int flags, struct sockaddr *dst, int destlen)
|
||||
int res = sendto(_socket, buffer, len, flags, dst, destlen);
|
||||
if (res == SOCKET_ERROR) {
|
||||
int err = WSAGetLastError();
|
||||
Log("unknown error in sendto (erro: %d wsaerr: %d).\n", res, err);
|
||||
Log("unknown error in sendto (erro: %d wsaerr: %d).", res, err);
|
||||
ASSERT(false && "Unknown error in sendto");
|
||||
}
|
||||
char dst_ip[1024];
|
||||
Log("sent packet length %d to %s:%d (ret:%d).\n", len, inet_ntop(AF_INET, (void *)&to->sin_addr, dst_ip, ARRAY_SIZE(dst_ip)), ntohs(to->sin_port), res);
|
||||
Log("sent packet length %d to %s:%d (ret:%d).", len, inet_ntop(AF_INET, (void *)&to->sin_addr, dst_ip, ARRAY_SIZE(dst_ip)), ntohs(to->sin_port), res);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -99,32 +99,15 @@ Udp::OnLoopPoll(void *cookie)
|
||||
if (len == -1) {
|
||||
int error = WSAGetLastError();
|
||||
if (error != WSAEWOULDBLOCK) {
|
||||
Log("recvfrom WSAGetLastError returned %d (%x).\n", error, error);
|
||||
Log("recvfrom WSAGetLastError returned %d (%x).", error, error);
|
||||
}
|
||||
break;
|
||||
} else if (len > 0) {
|
||||
char src_ip[1024];
|
||||
Log("recvfrom returned (len:%d from:%s:%d).\n", len, inet_ntop(AF_INET, (void*)&recv_addr.sin_addr, src_ip, ARRAY_SIZE(src_ip)), ntohs(recv_addr.sin_port) );
|
||||
Log("recvfrom returned (len:%d from:%s:%d).", len, inet_ntop(AF_INET, (void*)&recv_addr.sin_addr, src_ip, ARRAY_SIZE(src_ip)), ntohs(recv_addr.sin_port) );
|
||||
UdpMsg *msg = (UdpMsg *)recv_buf;
|
||||
_callbacks->OnMsg(recv_addr, msg, len);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Udp::Log(const char *fmt, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
size_t offset;
|
||||
va_list args;
|
||||
|
||||
strcpy(buf, "udp | ");
|
||||
offset = strlen(buf);
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf + offset, ARRAY_SIZE(buf) - offset - 1, fmt, args);
|
||||
buf[ARRAY_SIZE(buf)-1] = '\0';
|
||||
::Log(buf);
|
||||
va_end(args);
|
||||
}
|
||||
@@ -31,11 +31,6 @@ public:
|
||||
virtual void OnMsg(sockaddr_in &from, UdpMsg *msg, int len) = 0;
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
void Log(const char *fmt, ...);
|
||||
|
||||
public:
|
||||
Udp();
|
||||
|
||||
void Init(uint16 port, Poll *p, Callbacks *callbacks);
|
||||
|
||||
@@ -197,7 +197,7 @@ UdpProtocol::OnLoopPoll(void *cookie)
|
||||
case Syncing:
|
||||
next_interval = (_state.sync.roundtrips_remaining == NUM_SYNC_PACKETS) ? SYNC_FIRST_RETRY_INTERVAL : SYNC_RETRY_INTERVAL;
|
||||
if (_last_send_time && _last_send_time + next_interval < now && _peer_addr.sin_addr.s_addr != 0) {
|
||||
Log("No luck syncing after %d ms... Re-queueing sync packet.\n", next_interval);
|
||||
Log("udpproto%d | No luck syncing after %d ms... Re-queueing sync packet.", _queue, next_interval);
|
||||
SendSyncRequest();
|
||||
}
|
||||
break;
|
||||
@@ -205,7 +205,7 @@ UdpProtocol::OnLoopPoll(void *cookie)
|
||||
case Running:
|
||||
// xxx: rig all this up with a timer wrapper
|
||||
if (!_state.running.last_input_packet_recv_time || _state.running.last_input_packet_recv_time + RUNNING_RETRY_INTERVAL < now) {
|
||||
Log("Haven't exchanged packets in a while (last received:%d last sent:%d). Resending.\n", _last_received_input.frame, _last_sent_input.frame);
|
||||
Log("udpproto%d | Haven't exchanged packets in a while (last received:%d last sent:%d). Resending.", _queue, _last_received_input.frame, _last_sent_input.frame);
|
||||
SendPendingOutput();
|
||||
_state.running.last_input_packet_recv_time = now;
|
||||
}
|
||||
@@ -224,13 +224,13 @@ UdpProtocol::OnLoopPoll(void *cookie)
|
||||
}
|
||||
|
||||
if (_last_send_time && _last_send_time + KEEP_ALIVE_INTERVAL < now) {
|
||||
Log("Sending keep alive packet\n");
|
||||
Log("udpproto%d | Sending keep alive packet", _queue);
|
||||
SendMsg(new UdpMsg(UdpMsg::KeepAlive));
|
||||
}
|
||||
|
||||
if (_disconnect_timeout && _disconnect_notify_start &&
|
||||
!_disconnect_notify_sent && (_last_recv_time + _disconnect_notify_start < now)) {
|
||||
Log("Endpoint has stopped receiving packets for %d ms. Sending notification.\n", _disconnect_notify_start);
|
||||
Log("udpproto%d | Endpoint has stopped receiving packets for %d ms. Sending notification.", _queue, _disconnect_notify_start);
|
||||
Event e(Event::NetworkInterrupted);
|
||||
e.u.network_interrupted.disconnect_timeout = _disconnect_timeout - _disconnect_notify_start;
|
||||
QueueEvent(e);
|
||||
@@ -239,7 +239,7 @@ UdpProtocol::OnLoopPoll(void *cookie)
|
||||
|
||||
if (_disconnect_timeout && (_last_recv_time + _disconnect_timeout < now)) {
|
||||
if (!_disconnect_event_sent) {
|
||||
Log("Endpoint has stopped receiving packets for %d ms. Disconnecting.\n", _disconnect_timeout);
|
||||
Log("udpproto%d | Endpoint has stopped receiving packets for %d ms. Disconnecting.", _queue, _disconnect_timeout);
|
||||
QueueEvent(Event(Event::Disconnected));
|
||||
_disconnect_event_sent = true;
|
||||
}
|
||||
@@ -248,7 +248,7 @@ UdpProtocol::OnLoopPoll(void *cookie)
|
||||
|
||||
case Disconnected:
|
||||
if (_shutdown_timeout < now) {
|
||||
Log("Shutting down udp connection.\n");
|
||||
Log("udpproto%d | Shutting down udp connection.", _queue);
|
||||
_udp = NULL;
|
||||
_shutdown_timeout = 0;
|
||||
}
|
||||
@@ -345,9 +345,9 @@ UdpProtocol::OnMsg(UdpMsg *msg, int len)
|
||||
|
||||
// filter out out-of-order packets
|
||||
uint16 skipped = (uint16)((int)seq - (int)_next_recv_seq);
|
||||
// Log("checking sequence number -> next - seq : %d - %d = %d\n", seq, _next_recv_seq, skipped);
|
||||
// Log("udpproto%d | checking sequence number -> next - seq : %d - %d = %d", _queue, seq, _next_recv_seq, skipped);
|
||||
if (skipped > MAX_SEQ_DISTANCE) {
|
||||
Log("dropping out of order packet (seq: %d, last seq:%d)\n", seq, _next_recv_seq);
|
||||
Log("udpproto%d | dropping out of order packet (seq: %d, last seq:%d)", _queue, seq, _next_recv_seq);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -384,9 +384,9 @@ UdpProtocol::UpdateNetworkStats(void)
|
||||
|
||||
_kbps_sent = int(Bps / 1024);
|
||||
|
||||
Log("Network Stats -- Bandwidth: %.2f KBps Packets Sent: %5d (%.2f pps) "
|
||||
"KB Sent: %.2f UDP Overhead: %.2f %%.\n",
|
||||
_kbps_sent,
|
||||
Log("udpproto%d | Network Stats -- Bandwidth: %.2f KBps Packets Sent: %5d (%.2f pps) "
|
||||
"KB Sent: %.2f UDP Overhead: %.2f %%.", _queue,
|
||||
(float)_kbps_sent,
|
||||
_packets_sent,
|
||||
(float)_packets_sent * 1000 / (now - _stats_start_time),
|
||||
total_bytes_sent / 1024.0,
|
||||
@@ -419,51 +419,35 @@ UdpProtocol::GetPeerConnectStatus(int id, int *frame)
|
||||
return !_peer_connect_status[id].disconnected;
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::Log(const char *fmt, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
size_t offset;
|
||||
va_list args;
|
||||
|
||||
snprintf(buf, ARRAY_SIZE(buf), "udpproto%d | ", _queue);
|
||||
offset = strlen(buf);
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf + offset, ARRAY_SIZE(buf) - offset - 1, fmt, args);
|
||||
buf[ARRAY_SIZE(buf)-1] = '\0';
|
||||
::Log(buf);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::LogMsg(const char *prefix, UdpMsg *msg)
|
||||
{
|
||||
switch (msg->hdr.type) {
|
||||
case UdpMsg::SyncRequest:
|
||||
Log("%s sync-request (%d).\n", prefix,
|
||||
Log("udpproto%d | %s sync-request (%d).", _queue, prefix,
|
||||
msg->u.sync_request.random_request);
|
||||
break;
|
||||
case UdpMsg::SyncReply:
|
||||
Log("%s sync-reply (%d).\n", prefix,
|
||||
Log("udpproto%d | %s sync-reply (%d).", _queue, prefix,
|
||||
msg->u.sync_reply.random_reply);
|
||||
break;
|
||||
case UdpMsg::QualityReport:
|
||||
Log("%s quality report.\n", prefix);
|
||||
Log("udpproto%d | %s quality report.", _queue, prefix);
|
||||
break;
|
||||
case UdpMsg::QualityReply:
|
||||
Log("%s quality reply.\n", prefix);
|
||||
Log("udpproto%d | %s quality reply.", _queue, prefix);
|
||||
break;
|
||||
case UdpMsg::KeepAlive:
|
||||
Log("%s keep alive.\n", prefix);
|
||||
Log("udpproto%d | %s keep alive.", _queue, prefix);
|
||||
break;
|
||||
case UdpMsg::Input:
|
||||
Log("%s game-compressed-input %d (+ %d bits).\n", prefix, msg->u.input.start_frame, msg->u.input.num_bits);
|
||||
Log("udpproto%d | %s game-compressed-input %d (+ %d bits).", _queue, prefix, msg->u.input.start_frame, msg->u.input.num_bits);
|
||||
break;
|
||||
case UdpMsg::InputAck:
|
||||
Log("%s input ack.\n", prefix);
|
||||
Log("udpproto%d | %s input ack.", _queue, prefix);
|
||||
break;
|
||||
case UdpMsg::AppData:
|
||||
Log("%s app data (%d bytes).\n", prefix, msg->u.app_data.size);
|
||||
Log("udpproto%d | %s app data (%d bytes).", _queue, prefix, msg->u.app_data.size);
|
||||
break;
|
||||
default:
|
||||
ASSERT(false && "Unknown UdpMsg type.");
|
||||
@@ -474,7 +458,7 @@ void
|
||||
UdpProtocol::LogEvent(const char *prefix, const UdpProtocol::Event &evt)
|
||||
{
|
||||
if (evt.type == UdpProtocol::Event::Synchronzied)
|
||||
Log("%s (event: Synchronzied).\n", prefix);
|
||||
Log("udpproto%d | %s (event: Synchronized).", _queue, prefix);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -488,7 +472,7 @@ bool
|
||||
UdpProtocol::OnSyncRequest(UdpMsg *msg, int len)
|
||||
{
|
||||
if (_remote_magic_number != 0 && msg->hdr.magic != _remote_magic_number) {
|
||||
Log("Ignoring sync request from unknown endpoint (%d != %d).\n",
|
||||
Log("udpproto%d | Ignoring sync request from unknown endpoint (%d != %d).", _queue,
|
||||
msg->hdr.magic, _remote_magic_number);
|
||||
return false;
|
||||
}
|
||||
@@ -500,14 +484,14 @@ UdpProtocol::OnSyncRequest(UdpMsg *msg, int len)
|
||||
if (msgVerifSize != (int)verification.size()
|
||||
|| (msgVerifSize != 0 && memcmp(&msg->u.sync_request.verification[0], &verification[0], msgVerifSize)))
|
||||
{
|
||||
Log("Verification mismatch: size received %d expected %d", msgVerifSize, (int)verification.size());
|
||||
Log("udpproto%d | Verification mismatch: size received %d expected %d", _queue, msgVerifSize, (int)verification.size());
|
||||
reply->u.sync_reply.verification_failure = 1;
|
||||
SendMsg(reply);
|
||||
throw GGPOException("Verification mismatch", GGPO_ERRORCODE_VERIFICATION_ERROR);
|
||||
}
|
||||
// FIXME
|
||||
if (_state.sync.roundtrips_remaining == NUM_SYNC_PACKETS && msg->hdr.sequence_number == 0) {
|
||||
Log("Sync request 0 received... Re-queueing sync packet.\n");
|
||||
Log("udpproto%d | Sync request 0 received... Re-queueing sync packet.", _queue);
|
||||
SendSyncRequest();
|
||||
}
|
||||
|
||||
@@ -521,12 +505,12 @@ bool
|
||||
UdpProtocol::OnSyncReply(UdpMsg *msg, int len)
|
||||
{
|
||||
if (_current_state != Syncing) {
|
||||
Log("Ignoring SyncReply while not synching.\n");
|
||||
Log("udpproto%d | Ignoring SyncReply while not synching.", _queue);
|
||||
return msg->hdr.magic == _remote_magic_number;
|
||||
}
|
||||
|
||||
if (msg->u.sync_reply.random_reply != _state.sync.random) {
|
||||
Log("sync reply %d != %d. Keep looking...\n",
|
||||
Log("udpproto%d | sync reply %d != %d. Keep looking...", _queue,
|
||||
msg->u.sync_reply.random_reply, _state.sync.random);
|
||||
return false;
|
||||
}
|
||||
@@ -538,9 +522,9 @@ UdpProtocol::OnSyncReply(UdpMsg *msg, int len)
|
||||
_connected = true;
|
||||
}
|
||||
|
||||
Log("Checking sync state (%d round trips remaining).\n", _state.sync.roundtrips_remaining);
|
||||
Log("udpproto%d | Checking sync state (%d round trips remaining).", _queue, _state.sync.roundtrips_remaining);
|
||||
if (--_state.sync.roundtrips_remaining == 0) {
|
||||
Log("Synchronized!\n");
|
||||
Log("udpproto%d | Synchronized!", _queue);
|
||||
QueueEvent(UdpProtocol::Event(UdpProtocol::Event::Synchronzied));
|
||||
_current_state = Running;
|
||||
_last_received_input.frame = -1;
|
||||
@@ -564,7 +548,7 @@ UdpProtocol::OnInput(UdpMsg *msg, int len)
|
||||
bool disconnect_requested = msg->u.input.disconnect_requested;
|
||||
if (disconnect_requested) {
|
||||
if (_current_state != Disconnected && !_disconnect_event_sent) {
|
||||
Log("Disconnecting endpoint on remote request.\n");
|
||||
Log("udpproto%d | Disconnecting endpoint on remote request.", _queue);
|
||||
QueueEvent(Event(Event::Disconnected));
|
||||
_disconnect_event_sent = true;
|
||||
}
|
||||
@@ -629,20 +613,21 @@ UdpProtocol::OnInput(UdpMsg *msg, int len)
|
||||
_last_received_input.frame = currentFrame;
|
||||
|
||||
/*
|
||||
* Send the event to the emualtor
|
||||
* Send the event to the emulator
|
||||
*/
|
||||
UdpProtocol::Event evt(UdpProtocol::Event::Input);
|
||||
evt.u.input.input = _last_received_input;
|
||||
|
||||
_last_received_input.desc(desc, ARRAY_SIZE(desc));
|
||||
if (LogTypes::LDEBUG <= MAX_LOGLEVEL)
|
||||
_last_received_input.desc(desc, ARRAY_SIZE(desc));
|
||||
|
||||
_state.running.last_input_packet_recv_time = GGPOPlatform::GetCurrentTimeMS();
|
||||
|
||||
Log("Sending frame %d to emu queue %d (%s).\n", _last_received_input.frame, _queue, desc);
|
||||
Log("udpproto%d | Sending frame %d to emu queue %d (%s).", _queue, _last_received_input.frame, _queue, desc);
|
||||
QueueEvent(evt);
|
||||
|
||||
} else {
|
||||
Log("Skipping past frame:(%d) current is %d.\n", currentFrame, _last_received_input.frame);
|
||||
Log("udpproto%d | Skipping past frame:(%d) current is %d.", _queue, currentFrame, _last_received_input.frame);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -657,7 +642,7 @@ UdpProtocol::OnInput(UdpMsg *msg, int len)
|
||||
* Get rid of our buffered input
|
||||
*/
|
||||
while (_pending_output.size() && _pending_output.front().frame < msg->u.input.ack_frame) {
|
||||
Log("Throwing away pending output frame %d\n", _pending_output.front().frame);
|
||||
Log("udpproto%d | Throwing away pending output frame %d", _queue, _pending_output.front().frame);
|
||||
_last_acked_input = _pending_output.front();
|
||||
_pending_output.pop();
|
||||
}
|
||||
@@ -672,7 +657,7 @@ UdpProtocol::OnInputAck(UdpMsg *msg, int len)
|
||||
* Get rid of our buffered input
|
||||
*/
|
||||
while (_pending_output.size() && _pending_output.front().frame < msg->u.input_ack.ack_frame) {
|
||||
Log("Throwing away pending output frame %d\n", _pending_output.front().frame);
|
||||
Log("udpproto%d | Throwing away pending output frame %d", _queue, _pending_output.front().frame);
|
||||
_last_acked_input = _pending_output.front();
|
||||
_pending_output.pop();
|
||||
}
|
||||
@@ -770,7 +755,7 @@ UdpProtocol::PumpSendQueue()
|
||||
}
|
||||
if (_oop_percent && !_oo_packet.msg && ((rand() % 100) < _oop_percent)) {
|
||||
int delay = rand() % (_send_latency * 10 + 1000);
|
||||
Log("creating rogue oop (seq: %d delay: %d)\n", entry.msg->hdr.sequence_number, delay);
|
||||
Log("udpproto%d | creating rogue oop (seq: %d delay: %d)", _queue, entry.msg->hdr.sequence_number, delay);
|
||||
_oo_packet.send_time = GGPOPlatform::GetCurrentTimeMS() + delay;
|
||||
_oo_packet.msg = entry.msg;
|
||||
_oo_packet.dest_addr = entry.dest_addr;
|
||||
@@ -785,7 +770,7 @@ UdpProtocol::PumpSendQueue()
|
||||
_send_queue.pop();
|
||||
}
|
||||
if (_oo_packet.msg && _oo_packet.send_time < (int)GGPOPlatform::GetCurrentTimeMS()) {
|
||||
Log("sending rogue oop!");
|
||||
Log("udpproto%d | sending rogue oop!", _queue);
|
||||
_udp->SendTo((char *)_oo_packet.msg, _oo_packet.msg->PacketSize(), 0,
|
||||
(struct sockaddr *)&_oo_packet.dest_addr, sizeof _oo_packet.dest_addr);
|
||||
|
||||
|
||||
@@ -119,7 +119,6 @@ protected:
|
||||
void UpdateNetworkStats(void);
|
||||
void QueueEvent(const UdpProtocol::Event &evt);
|
||||
void ClearSendQueue(void);
|
||||
void Log(const char *fmt, ...);
|
||||
void LogMsg(const char *prefix, UdpMsg *msg);
|
||||
void LogEvent(const char *prefix, const UdpProtocol::Event &evt);
|
||||
void SendSyncRequest();
|
||||
|
||||
@@ -59,7 +59,7 @@ Sync::AddLocalInput(int queue, GameInput &input)
|
||||
{
|
||||
int frames_behind = _framecount - _last_confirmed_frame;
|
||||
if (_framecount >= _max_prediction_frames && frames_behind >= _max_prediction_frames) {
|
||||
Log("Rejecting input from emulator: reached prediction barrier.\n");
|
||||
Log("Rejecting input from emulator: reached prediction barrier.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ Sync::AddLocalInput(int queue, GameInput &input)
|
||||
SaveCurrentFrame();
|
||||
}
|
||||
|
||||
Log("Sending undelayed local frame %d to queue %d.\n", _framecount, queue);
|
||||
Log("Sending undelayed local frame %d to queue %d.", _framecount, queue);
|
||||
input.frame = _framecount;
|
||||
_input_queues[queue].AddInput(input);
|
||||
|
||||
@@ -146,7 +146,7 @@ Sync::AdjustSimulation(int seek_to)
|
||||
int framecount = _framecount;
|
||||
int count = _framecount - seek_to;
|
||||
|
||||
Log("Catching up\n");
|
||||
Log("Catching up");
|
||||
_rollingback = true;
|
||||
|
||||
/*
|
||||
@@ -167,7 +167,7 @@ Sync::AdjustSimulation(int seek_to)
|
||||
|
||||
_rollingback = false;
|
||||
|
||||
Log("---\n");
|
||||
Log("---");
|
||||
}
|
||||
|
||||
void
|
||||
@@ -175,7 +175,7 @@ Sync::LoadFrame(int frame)
|
||||
{
|
||||
// find the frame in question
|
||||
if (frame == _framecount) {
|
||||
Log("Skipping NOP.\n");
|
||||
Log("Skipping NOP.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ Sync::LoadFrame(int frame)
|
||||
_savedstate.head = FindSavedFrameIndex(frame);
|
||||
SavedFrame *state = _savedstate.frames + _savedstate.head;
|
||||
|
||||
Log("=== Loading frame info %d (size: %d checksum: %08x).\n",
|
||||
Log("=== Loading frame info %d (size: %d checksum: %08x).",
|
||||
state->frame, state->cbuf, state->checksum);
|
||||
|
||||
ASSERT(state->buf && state->cbuf);
|
||||
@@ -210,7 +210,7 @@ Sync::SaveCurrentFrame()
|
||||
state->frame = _framecount;
|
||||
_callbacks.save_game_state(&state->buf, &state->cbuf, &state->checksum, state->frame);
|
||||
|
||||
Log("=== Saved frame info %d (size: %d checksum: %08x).\n", state->frame, state->cbuf, state->checksum);
|
||||
Log("=== Saved frame info %d (size: %d checksum: %08x).", state->frame, state->cbuf, state->checksum);
|
||||
_savedstate.head = (_savedstate.head + 1) % ARRAY_SIZE(_savedstate.frames);
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ Sync::CheckSimulationConsistency(int *seekTo)
|
||||
int first_incorrect = GameInput::NullFrame;
|
||||
for (int i = 0; i < _config.num_players; i++) {
|
||||
int incorrect = _input_queues[i].GetFirstIncorrectFrame();
|
||||
Log("considering incorrect frame %d reported by queue %d.\n", incorrect, i);
|
||||
Log("considering incorrect frame %d reported by queue %d.", incorrect, i);
|
||||
|
||||
if (incorrect != GameInput::NullFrame && (first_incorrect == GameInput::NullFrame || incorrect < first_incorrect)) {
|
||||
first_incorrect = incorrect;
|
||||
@@ -267,7 +267,7 @@ Sync::CheckSimulationConsistency(int *seekTo)
|
||||
}
|
||||
|
||||
if (first_incorrect == GameInput::NullFrame) {
|
||||
Log("prediction ok. proceeding.\n");
|
||||
Log("prediction ok. proceeding.");
|
||||
return true;
|
||||
}
|
||||
*seekTo = first_incorrect;
|
||||
|
||||
@@ -59,7 +59,7 @@ TimeSync::recommend_frame_wait_duration(bool require_idle_input)
|
||||
// sleep for.
|
||||
int sleep_frames = (int)(((radvantage - advantage) / 2) + 0.5);
|
||||
|
||||
Log("iteration %d: sleep frames is %d\n", count, sleep_frames);
|
||||
Log("iteration %d: sleep frames is %d", count, sleep_frames);
|
||||
|
||||
// Some things just aren't worth correcting for. Make sure
|
||||
// the difference is relevant before proceeding.
|
||||
@@ -74,7 +74,7 @@ TimeSync::recommend_frame_wait_duration(bool require_idle_input)
|
||||
if (require_idle_input) {
|
||||
for (size_t i = 1; i < ARRAY_SIZE(_last_inputs); i++) {
|
||||
if (!_last_inputs[i].equal(_last_inputs[0], true)) {
|
||||
Log("iteration %d: rejecting due to input stuff at position %d...!!!\n", count, i);
|
||||
Log("iteration %d: rejecting due to input stuff at position %d...!!!", count, (int)i);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Submodule
+1
Submodule core/deps/glslang added at 10423ec659.
@@ -1,108 +0,0 @@
|
||||
# Windows Build Configuration for AppVeyor
|
||||
# http://www.appveyor.com/docs/appveyor-yml
|
||||
|
||||
# build version format
|
||||
version: "{build}"
|
||||
|
||||
os: Visual Studio 2013
|
||||
|
||||
platform:
|
||||
- x64
|
||||
|
||||
configuration:
|
||||
- Debug
|
||||
- Release
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
# changes to these files don't need to trigger testing
|
||||
skip_commits:
|
||||
files:
|
||||
- README.md
|
||||
- README-spirv-remap.txt
|
||||
- LICENSE.txt
|
||||
- CODE_OF_CONDUCT.md
|
||||
- BUILD.*
|
||||
- WORKSPACE
|
||||
- kokoro/*
|
||||
- make-revision
|
||||
- Android.mk
|
||||
- _config.yml
|
||||
|
||||
# Travis advances the master-tot tag to current top of the tree after
|
||||
# each push into the master branch, because it relies on that tag to
|
||||
# upload build artifacts to the master-tot release. This will cause
|
||||
# double testing for each push on Appveyor: one for the push, one for
|
||||
# the tag advance. Disable testing tags.
|
||||
skip_tags: true
|
||||
|
||||
clone_depth: 5
|
||||
|
||||
matrix:
|
||||
fast_finish: true # Show final status immediately if a test fails.
|
||||
|
||||
# scripts that run after cloning repository
|
||||
install:
|
||||
- C:/Python27/python.exe update_glslang_sources.py
|
||||
- set PATH=C:\ninja;C:\Python36;%PATH%
|
||||
- git clone https://github.com/google/googletest.git External/googletest
|
||||
- cd External/googletest
|
||||
- git checkout 440527a61e1c91188195f7de212c63c77e8f0a45
|
||||
- cd ../..
|
||||
|
||||
build:
|
||||
parallel: true # enable MSBuild parallel builds
|
||||
verbosity: minimal
|
||||
|
||||
build_script:
|
||||
- mkdir build && cd build
|
||||
- cmake -G "Visual Studio 12 2013 Win64" -DCMAKE_INSTALL_PREFIX=install ..
|
||||
- cmake --build . --config %CONFIGURATION% --target install
|
||||
|
||||
test_script:
|
||||
- ctest -C %CONFIGURATION% --output-on-failure
|
||||
- cd ../Test && bash runtests
|
||||
- cd ../build
|
||||
|
||||
after_test:
|
||||
# For debug build, the generated dll has a postfix "d" in its name.
|
||||
- ps: >-
|
||||
If ($env:configuration -Match "Debug") {
|
||||
$env:SUFFIX="d"
|
||||
} Else {
|
||||
$env:SUFFIX=""
|
||||
}
|
||||
- cd install
|
||||
# Zip all glslang artifacts for uploading and deploying
|
||||
- 7z a glslang-master-windows-"%PLATFORM%"-"%CONFIGURATION%".zip
|
||||
bin\glslangValidator.exe
|
||||
bin\spirv-remap.exe
|
||||
include\glslang\*
|
||||
lib\glslang%SUFFIX%.lib
|
||||
lib\HLSL%SUFFIX%.lib
|
||||
lib\OGLCompiler%SUFFIX%.lib
|
||||
lib\OSDependent%SUFFIX%.lib
|
||||
lib\SPIRV%SUFFIX%.lib
|
||||
lib\SPVRemapper%SUFFIX%.lib
|
||||
lib\SPIRV-Tools%SUFFIX%.lib
|
||||
lib\SPIRV-Tools-opt%SUFFIX%.lib
|
||||
|
||||
artifacts:
|
||||
- path: build\install\*.zip
|
||||
name: artifacts-zip
|
||||
|
||||
deploy:
|
||||
- provider: GitHub
|
||||
auth_token:
|
||||
secure: YglcSYdl0TylEa59H4K6lylBEDr586NAt2EMgZquSo+iuPrwgZQuJLPCoihSm9y6
|
||||
release: master-tot
|
||||
description: "Continuous build of the latest master branch by Appveyor and Travis CI"
|
||||
artifact: artifacts-zip
|
||||
draft: false
|
||||
prerelease: false
|
||||
force_update: true
|
||||
on:
|
||||
branch: master
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
|
||||
@@ -1,13 +0,0 @@
|
||||
Language: Cpp
|
||||
IndentWidth: 4
|
||||
PointerAlignment: Left
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping: { AfterFunction: true, AfterControlStatement: false }
|
||||
IndentCaseLabels: false
|
||||
ReflowComments: false
|
||||
ColumnLimit: 120
|
||||
AccessModifierOffset: -4
|
||||
AlignTrailingComments: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
@@ -1,17 +0,0 @@
|
||||
# test files have a mix of lf/crlf, and that's a good thing, for testing, don't mess with it
|
||||
# bash scripts need lines ending with lf, and that's correct for Windows too, e.g., under Cygwin
|
||||
# (scripts often don't have a suffix)
|
||||
* -text
|
||||
*.sh text eof=lf
|
||||
|
||||
# txt files should be native and normalized
|
||||
*.txt text
|
||||
|
||||
# source code can be native and normalized, but simpler if lf everywhere; will try that way
|
||||
*.h text eol=lf
|
||||
*.c text eol=lf
|
||||
*.cpp text eol=lf
|
||||
*.y text eol=lf
|
||||
*.out text eol=lf
|
||||
*.conf text eol=lf
|
||||
*.err text eol=lf
|
||||
@@ -1,10 +0,0 @@
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
*.exe
|
||||
tags
|
||||
TAGS
|
||||
build/
|
||||
Test/localResults/
|
||||
External/googletest
|
||||
External/spirv-tools
|
||||
@@ -1,128 +0,0 @@
|
||||
# Linux and Mac Build Configuration for Travis
|
||||
|
||||
language: cpp
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
# Use Ubuntu 14.04 LTS (Trusty) as the Linux testing environment.
|
||||
sudo: false
|
||||
dist: trusty
|
||||
|
||||
env:
|
||||
global:
|
||||
- secure: aGFrgzyKp+84hKrGkxVWg8cHV61uqrKEHT38gfSQK6+WS4GfLOyH83p7WnsEBb7AMhzU7LMNFdvOFr6+NaMpVnqRvc40CEG1Q+lNg9Pq9mhIZLowvDrfqTL9kQ+8Nbw5Q6/dg6CTvY7fvRfpfCEmKIUZBRkoKUuHeuM1uy3IupFcdNuL5bSYn3Beo+apSJginh9DI4BLDXFUgBzTRSLLyCX5g3cpaeGGOCr8quJlYx75W6HRck5g9SZuLtUoH9GFEV3l+ZEWB8noErW+J56L03bwNwFuuAh321evw++oQk5KFa8rlDvar3SJ3b1RHB8u/eq5DBYMyaK/fS8+Q7QbGr8diF/wDe68bKO7U9IhpNfExXmczCpExjHomW5TQv4rYdGhygPMfW97aIsPRYyNKcl4fkmb7NDrM8w0Jscdq2g5c2Kz0ItyZoBri/NXLwFQQjaVCs7Pf97TjuMA7mK0GJmDTRzi6SrDYlWMt5BQL3y0CCojyfLIRcTh0CQjQI29s97bLfQrYAxt9GNNFR+HTXRLLrkaAlJkPGEPwUywlSfEThnvHLesNxYqemolAYpQT4ithoL4GehGIHmaxsW295aKVhuRf8K9eBODNqrfblvM42UHhjntT+92ZnQ/Gkq80GqaMxnxi4PO5FyPIxt0r981b54YBkWi8YA4P7w5pNI=
|
||||
matrix:
|
||||
- GLSLANG_BUILD_TYPE=Release
|
||||
- GLSLANG_BUILD_TYPE=Debug
|
||||
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
|
||||
matrix:
|
||||
fast_finish: true # Show final status immediately if a test fails.
|
||||
exclude:
|
||||
# Skip GCC builds on Mac OS X.
|
||||
- os: osx
|
||||
compiler: gcc
|
||||
include:
|
||||
# Additional build using Android NDK.
|
||||
- env: BUILD_NDK=ON
|
||||
|
||||
cache:
|
||||
apt: true
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.6
|
||||
|
||||
install:
|
||||
# Make sure that clang-3.6 is selected on Linux.
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" && "$CC" == "clang" ]]; then
|
||||
export CC=clang-3.6 CXX=clang++-3.6;
|
||||
fi
|
||||
# Download a recent Android NDK and use its android.toolchain.cmake file.
|
||||
- if [[ "$BUILD_NDK" == "ON" ]]; then
|
||||
export ANDROID_NDK=$HOME/android-ndk;
|
||||
git init $ANDROID_NDK;
|
||||
pushd $ANDROID_NDK;
|
||||
git remote add dneto0 https://github.com/dneto0/android-ndk.git;
|
||||
git fetch --depth=1 dneto0 r17b-strip;
|
||||
git checkout FETCH_HEAD;
|
||||
popd;
|
||||
export TOOLCHAIN_PATH=$ANDROID_NDK/build/cmake/android.toolchain.cmake;
|
||||
fi
|
||||
|
||||
before_script:
|
||||
- git clone --depth=1 https://github.com/google/googletest.git External/googletest
|
||||
- ./update_glslang_sources.py
|
||||
|
||||
script:
|
||||
- mkdir build && cd build
|
||||
# For Android, do release building using NDK without testing.
|
||||
# Use android-14, the oldest native API level supporeted by NDK r17b.
|
||||
# We can use newer API levels if we want.
|
||||
# For Linux and macOS, do debug/release building with testing.
|
||||
- if [[ "$BUILD_NDK" == "ON" ]]; then
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_PATH}
|
||||
-DANDROID_NATIVE_API_LEVEL=android-14
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DANDROID_ABI="armeabi-v7a with NEON"
|
||||
-DBUILD_TESTING=OFF ..;
|
||||
make -j4;
|
||||
else
|
||||
cmake -DCMAKE_BUILD_TYPE=${GLSLANG_BUILD_TYPE}
|
||||
-DCMAKE_INSTALL_PREFIX=`pwd`/install ..;
|
||||
make -j4 install;
|
||||
ctest --output-on-failure &&
|
||||
cd ../Test && ./runtests;
|
||||
fi
|
||||
|
||||
after_success:
|
||||
# For debug build, the generated dll has a postfix "d" in its name.
|
||||
- if [[ "${GLSLANG_BUILD_TYPE}" == "Debug" ]]; then
|
||||
export SUFFIX="d";
|
||||
else
|
||||
export SUFFIX="";
|
||||
fi
|
||||
# Create tarball for deployment
|
||||
- if [[ ${CC} == clang* && "${BUILD_NDK}" != "ON" ]]; then
|
||||
cd ../build/install;
|
||||
export TARBALL=glslang-master-${TRAVIS_OS_NAME}-${GLSLANG_BUILD_TYPE}.zip;
|
||||
zip ${TARBALL}
|
||||
bin/glslangValidator
|
||||
include/glslang/*
|
||||
lib/libglslang${SUFFIX}.a
|
||||
lib/libHLSL${SUFFIX}.a
|
||||
lib/libOGLCompiler${SUFFIX}.a
|
||||
lib/libOSDependent${SUFFIX}.a
|
||||
lib/libSPIRV${SUFFIX}.a
|
||||
lib/libSPVRemapper${SUFFIX}.a
|
||||
lib/libSPIRV-Tools${SUFFIX}.a
|
||||
lib/libSPIRV-Tools-opt${SUFFIX}.a;
|
||||
fi
|
||||
|
||||
before_deploy:
|
||||
# Tag the current top of the tree as "master-tot".
|
||||
# Travis CI replies on the tag name to properly push to GitHub Releases.
|
||||
- git config --global user.name "Travis CI"
|
||||
- git config --global user.email "[email protected]"
|
||||
- git tag -f master-tot
|
||||
- git push -q -f https://${glslangtoken}@github.com/KhronosGroup/glslang --tags
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key: ${glslangtoken}
|
||||
on:
|
||||
branch: master
|
||||
condition: ${CC} == clang* && ${BUILD_NDK} != ON
|
||||
file: ${TARBALL}
|
||||
skip_cleanup: true
|
||||
overwrite: true
|
||||
@@ -1,100 +0,0 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
GLSLANG_OS_FLAGS := -DGLSLANG_OSINCLUDE_UNIX
|
||||
# AMD and NV extensions are turned on by default in upstream Glslang.
|
||||
GLSLANG_DEFINES:= -DAMD_EXTENSIONS -DNV_EXTENSIONS -DENABLE_HLSL $(GLSLANG_OS_FLAGS)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:=OSDependent
|
||||
LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti $(GLSLANG_DEFINES)
|
||||
LOCAL_EXPORT_C_INCLUDES:=$(LOCAL_PATH)
|
||||
LOCAL_SRC_FILES:=glslang/OSDependent/Unix/ossource.cpp
|
||||
LOCAL_C_INCLUDES:=$(LOCAL_PATH) $(LOCAL_PATH)/glslang/OSDependent/Unix/
|
||||
LOCAL_EXPORT_C_INCLUDES:=$(LOCAL_PATH)/glslang/OSDependent/Unix/
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:=OGLCompiler
|
||||
LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti $(GLSLANG_DEFINES)
|
||||
LOCAL_EXPORT_C_INCLUDES:=$(LOCAL_PATH)
|
||||
LOCAL_SRC_FILES:=OGLCompilersDLL/InitializeDll.cpp
|
||||
LOCAL_C_INCLUDES:=$(LOCAL_PATH)/OGLCompiler
|
||||
LOCAL_STATIC_LIBRARIES:=OSDependent
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# Build Glslang's HLSL parser library.
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:=HLSL
|
||||
LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti $(GLSLANG_DEFINES)
|
||||
LOCAL_SRC_FILES:= \
|
||||
hlsl/hlslAttributes.cpp \
|
||||
hlsl/hlslGrammar.cpp \
|
||||
hlsl/hlslOpMap.cpp \
|
||||
hlsl/hlslParseables.cpp \
|
||||
hlsl/hlslParseHelper.cpp \
|
||||
hlsl/hlslScanContext.cpp \
|
||||
hlsl/hlslTokenStream.cpp
|
||||
LOCAL_C_INCLUDES:=$(LOCAL_PATH) \
|
||||
$(LOCAL_PATH)/hlsl
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
GLSLANG_OUT_PATH=$(if $(call host-path-is-absolute,$(TARGET_OUT)),$(TARGET_OUT),$(abspath $(TARGET_OUT)))
|
||||
|
||||
LOCAL_MODULE:=glslang
|
||||
LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti $(GLSLANG_DEFINES)
|
||||
LOCAL_EXPORT_C_INCLUDES:=$(LOCAL_PATH)
|
||||
LOCAL_SRC_FILES:= \
|
||||
glslang/GenericCodeGen/CodeGen.cpp \
|
||||
glslang/GenericCodeGen/Link.cpp \
|
||||
glslang/MachineIndependent/attribute.cpp \
|
||||
glslang/MachineIndependent/Constant.cpp \
|
||||
glslang/MachineIndependent/glslang_tab.cpp \
|
||||
glslang/MachineIndependent/InfoSink.cpp \
|
||||
glslang/MachineIndependent/Initialize.cpp \
|
||||
glslang/MachineIndependent/Intermediate.cpp \
|
||||
glslang/MachineIndependent/intermOut.cpp \
|
||||
glslang/MachineIndependent/IntermTraverse.cpp \
|
||||
glslang/MachineIndependent/iomapper.cpp \
|
||||
glslang/MachineIndependent/limits.cpp \
|
||||
glslang/MachineIndependent/linkValidate.cpp \
|
||||
glslang/MachineIndependent/parseConst.cpp \
|
||||
glslang/MachineIndependent/ParseContextBase.cpp \
|
||||
glslang/MachineIndependent/ParseHelper.cpp \
|
||||
glslang/MachineIndependent/PoolAlloc.cpp \
|
||||
glslang/MachineIndependent/propagateNoContraction.cpp \
|
||||
glslang/MachineIndependent/reflection.cpp \
|
||||
glslang/MachineIndependent/RemoveTree.cpp \
|
||||
glslang/MachineIndependent/Scan.cpp \
|
||||
glslang/MachineIndependent/ShaderLang.cpp \
|
||||
glslang/MachineIndependent/SymbolTable.cpp \
|
||||
glslang/MachineIndependent/Versions.cpp \
|
||||
glslang/MachineIndependent/preprocessor/PpAtom.cpp \
|
||||
glslang/MachineIndependent/preprocessor/PpContext.cpp \
|
||||
glslang/MachineIndependent/preprocessor/Pp.cpp \
|
||||
glslang/MachineIndependent/preprocessor/PpScanner.cpp \
|
||||
glslang/MachineIndependent/preprocessor/PpTokens.cpp
|
||||
LOCAL_C_INCLUDES:=$(LOCAL_PATH) \
|
||||
$(LOCAL_PATH)/glslang/MachineIndependent \
|
||||
$(GLSLANG_OUT_PATH)
|
||||
LOCAL_STATIC_LIBRARIES:=OSDependent OGLCompiler HLSL
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:=SPIRV
|
||||
LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti -Werror $(GLSLANG_DEFINES)
|
||||
LOCAL_EXPORT_C_INCLUDES:=$(LOCAL_PATH)
|
||||
LOCAL_SRC_FILES:= \
|
||||
SPIRV/GlslangToSpv.cpp \
|
||||
SPIRV/InReadableOrder.cpp \
|
||||
SPIRV/Logger.cpp \
|
||||
SPIRV/SPVRemapper.cpp \
|
||||
SPIRV/SpvBuilder.cpp \
|
||||
SPIRV/SpvPostProcess.cpp \
|
||||
SPIRV/SpvTools.cpp \
|
||||
SPIRV/disassemble.cpp \
|
||||
SPIRV/doc.cpp
|
||||
LOCAL_C_INCLUDES:=$(LOCAL_PATH) $(LOCAL_PATH)/glslang/SPIRV
|
||||
LOCAL_EXPORT_C_INCLUDES:=$(LOCAL_PATH)/glslang/SPIRV
|
||||
LOCAL_STATIC_LIBRARIES:=glslang
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
@@ -1,247 +0,0 @@
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
# Description:
|
||||
#
|
||||
# Khronos reference front-end for GLSL and ESSL, and sample SPIR-V generator.
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
exports_files(["LICENSE"])
|
||||
|
||||
COMMON_COPTS = select({
|
||||
"@bazel_tools//src/conditions:windows": [""],
|
||||
"//conditions:default": [
|
||||
"-Wall",
|
||||
"-Wuninitialized",
|
||||
"-Wunused",
|
||||
"-Wunused-local-typedefs",
|
||||
"-Wunused-parameter",
|
||||
"-Wunused-value",
|
||||
"-Wunused-variable",
|
||||
"-Wno-reorder",
|
||||
"-std=c++11",
|
||||
"-fvisibility=hidden",
|
||||
"-fvisibility-inlines-hidden",
|
||||
"-fno-exceptions",
|
||||
"-fno-rtti",
|
||||
],
|
||||
})
|
||||
|
||||
cc_library(
|
||||
name = "glslang",
|
||||
srcs = glob(
|
||||
[
|
||||
"glslang/GenericCodeGen/*.cpp",
|
||||
"glslang/MachineIndependent/*.cpp",
|
||||
"glslang/MachineIndependent/preprocessor/*.cpp",
|
||||
"hlsl/*.cpp",
|
||||
],
|
||||
exclude = [
|
||||
"glslang/MachineIndependent/pch.cpp",
|
||||
"glslang/MachineIndependent/pch.h",
|
||||
"hlsl/pch.cpp",
|
||||
"hlsl/pch.h",
|
||||
],
|
||||
) + [
|
||||
"OGLCompilersDLL/InitializeDll.cpp",
|
||||
] + select({
|
||||
"@bazel_tools//src/conditions:windows":
|
||||
["glslang/OSDependent/Windows/ossource.cpp"],
|
||||
"//conditions:default":
|
||||
["glslang/OSDependent/Unix/ossource.cpp"],
|
||||
}),
|
||||
hdrs = glob([
|
||||
"glslang/Include/*.h",
|
||||
"glslang/MachineIndependent/*.h",
|
||||
"glslang/MachineIndependent/preprocessor/*.h",
|
||||
"hlsl/*.h",
|
||||
]) + [
|
||||
"OGLCompilersDLL/InitializeDll.h",
|
||||
"StandAlone/DirStackFileIncluder.h",
|
||||
"glslang/OSDependent/osinclude.h",
|
||||
"glslang/Public/ShaderLang.h",
|
||||
],
|
||||
copts = COMMON_COPTS,
|
||||
defines = [
|
||||
"AMD_EXTENSIONS",
|
||||
"ENABLE_HLSL=0",
|
||||
"ENABLE_OPT=0",
|
||||
"NV_EXTENSIONS",
|
||||
],
|
||||
linkopts = select({
|
||||
"@bazel_tools//src/conditions:windows": [""],
|
||||
"//conditions:default": ["-lm", "-lpthread"],
|
||||
}),
|
||||
linkstatic = 1,
|
||||
)
|
||||
|
||||
genrule(
|
||||
name = "export_spirv_headers",
|
||||
srcs = [
|
||||
"SPIRV/GLSL.ext.AMD.h",
|
||||
"SPIRV/GLSL.ext.EXT.h",
|
||||
"SPIRV/GLSL.ext.KHR.h",
|
||||
"SPIRV/GLSL.ext.NV.h",
|
||||
"SPIRV/GLSL.std.450.h",
|
||||
"SPIRV/NonSemanticDebugPrintf.h",
|
||||
"SPIRV/spirv.hpp",
|
||||
],
|
||||
outs = [
|
||||
"include/SPIRV/GLSL.ext.AMD.h",
|
||||
"include/SPIRV/GLSL.ext.EXT.h",
|
||||
"include/SPIRV/GLSL.ext.KHR.h",
|
||||
"include/SPIRV/GLSL.ext.NV.h",
|
||||
"include/SPIRV/GLSL.std.450.h",
|
||||
"include/SPIRV/NonSemanticDebugPrintf.h",
|
||||
"include/SPIRV/spirv.hpp",
|
||||
],
|
||||
cmd = "mkdir -p $(@D)/include/SPIRV && cp $(SRCS) $(@D)/include/SPIRV/",
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "SPIRV_headers",
|
||||
hdrs = [":export_spirv_headers"],
|
||||
copts = COMMON_COPTS,
|
||||
includes = [
|
||||
"include",
|
||||
"include/SPIRV",
|
||||
],
|
||||
linkstatic = 1,
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "SPIRV",
|
||||
srcs = glob(
|
||||
["SPIRV/*.cpp"],
|
||||
exclude = [
|
||||
"SPIRV/SpvTools.cpp",
|
||||
],
|
||||
),
|
||||
hdrs = [
|
||||
"SPIRV/GlslangToSpv.h",
|
||||
"SPIRV/Logger.h",
|
||||
"SPIRV/SPVRemapper.h",
|
||||
"SPIRV/SpvBuilder.h",
|
||||
"SPIRV/SpvTools.h",
|
||||
"SPIRV/bitutils.h",
|
||||
"SPIRV/disassemble.h",
|
||||
"SPIRV/doc.h",
|
||||
"SPIRV/hex_float.h",
|
||||
"SPIRV/spvIR.h",
|
||||
],
|
||||
copts = COMMON_COPTS,
|
||||
includes = ["SPIRV"],
|
||||
linkopts = select({
|
||||
"@bazel_tools//src/conditions:windows": [""],
|
||||
"//conditions:default": ["-lm"],
|
||||
}),
|
||||
linkstatic = 1,
|
||||
deps = [
|
||||
":SPIRV_headers",
|
||||
":glslang",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "glslang-default-resource-limits",
|
||||
srcs = ["StandAlone/ResourceLimits.cpp"],
|
||||
hdrs = ["StandAlone/ResourceLimits.h"],
|
||||
copts = COMMON_COPTS,
|
||||
linkstatic = 1,
|
||||
deps = [":glslang"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "glslangValidator",
|
||||
srcs = [
|
||||
"StandAlone/StandAlone.cpp",
|
||||
"StandAlone/Worklist.h",
|
||||
],
|
||||
copts = COMMON_COPTS,
|
||||
deps = [
|
||||
":SPIRV",
|
||||
":glslang",
|
||||
":glslang-default-resource-limits",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "spirv-remap",
|
||||
srcs = ["StandAlone/spirv-remap.cpp"],
|
||||
copts = COMMON_COPTS,
|
||||
deps = [
|
||||
":SPIRV",
|
||||
":glslang",
|
||||
":glslang-default-resource-limits",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "test_files",
|
||||
srcs = glob(
|
||||
["Test/**"],
|
||||
exclude = [
|
||||
"Test/bump",
|
||||
"Test/glslangValidator",
|
||||
"Test/runtests",
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "glslang_test_lib",
|
||||
testonly = 1,
|
||||
srcs = [
|
||||
"gtests/HexFloat.cpp",
|
||||
"gtests/Initializer.h",
|
||||
"gtests/Settings.cpp",
|
||||
"gtests/Settings.h",
|
||||
"gtests/TestFixture.cpp",
|
||||
"gtests/TestFixture.h",
|
||||
"gtests/main.cpp",
|
||||
],
|
||||
copts = COMMON_COPTS,
|
||||
data = [":test_files"],
|
||||
defines = select({
|
||||
# Unfortunately we can't use $(location) in cc_library at the moment.
|
||||
# See https://github.com/bazelbuild/bazel/issues/1023
|
||||
# So we'll specify the path manually.
|
||||
"@bazel_tools//src/conditions:windows":
|
||||
["GLSLANG_TEST_DIRECTORY='\"../../../../../Test\"'"],
|
||||
"//conditions:default":
|
||||
["GLSLANG_TEST_DIRECTORY='\"Test\"'"],
|
||||
}),
|
||||
linkstatic = 1,
|
||||
deps = [
|
||||
":SPIRV",
|
||||
":glslang",
|
||||
":glslang-default-resource-limits",
|
||||
"@com_google_googletest//:gtest",
|
||||
],
|
||||
)
|
||||
|
||||
GLSLANG_TESTS = glob(
|
||||
["gtests/*.FromFile.cpp"],
|
||||
# Since we are not building the SPIRV-Tools dependency, the following tests
|
||||
# cannot be performed.
|
||||
exclude = [
|
||||
"gtests/Hlsl.FromFile.cpp",
|
||||
"gtests/Spv.FromFile.cpp",
|
||||
],
|
||||
)
|
||||
|
||||
[cc_test(
|
||||
name = test_file.replace("gtests/", "").replace(".FromFile.cpp", "") + "_test",
|
||||
srcs = [test_file],
|
||||
copts = COMMON_COPTS,
|
||||
data = [
|
||||
":test_files",
|
||||
],
|
||||
deps = [
|
||||
":SPIRV",
|
||||
":glslang",
|
||||
":glslang_test_lib",
|
||||
],
|
||||
) for test_file in GLSLANG_TESTS]
|
||||
@@ -1,248 +0,0 @@
|
||||
# Copyright (C) 2018 Google, Inc.
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
#
|
||||
# Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import("//build_overrides/glslang.gni")
|
||||
|
||||
# Both Chromium and Fuchsia use by default a set of warning errors
|
||||
# that is far too strict to compile this project. These are also
|
||||
# typically appended after |cflags|, overriding target-specific
|
||||
# definitions. To work around this, determine which configs to
|
||||
# add and remove in order to succesfully build the project.
|
||||
if (defined(is_fuchsia_tree) && is_fuchsia_tree) {
|
||||
_configs_to_remove = [ "//build/config:default_warnings" ]
|
||||
_configs_to_add = []
|
||||
} else {
|
||||
_configs_to_remove = [ "//build/config/compiler:chromium_code" ]
|
||||
_configs_to_add = [ "//build/config/compiler:no_chromium_code" ]
|
||||
}
|
||||
|
||||
spirv_tools_dir = glslang_spirv_tools_dir
|
||||
|
||||
config("glslang_public") {
|
||||
include_dirs = [ "." ]
|
||||
|
||||
defines = [ "ENABLE_HLSL=1" ]
|
||||
}
|
||||
|
||||
source_set("glslang_sources") {
|
||||
public_configs = [ ":glslang_public" ]
|
||||
|
||||
sources = [
|
||||
"OGLCompilersDLL/InitializeDll.cpp",
|
||||
"OGLCompilersDLL/InitializeDll.h",
|
||||
"SPIRV/GLSL.ext.AMD.h",
|
||||
"SPIRV/GLSL.ext.EXT.h",
|
||||
"SPIRV/GLSL.ext.KHR.h",
|
||||
"SPIRV/GLSL.ext.NV.h",
|
||||
"SPIRV/GLSL.std.450.h",
|
||||
"SPIRV/GlslangToSpv.cpp",
|
||||
"SPIRV/GlslangToSpv.h",
|
||||
"SPIRV/InReadableOrder.cpp",
|
||||
"SPIRV/Logger.cpp",
|
||||
"SPIRV/Logger.h",
|
||||
"SPIRV/NonSemanticDebugPrintf.h",
|
||||
"SPIRV/SPVRemapper.cpp",
|
||||
"SPIRV/SPVRemapper.h",
|
||||
"SPIRV/SpvBuilder.cpp",
|
||||
"SPIRV/SpvBuilder.h",
|
||||
"SPIRV/SpvPostProcess.cpp",
|
||||
"SPIRV/SpvTools.cpp",
|
||||
"SPIRV/SpvTools.h",
|
||||
"SPIRV/bitutils.h",
|
||||
"SPIRV/disassemble.cpp",
|
||||
"SPIRV/disassemble.h",
|
||||
"SPIRV/doc.cpp",
|
||||
"SPIRV/doc.h",
|
||||
"SPIRV/hex_float.h",
|
||||
"SPIRV/spirv.hpp",
|
||||
"SPIRV/spvIR.h",
|
||||
"glslang/GenericCodeGen/CodeGen.cpp",
|
||||
"glslang/GenericCodeGen/Link.cpp",
|
||||
"glslang/Include/BaseTypes.h",
|
||||
"glslang/Include/Common.h",
|
||||
"glslang/Include/ConstantUnion.h",
|
||||
"glslang/Include/InfoSink.h",
|
||||
"glslang/Include/InitializeGlobals.h",
|
||||
"glslang/Include/PoolAlloc.h",
|
||||
"glslang/Include/ResourceLimits.h",
|
||||
"glslang/Include/ShHandle.h",
|
||||
"glslang/Include/Types.h",
|
||||
"glslang/Include/arrays.h",
|
||||
"glslang/Include/intermediate.h",
|
||||
"glslang/Include/revision.h",
|
||||
"glslang/MachineIndependent/Constant.cpp",
|
||||
"glslang/MachineIndependent/InfoSink.cpp",
|
||||
"glslang/MachineIndependent/Initialize.cpp",
|
||||
"glslang/MachineIndependent/Initialize.h",
|
||||
"glslang/MachineIndependent/IntermTraverse.cpp",
|
||||
"glslang/MachineIndependent/Intermediate.cpp",
|
||||
"glslang/MachineIndependent/LiveTraverser.h",
|
||||
"glslang/MachineIndependent/ParseContextBase.cpp",
|
||||
"glslang/MachineIndependent/ParseHelper.cpp",
|
||||
"glslang/MachineIndependent/ParseHelper.h",
|
||||
"glslang/MachineIndependent/PoolAlloc.cpp",
|
||||
"glslang/MachineIndependent/RemoveTree.cpp",
|
||||
"glslang/MachineIndependent/RemoveTree.h",
|
||||
"glslang/MachineIndependent/Scan.cpp",
|
||||
"glslang/MachineIndependent/Scan.h",
|
||||
"glslang/MachineIndependent/ScanContext.h",
|
||||
"glslang/MachineIndependent/ShaderLang.cpp",
|
||||
"glslang/MachineIndependent/SymbolTable.cpp",
|
||||
"glslang/MachineIndependent/SymbolTable.h",
|
||||
"glslang/MachineIndependent/Versions.cpp",
|
||||
"glslang/MachineIndependent/Versions.h",
|
||||
"glslang/MachineIndependent/attribute.cpp",
|
||||
"glslang/MachineIndependent/attribute.h",
|
||||
"glslang/MachineIndependent/gl_types.h",
|
||||
"glslang/MachineIndependent/glslang_tab.cpp",
|
||||
"glslang/MachineIndependent/glslang_tab.cpp.h",
|
||||
"glslang/MachineIndependent/intermOut.cpp",
|
||||
"glslang/MachineIndependent/iomapper.cpp",
|
||||
"glslang/MachineIndependent/iomapper.h",
|
||||
"glslang/MachineIndependent/limits.cpp",
|
||||
"glslang/MachineIndependent/linkValidate.cpp",
|
||||
"glslang/MachineIndependent/localintermediate.h",
|
||||
"glslang/MachineIndependent/parseConst.cpp",
|
||||
"glslang/MachineIndependent/parseVersions.h",
|
||||
"glslang/MachineIndependent/preprocessor/Pp.cpp",
|
||||
"glslang/MachineIndependent/preprocessor/PpAtom.cpp",
|
||||
"glslang/MachineIndependent/preprocessor/PpContext.cpp",
|
||||
"glslang/MachineIndependent/preprocessor/PpContext.h",
|
||||
"glslang/MachineIndependent/preprocessor/PpScanner.cpp",
|
||||
"glslang/MachineIndependent/preprocessor/PpTokens.cpp",
|
||||
"glslang/MachineIndependent/preprocessor/PpTokens.h",
|
||||
"glslang/MachineIndependent/propagateNoContraction.cpp",
|
||||
"glslang/MachineIndependent/propagateNoContraction.h",
|
||||
"glslang/MachineIndependent/reflection.cpp",
|
||||
"glslang/MachineIndependent/reflection.h",
|
||||
"glslang/OSDependent/osinclude.h",
|
||||
"glslang/Public/ShaderLang.h",
|
||||
"hlsl/hlslAttributes.cpp",
|
||||
"hlsl/hlslAttributes.h",
|
||||
"hlsl/hlslGrammar.cpp",
|
||||
"hlsl/hlslGrammar.h",
|
||||
"hlsl/hlslOpMap.cpp",
|
||||
"hlsl/hlslOpMap.h",
|
||||
"hlsl/hlslParseHelper.cpp",
|
||||
"hlsl/hlslParseHelper.h",
|
||||
"hlsl/hlslParseables.cpp",
|
||||
"hlsl/hlslParseables.h",
|
||||
"hlsl/hlslScanContext.cpp",
|
||||
"hlsl/hlslScanContext.h",
|
||||
"hlsl/hlslTokenStream.cpp",
|
||||
"hlsl/hlslTokenStream.h",
|
||||
"hlsl/hlslTokens.h",
|
||||
]
|
||||
|
||||
defines = [ "ENABLE_OPT=1" ]
|
||||
|
||||
if (is_win) {
|
||||
sources += [ "glslang/OSDependent/Windows/ossource.cpp" ]
|
||||
defines += [ "GLSLANG_OSINCLUDE_WIN32" ]
|
||||
} else {
|
||||
sources += [ "glslang/OSDependent/Unix/ossource.cpp" ]
|
||||
defines += [ "GLSLANG_OSINCLUDE_UNIX" ]
|
||||
}
|
||||
|
||||
if (is_clang) {
|
||||
cflags = [
|
||||
"-Wno-extra-semi",
|
||||
"-Wno-ignored-qualifiers",
|
||||
"-Wno-implicit-fallthrough",
|
||||
"-Wno-inconsistent-missing-override",
|
||||
"-Wno-sign-compare",
|
||||
"-Wno-unused-variable",
|
||||
"-Wno-missing-field-initializers",
|
||||
"-Wno-newline-eof",
|
||||
]
|
||||
}
|
||||
if (is_win && !is_clang) {
|
||||
cflags = [
|
||||
"/wd4018", # signed/unsigned mismatch
|
||||
"/wd4189", # local variable is initialized but not referenced
|
||||
]
|
||||
}
|
||||
|
||||
deps = [
|
||||
"${spirv_tools_dir}:spvtools_opt",
|
||||
"${spirv_tools_dir}:spvtools_val",
|
||||
]
|
||||
|
||||
configs -= _configs_to_remove
|
||||
configs += _configs_to_add
|
||||
}
|
||||
|
||||
source_set("glslang_default_resource_limits_sources") {
|
||||
sources = [
|
||||
"StandAlone/ResourceLimits.cpp",
|
||||
"StandAlone/ResourceLimits.h",
|
||||
]
|
||||
deps = [
|
||||
":glslang_sources",
|
||||
]
|
||||
public_configs = [ ":glslang_public" ]
|
||||
|
||||
configs -= _configs_to_remove
|
||||
configs += _configs_to_add
|
||||
}
|
||||
|
||||
executable("glslang_validator") {
|
||||
sources = [
|
||||
"StandAlone/DirStackFileIncluder.h",
|
||||
"StandAlone/StandAlone.cpp",
|
||||
]
|
||||
if (!is_win) {
|
||||
cflags = [ "-Woverflow" ]
|
||||
}
|
||||
defines = [ "ENABLE_OPT=1" ]
|
||||
deps = [
|
||||
":glslang_default_resource_limits_sources",
|
||||
":glslang_sources",
|
||||
]
|
||||
|
||||
configs -= _configs_to_remove
|
||||
configs += _configs_to_add
|
||||
}
|
||||
|
||||
executable("spirv-remap") {
|
||||
sources = [
|
||||
"StandAlone/spirv-remap.cpp",
|
||||
]
|
||||
defines = [ "ENABLE_OPT=1" ]
|
||||
deps = [
|
||||
":glslang_sources",
|
||||
]
|
||||
|
||||
configs -= _configs_to_remove
|
||||
configs += _configs_to_add
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
# increase to 3.1 once all major distributions
|
||||
# include a version of CMake >= 3.1
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
if (POLICY CMP0048)
|
||||
cmake_policy(SET CMP0048 NEW)
|
||||
endif()
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
# Enable compile commands database
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
# Adhere to GNU filesystem layout conventions
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Needed for CMAKE_DEPENDENT_OPTION macro
|
||||
include(CMakeDependentOption)
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build Shared Libraries" OFF)
|
||||
option(BUILD_EXTERNAL "Build external dependencies in /External" ON)
|
||||
|
||||
set(LIB_TYPE STATIC)
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
set(LIB_TYPE SHARED)
|
||||
endif()
|
||||
|
||||
option(SKIP_GLSLANG_INSTALL "Skip installation" ${SKIP_GLSLANG_INSTALL})
|
||||
if(NOT ${SKIP_GLSLANG_INSTALL})
|
||||
set(ENABLE_GLSLANG_INSTALL ON)
|
||||
endif()
|
||||
option(ENABLE_SPVREMAPPER "Enables building of SPVRemapper" ON)
|
||||
|
||||
option(ENABLE_GLSLANG_BINARIES "Builds glslangValidator and spirv-remap" ON)
|
||||
|
||||
option(ENABLE_GLSLANG_JS
|
||||
"If using Emscripten, build glslang.js. Otherwise, builds a sample executable for binary-size testing." OFF)
|
||||
CMAKE_DEPENDENT_OPTION(ENABLE_GLSLANG_WEBMIN
|
||||
"Reduces glslang to minimum needed for web use"
|
||||
OFF "ENABLE_GLSLANG_JS"
|
||||
OFF)
|
||||
CMAKE_DEPENDENT_OPTION(ENABLE_GLSLANG_WEBMIN_DEVEL
|
||||
"For ENABLE_GLSLANG_WEBMIN builds, enables compilation error messages"
|
||||
OFF "ENABLE_GLSLANG_WEBMIN"
|
||||
OFF)
|
||||
CMAKE_DEPENDENT_OPTION(ENABLE_EMSCRIPTEN_SINGLE_FILE
|
||||
"If using Emscripten, enables SINGLE_FILE build"
|
||||
OFF "ENABLE_GLSLANG_JS AND EMSCRIPTEN"
|
||||
OFF)
|
||||
CMAKE_DEPENDENT_OPTION(ENABLE_EMSCRIPTEN_ENVIRONMENT_NODE
|
||||
"If using Emscripten, builds to run on Node instead of Web"
|
||||
OFF "ENABLE_GLSLANG_JS AND EMSCRIPTEN"
|
||||
OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(ENABLE_HLSL
|
||||
"Enables HLSL input support"
|
||||
ON "NOT ENABLE_GLSLANG_WEBMIN"
|
||||
OFF)
|
||||
|
||||
option(ENABLE_RTTI "Enables RTTI" OFF)
|
||||
option(ENABLE_OPT "Enables spirv-opt capability if present" ON)
|
||||
option(ENABLE_PCH "Enables Precompiled header" ON)
|
||||
option(ENABLE_CTEST "Enables testing" ON)
|
||||
|
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND WIN32)
|
||||
set(CMAKE_INSTALL_PREFIX "install" CACHE STRING "..." FORCE)
|
||||
endif()
|
||||
|
||||
option(USE_CCACHE "Use ccache" OFF)
|
||||
if(USE_CCACHE)
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(CCACHE_FOUND)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
endif(CCACHE_FOUND)
|
||||
endif()
|
||||
|
||||
# Precompiled header macro. Parameters are source file list and filename for pch cpp file.
|
||||
macro(glslang_pch SRCS PCHCPP)
|
||||
if(MSVC AND CMAKE_GENERATOR MATCHES "^Visual Studio" AND NOT ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang" AND ENABLE_PCH)
|
||||
set(PCH_NAME "$(IntDir)\\pch.pch")
|
||||
# make source files use/depend on PCH_NAME
|
||||
set_source_files_properties(${${SRCS}} PROPERTIES COMPILE_FLAGS "/Yupch.h /FIpch.h /Fp${PCH_NAME} /Zm300" OBJECT_DEPENDS "${PCH_NAME}")
|
||||
# make PCHCPP file compile and generate PCH_NAME
|
||||
set_source_files_properties(${PCHCPP} PROPERTIES COMPILE_FLAGS "/Ycpch.h /Fp${PCH_NAME} /Zm300" OBJECT_OUTPUTS "${PCH_NAME}")
|
||||
list(APPEND ${SRCS} "${PCHCPP}")
|
||||
endif()
|
||||
endmacro(glslang_pch)
|
||||
|
||||
project(glslang)
|
||||
|
||||
if(ENABLE_CTEST)
|
||||
include(CTest)
|
||||
endif()
|
||||
|
||||
if(ENABLE_HLSL)
|
||||
add_definitions(-DENABLE_HLSL)
|
||||
endif(ENABLE_HLSL)
|
||||
|
||||
if(ENABLE_GLSLANG_WEBMIN)
|
||||
add_definitions(-DGLSLANG_WEB)
|
||||
if(ENABLE_GLSLANG_WEBMIN_DEVEL)
|
||||
add_definitions(-DGLSLANG_WEB_DEVEL)
|
||||
endif(ENABLE_GLSLANG_WEBMIN_DEVEL)
|
||||
endif(ENABLE_GLSLANG_WEBMIN)
|
||||
|
||||
if(WIN32)
|
||||
set(CMAKE_DEBUG_POSTFIX "d")
|
||||
if(MSVC)
|
||||
include(ChooseMSVCCRT.cmake)
|
||||
endif(MSVC)
|
||||
add_definitions(-DGLSLANG_OSINCLUDE_WIN32)
|
||||
elseif(UNIX)
|
||||
add_definitions(-DGLSLANG_OSINCLUDE_UNIX)
|
||||
else(WIN32)
|
||||
message("unknown platform")
|
||||
endif(WIN32)
|
||||
|
||||
if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
|
||||
add_compile_options(-Wall -Wmaybe-uninitialized -Wuninitialized -Wunused -Wunused-local-typedefs
|
||||
-Wunused-parameter -Wunused-value -Wunused-variable -Wunused-but-set-parameter -Wunused-but-set-variable -fno-exceptions)
|
||||
add_compile_options(-Wno-reorder) # disable this from -Wall, since it happens all over.
|
||||
if(NOT ENABLE_RTTI)
|
||||
add_compile_options(-fno-rtti)
|
||||
endif()
|
||||
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "9.0.0")
|
||||
add_compile_options(-Werror=deprecated-copy)
|
||||
endif()
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang" AND NOT MSVC)
|
||||
add_compile_options(-Wall -Wuninitialized -Wunused -Wunused-local-typedefs
|
||||
-Wunused-parameter -Wunused-value -Wunused-variable)
|
||||
add_compile_options(-Wno-reorder) # disable this from -Wall, since it happens all over.
|
||||
if(NOT ENABLE_RTTI)
|
||||
add_compile_options(-fno-rtti)
|
||||
endif()
|
||||
elseif(MSVC)
|
||||
if(NOT ENABLE_RTTI)
|
||||
add_compile_options(/GR-) # Disable RTTI
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_GLSLANG_JS)
|
||||
if(MSVC)
|
||||
add_compile_options(/Os /GR-)
|
||||
else()
|
||||
add_compile_options(-Os -fno-exceptions)
|
||||
if(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang" AND NOT MSVC)
|
||||
add_compile_options(-Wno-unused-parameter)
|
||||
add_compile_options(-Wno-unused-variable -Wno-unused-const-variable)
|
||||
endif()
|
||||
endif()
|
||||
endif(ENABLE_GLSLANG_JS)
|
||||
|
||||
# Request C++11
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.1)
|
||||
# CMake versions before 3.1 do not understand CMAKE_CXX_STANDARD
|
||||
# remove this block once CMake >=3.1 has fixated in the ecosystem
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
else()
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
endif()
|
||||
|
||||
function(glslang_set_link_args TARGET)
|
||||
# For MinGW compiles, statically link against the GCC and C++ runtimes.
|
||||
# This avoids the need to ship those runtimes as DLLs.
|
||||
if(WIN32 AND ${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
|
||||
set_target_properties(${TARGET} PROPERTIES
|
||||
LINK_FLAGS "-static -static-libgcc -static-libstdc++")
|
||||
endif()
|
||||
endfunction(glslang_set_link_args)
|
||||
|
||||
# CMake needs to find the right version of python, right from the beginning,
|
||||
# otherwise, it will find the wrong version and fail later
|
||||
if(BUILD_EXTERNAL AND IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/External)
|
||||
find_package(PythonInterp 3 REQUIRED)
|
||||
|
||||
# We depend on these for later projects, so they should come first.
|
||||
add_subdirectory(External)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET SPIRV-Tools-opt)
|
||||
set(ENABLE_OPT OFF)
|
||||
endif()
|
||||
|
||||
if(ENABLE_OPT)
|
||||
message(STATUS "optimizer enabled")
|
||||
add_definitions(-DENABLE_OPT=1)
|
||||
else()
|
||||
if(ENABLE_HLSL)
|
||||
message(STATUS "spirv-tools not linked - illegal SPIRV may be generated for HLSL")
|
||||
endif()
|
||||
add_definitions(-DENABLE_OPT=0)
|
||||
endif()
|
||||
|
||||
add_subdirectory(glslang)
|
||||
add_subdirectory(OGLCompilersDLL)
|
||||
if(ENABLE_GLSLANG_BINARIES)
|
||||
add_subdirectory(StandAlone)
|
||||
endif()
|
||||
add_subdirectory(SPIRV)
|
||||
if(ENABLE_HLSL)
|
||||
add_subdirectory(hlsl)
|
||||
endif(ENABLE_HLSL)
|
||||
if(ENABLE_CTEST)
|
||||
add_subdirectory(gtests)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
# glslang-testsuite runs a bash script on Windows.
|
||||
# Make sure to use '-o igncr' flag to ignore carriage returns (\r).
|
||||
set(IGNORE_CR_FLAG "")
|
||||
if(WIN32)
|
||||
set(IGNORE_CR_FLAG -o igncr)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CONFIGURATION_TYPES)
|
||||
set(RESULTS_PATH ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>/localResults)
|
||||
set(VALIDATOR_PATH ${CMAKE_CURRENT_BINARY_DIR}/StandAlone/$<CONFIGURATION>/glslangValidator)
|
||||
set(REMAP_PATH ${CMAKE_CURRENT_BINARY_DIR}/StandAlone/$<CONFIGURATION>/spirv-remap)
|
||||
else(CMAKE_CONFIGURATION_TYPES)
|
||||
set(RESULTS_PATH ${CMAKE_CURRENT_BINARY_DIR}/localResults)
|
||||
set(VALIDATOR_PATH ${CMAKE_CURRENT_BINARY_DIR}/StandAlone/glslangValidator)
|
||||
set(REMAP_PATH ${CMAKE_CURRENT_BINARY_DIR}/StandAlone/spirv-remap)
|
||||
endif(CMAKE_CONFIGURATION_TYPES)
|
||||
|
||||
add_test(NAME glslang-testsuite
|
||||
COMMAND bash ${IGNORE_CR_FLAG} runtests ${RESULTS_PATH} ${VALIDATOR_PATH} ${REMAP_PATH}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Test/)
|
||||
endif(BUILD_TESTING)
|
||||
@@ -1 +0,0 @@
|
||||
A reminder that this issue tracker is managed by the Khronos Group. Interactions here should follow the Khronos Code of Conduct (https://www.khronos.org/developers/code-of-conduct), which prohibits aggressive or derogatory language. Please keep the discussion friendly and civil.
|
||||
@@ -1,105 +0,0 @@
|
||||
# The macro choose_msvc_crt() takes a list of possible
|
||||
# C runtimes to choose from, in the form of compiler flags,
|
||||
# to present to the user. (MTd for /MTd, etc)
|
||||
#
|
||||
# The macro is invoked at the end of the file.
|
||||
#
|
||||
# CMake already sets CRT flags in the CMAKE_CXX_FLAGS_* and
|
||||
# CMAKE_C_FLAGS_* variables by default. To let the user
|
||||
# override that for each build type:
|
||||
# 1. Detect which CRT is already selected, and reflect this in
|
||||
# LLVM_USE_CRT_* so the user can have a better idea of what
|
||||
# changes they're making.
|
||||
# 2. Replace the flags in both variables with the new flag via a regex.
|
||||
# 3. set() the variables back into the cache so the changes
|
||||
# are user-visible.
|
||||
|
||||
### Helper macros: ###
|
||||
macro(make_crt_regex regex crts)
|
||||
set(${regex} "")
|
||||
foreach(crt ${${crts}})
|
||||
# Trying to match the beginning or end of the string with stuff
|
||||
# like [ ^]+ didn't work, so use a bunch of parentheses instead.
|
||||
set(${regex} "${${regex}}|(^| +)/${crt}($| +)")
|
||||
endforeach(crt)
|
||||
string(REGEX REPLACE "^\\|" "" ${regex} "${${regex}}")
|
||||
endmacro(make_crt_regex)
|
||||
|
||||
macro(get_current_crt crt_current regex flagsvar)
|
||||
# Find the selected-by-CMake CRT for each build type, if any.
|
||||
# Strip off the leading slash and any whitespace.
|
||||
string(REGEX MATCH "${${regex}}" ${crt_current} "${${flagsvar}}")
|
||||
string(REPLACE "/" " " ${crt_current} "${${crt_current}}")
|
||||
string(STRIP "${${crt_current}}" ${crt_current})
|
||||
endmacro(get_current_crt)
|
||||
|
||||
# Replaces or adds a flag to a variable.
|
||||
# Expects 'flag' to be padded with spaces.
|
||||
macro(set_flag_in_var flagsvar regex flag)
|
||||
string(REGEX MATCH "${${regex}}" current_flag "${${flagsvar}}")
|
||||
if("${current_flag}" STREQUAL "")
|
||||
set(${flagsvar} "${${flagsvar}}${${flag}}")
|
||||
else()
|
||||
string(REGEX REPLACE "${${regex}}" "${${flag}}" ${flagsvar} "${${flagsvar}}")
|
||||
endif()
|
||||
string(STRIP "${${flagsvar}}" ${flagsvar})
|
||||
# Make sure this change gets reflected in the cache/gui.
|
||||
# CMake requires the docstring parameter whenever set() touches the cache,
|
||||
# so get the existing docstring and re-use that.
|
||||
get_property(flagsvar_docs CACHE ${flagsvar} PROPERTY HELPSTRING)
|
||||
set(${flagsvar} "${${flagsvar}}" CACHE STRING "${flagsvar_docs}" FORCE)
|
||||
endmacro(set_flag_in_var)
|
||||
|
||||
|
||||
macro(choose_msvc_crt MSVC_CRT)
|
||||
if(LLVM_USE_CRT)
|
||||
message(FATAL_ERROR
|
||||
"LLVM_USE_CRT is deprecated. Use the CMAKE_BUILD_TYPE-specific
|
||||
variables (LLVM_USE_CRT_DEBUG, etc) instead.")
|
||||
endif()
|
||||
|
||||
make_crt_regex(MSVC_CRT_REGEX ${MSVC_CRT})
|
||||
|
||||
foreach(build_type ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE})
|
||||
string(TOUPPER "${build_type}" build)
|
||||
if (NOT LLVM_USE_CRT_${build})
|
||||
get_current_crt(LLVM_USE_CRT_${build}
|
||||
MSVC_CRT_REGEX
|
||||
CMAKE_CXX_FLAGS_${build})
|
||||
set(LLVM_USE_CRT_${build}
|
||||
"${LLVM_USE_CRT_${build}}"
|
||||
CACHE STRING "Specify VC++ CRT to use for ${build_type} configurations."
|
||||
FORCE)
|
||||
set_property(CACHE LLVM_USE_CRT_${build}
|
||||
PROPERTY STRINGS ;${${MSVC_CRT}})
|
||||
endif(NOT LLVM_USE_CRT_${build})
|
||||
endforeach(build_type)
|
||||
|
||||
foreach(build_type ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE})
|
||||
string(TOUPPER "${build_type}" build)
|
||||
if ("${LLVM_USE_CRT_${build}}" STREQUAL "")
|
||||
set(flag_string " ")
|
||||
else()
|
||||
set(flag_string " /${LLVM_USE_CRT_${build}} ")
|
||||
list(FIND ${MSVC_CRT} ${LLVM_USE_CRT_${build}} idx)
|
||||
if (idx LESS 0)
|
||||
message(FATAL_ERROR
|
||||
"Invalid value for LLVM_USE_CRT_${build}: ${LLVM_USE_CRT_${build}}. Valid options are one of: ${${MSVC_CRT}}")
|
||||
endif (idx LESS 0)
|
||||
message(STATUS "Using ${build_type} VC++ CRT: ${LLVM_USE_CRT_${build}}")
|
||||
endif()
|
||||
foreach(lang C CXX)
|
||||
set_flag_in_var(CMAKE_${lang}_FLAGS_${build} MSVC_CRT_REGEX flag_string)
|
||||
endforeach(lang)
|
||||
endforeach(build_type)
|
||||
endmacro(choose_msvc_crt MSVC_CRT)
|
||||
|
||||
|
||||
# List of valid CRTs for MSVC
|
||||
set(MSVC_CRT
|
||||
MD
|
||||
MDd
|
||||
MT
|
||||
MTd)
|
||||
|
||||
choose_msvc_crt(MSVC_CRT)
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
# Suppress all warnings from external projects.
|
||||
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS -w)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
if(TARGET gmock)
|
||||
message(STATUS "Google Mock already configured - use it")
|
||||
elseif(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/googletest)
|
||||
# We need to make sure Google Test does not mess up with the
|
||||
# global CRT settings on Windows.
|
||||
if(WIN32)
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
endif(WIN32)
|
||||
# EXCLUDE_FROM_ALL keeps the install target from installing GTEST files.
|
||||
add_subdirectory(googletest EXCLUDE_FROM_ALL)
|
||||
set(GTEST_TARGETS
|
||||
gtest
|
||||
gtest_main
|
||||
gmock
|
||||
gmock_main)
|
||||
foreach(target ${GTEST_TARGETS})
|
||||
set_property(TARGET ${target} PROPERTY FOLDER gtest)
|
||||
endforeach()
|
||||
mark_as_advanced(gmock_build_tests
|
||||
BUILD_GMOCK
|
||||
BUILD_GTEST
|
||||
BUILD_SHARED_LIBS
|
||||
gtest_build_samples
|
||||
gtest_build_tests
|
||||
gtest_disable_pthreads
|
||||
gtest_force_shared_crt
|
||||
gtest_hide_internal_symbols)
|
||||
else()
|
||||
message(STATUS
|
||||
"Google Mock was not found - tests based on that will not build")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_OPT AND NOT TARGET SPIRV-Tools-opt)
|
||||
if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/spirv-tools)
|
||||
set(SPIRV_SKIP_TESTS ON CACHE BOOL "Skip building SPIRV-Tools tests")
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/spirv-tools spirv-tools)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
Here, glslang proper means core GLSL parsing, HLSL parsing, and SPIR-V code
|
||||
generation. Glslang proper requires use of two licenses, one that covers
|
||||
non-preprocessing and an additional one that covers preprocessing.
|
||||
|
||||
Bison was removed long ago. You can build glslang from the source grammar,
|
||||
using tools of your choice, without using bison or any bison files.
|
||||
|
||||
Other parts, outside of glslang proper, include:
|
||||
|
||||
- gl_types.h, only needed for OpenGL-like reflection, and can be left out of
|
||||
a parse and codegen project. See it for its license.
|
||||
|
||||
- update_glslang_sources.py, which is not part of the project proper and does
|
||||
not need to be used.
|
||||
|
||||
- the SPIR-V "remapper", which is optional, but has the same license as
|
||||
glslang proper
|
||||
|
||||
- Google tests and SPIR-V tools, and anything in the external subdirectory
|
||||
are external and optional; see them for their respective licenses.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
The core of glslang-proper, minus the preprocessor is licenced as follows:
|
||||
|
||||
//
|
||||
// Copyright (C) 2015-2018 Google, Inc.
|
||||
// Copyright (C) <various other dates and companies>
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
The preprocessor has the core license stated above, plus an additional licence:
|
||||
|
||||
/****************************************************************************\
|
||||
Copyright (c) 2002, NVIDIA Corporation.
|
||||
|
||||
NVIDIA Corporation("NVIDIA") supplies this software to you in
|
||||
consideration of your agreement to the following terms, and your use,
|
||||
installation, modification or redistribution of this NVIDIA software
|
||||
constitutes acceptance of these terms. If you do not agree with these
|
||||
terms, please do not use, install, modify or redistribute this NVIDIA
|
||||
software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, NVIDIA grants you a personal, non-exclusive
|
||||
license, under NVIDIA's copyrights in this original NVIDIA software (the
|
||||
"NVIDIA Software"), to use, reproduce, modify and redistribute the
|
||||
NVIDIA Software, with or without modifications, in source and/or binary
|
||||
forms; provided that if you redistribute the NVIDIA Software, you must
|
||||
retain the copyright notice of NVIDIA, this notice and the following
|
||||
text and disclaimers in all such redistributions of the NVIDIA Software.
|
||||
Neither the name, trademarks, service marks nor logos of NVIDIA
|
||||
Corporation may be used to endorse or promote products derived from the
|
||||
NVIDIA Software without specific prior written permission from NVIDIA.
|
||||
Except as expressly stated in this notice, no other rights or licenses
|
||||
express or implied, are granted by NVIDIA herein, including but not
|
||||
limited to any patent rights that may be infringed by your derivative
|
||||
works or by other works in which the NVIDIA Software may be
|
||||
incorporated. No hardware is licensed hereunder.
|
||||
|
||||
THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
||||
INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
|
||||
ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
|
||||
PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
|
||||
INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
|
||||
OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
|
||||
NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
|
||||
TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
||||
NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
\****************************************************************************/
|
||||
@@ -1,15 +0,0 @@
|
||||
set(SOURCES InitializeDll.cpp InitializeDll.h)
|
||||
|
||||
add_library(OGLCompiler STATIC ${SOURCES})
|
||||
set_property(TARGET OGLCompiler PROPERTY FOLDER glslang)
|
||||
set_property(TARGET OGLCompiler PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
if(WIN32)
|
||||
source_group("Source" FILES ${SOURCES})
|
||||
endif(WIN32)
|
||||
|
||||
if(ENABLE_GLSLANG_INSTALL)
|
||||
install(TARGETS OGLCompiler EXPORT OGLCompilerTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install(EXPORT OGLCompilerTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
|
||||
endif(ENABLE_GLSLANG_INSTALL)
|
||||
@@ -1,165 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#define SH_EXPORTING
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "InitializeDll.h"
|
||||
#include "../glslang/Include/InitializeGlobals.h"
|
||||
#include "../glslang/Public/ShaderLang.h"
|
||||
#include "../glslang/Include/PoolAlloc.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
OS_TLSIndex ThreadInitializeIndex = OS_INVALID_TLS_INDEX;
|
||||
|
||||
// Per-process initialization.
|
||||
// Needs to be called at least once before parsing, etc. is done.
|
||||
// Will also do thread initialization for the calling thread; other
|
||||
// threads will need to do that explicitly.
|
||||
bool InitProcess()
|
||||
{
|
||||
glslang::GetGlobalLock();
|
||||
|
||||
if (ThreadInitializeIndex != OS_INVALID_TLS_INDEX) {
|
||||
//
|
||||
// Function is re-entrant.
|
||||
//
|
||||
|
||||
glslang::ReleaseGlobalLock();
|
||||
return true;
|
||||
}
|
||||
|
||||
ThreadInitializeIndex = OS_AllocTLSIndex();
|
||||
|
||||
if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) {
|
||||
assert(0 && "InitProcess(): Failed to allocate TLS area for init flag");
|
||||
|
||||
glslang::ReleaseGlobalLock();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! InitializePoolIndex()) {
|
||||
assert(0 && "InitProcess(): Failed to initialize global pool");
|
||||
|
||||
glslang::ReleaseGlobalLock();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! InitThread()) {
|
||||
assert(0 && "InitProcess(): Failed to initialize thread");
|
||||
|
||||
glslang::ReleaseGlobalLock();
|
||||
return false;
|
||||
}
|
||||
|
||||
glslang::ReleaseGlobalLock();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Per-thread scoped initialization.
|
||||
// Must be called at least once by each new thread sharing the
|
||||
// symbol tables, etc., needed to parse.
|
||||
bool InitThread()
|
||||
{
|
||||
//
|
||||
// This function is re-entrant
|
||||
//
|
||||
if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) {
|
||||
assert(0 && "InitThread(): Process hasn't been initalised.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (OS_GetTLSValue(ThreadInitializeIndex) != 0)
|
||||
return true;
|
||||
|
||||
if (! OS_SetTLSValue(ThreadInitializeIndex, (void *)1)) {
|
||||
assert(0 && "InitThread(): Unable to set init flag.");
|
||||
return false;
|
||||
}
|
||||
|
||||
glslang::SetThreadPoolAllocator(nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not necessary to call this: InitThread() is reentrant, and the need
|
||||
// to do per thread tear down has been removed.
|
||||
//
|
||||
// This is kept, with memory management removed, to satisfy any exiting
|
||||
// calls to it that rely on it.
|
||||
bool DetachThread()
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX)
|
||||
return true;
|
||||
|
||||
//
|
||||
// Function is re-entrant and this thread may not have been initialized.
|
||||
//
|
||||
if (OS_GetTLSValue(ThreadInitializeIndex) != 0) {
|
||||
if (!OS_SetTLSValue(ThreadInitializeIndex, (void *)0)) {
|
||||
assert(0 && "DetachThread(): Unable to clear init flag.");
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Not necessary to call this: InitProcess() is reentrant.
|
||||
//
|
||||
// This is kept, with memory management removed, to satisfy any exiting
|
||||
// calls to it that rely on it.
|
||||
//
|
||||
// Users of glslang should call shFinalize() or glslang::FinalizeProcess() for
|
||||
// process-scoped memory tear down.
|
||||
bool DetachProcess()
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX)
|
||||
return true;
|
||||
|
||||
success = DetachThread();
|
||||
|
||||
OS_FreeTLSIndex(ThreadInitializeIndex);
|
||||
ThreadInitializeIndex = OS_INVALID_TLS_INDEX;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
||||
@@ -1,49 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
#ifndef __INITIALIZEDLL_H
|
||||
#define __INITIALIZEDLL_H
|
||||
|
||||
#include "../glslang/OSDependent/osinclude.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
bool InitProcess();
|
||||
bool InitThread();
|
||||
bool DetachThread(); // not called from standalone, perhaps other tools rely on parts of it
|
||||
bool DetachProcess(); // not called from standalone, perhaps other tools rely on parts of it
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // __INITIALIZEDLL_H
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
|
||||
VERSION
|
||||
--------------------------------------------------------------------------------
|
||||
spirv-remap 0.97
|
||||
|
||||
INTRO:
|
||||
--------------------------------------------------------------------------------
|
||||
spirv-remap is a utility to improve compression of SPIR-V binary files via
|
||||
entropy reduction, plus optional stripping of debug information and
|
||||
load/store optimization. It transforms SPIR-V to SPIR-V, remapping IDs. The
|
||||
resulting modules have an increased ID range (IDs are not as tightly packed
|
||||
around zero), but will compress better when multiple modules are compressed
|
||||
together, since compressor's dictionary can find better cross module
|
||||
commonality.
|
||||
|
||||
Remapping is accomplished via canonicalization. Thus, modules can be
|
||||
compressed one at a time with no loss of quality relative to operating on
|
||||
many modules at once. The command line tool operates on multiple modules
|
||||
only in the trivial repetition sense, for ease of use. The remapper API
|
||||
only accepts a single module at a time.
|
||||
|
||||
There are two modes of use: command line, and a C++11 API. Both are
|
||||
described below.
|
||||
|
||||
spirv-remap is currently in an alpha state. Although there are no known
|
||||
remapping defects, it has only been exercised on one real world game shader
|
||||
workload.
|
||||
|
||||
|
||||
FEEDBACK
|
||||
--------------------------------------------------------------------------------
|
||||
Report defects, enhancements requests, code improvements, etc to:
|
||||
[email protected]
|
||||
|
||||
|
||||
COMMAND LINE USAGE:
|
||||
--------------------------------------------------------------------------------
|
||||
Examples are given with a verbosity of one (-v), but more verbosity can be
|
||||
had via -vv, -vvv, etc, or an integer parameter to --verbose, such as
|
||||
"--verbose 4". With no verbosity, the command is silent and returns 0 on
|
||||
success, and a positive integer error on failure.
|
||||
|
||||
Pre-built binaries for several OSs are available. Examples presented are
|
||||
for Linux. Command line arguments can be provided in any order.
|
||||
|
||||
1. Basic ID remapping
|
||||
|
||||
Perform ID remapping on all shaders in "*.spv", writing new files with
|
||||
the same basenames to /tmp/out_dir.
|
||||
|
||||
spirv-remap -v --map all --input *.spv --output /tmp/out_dir
|
||||
|
||||
2. Perform all possible size reductions
|
||||
|
||||
spirv-remap-linux-64 -v --do-everything --input *.spv --output /tmp/out_dir
|
||||
|
||||
Note that --do-everything is a synonym for:
|
||||
|
||||
--map all --dce all --opt all --strip all
|
||||
|
||||
API USAGE:
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
The public interface to the remapper is defined in SPIRV/SPVRemapper.h as follows:
|
||||
|
||||
namespace spv {
|
||||
|
||||
class spirvbin_t
|
||||
{
|
||||
public:
|
||||
enum Options { ... };
|
||||
spirvbin_t(int verbose = 0); // construct
|
||||
|
||||
// remap an existing binary in memory
|
||||
void remap(std::vector<std::uint32_t>& spv, std::uint32_t opts = DO_EVERYTHING);
|
||||
|
||||
// Type for error/log handler functions
|
||||
typedef std::function<void(const std::string&)> errorfn_t;
|
||||
typedef std::function<void(const std::string&)> logfn_t;
|
||||
|
||||
// Register error/log handling functions (can be c/c++ fn, lambda fn, or functor)
|
||||
static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; }
|
||||
static void registerLogHandler(logfn_t handler) { logHandler = handler; }
|
||||
};
|
||||
|
||||
} // namespace spv
|
||||
|
||||
The class definition is in SPVRemapper.cpp.
|
||||
|
||||
remap() accepts an std::vector of SPIR-V words, modifies them per the
|
||||
request given in 'opts', and leaves the 'spv' container with the result.
|
||||
It is safe to instantiate one spirvbin_t per thread and process a different
|
||||
SPIR-V in each.
|
||||
|
||||
The "opts" parameter to remap() accepts a bit mask of desired remapping
|
||||
options. See REMAPPING AND OPTIMIZATION OPTIONS.
|
||||
|
||||
On error, the function supplied to registerErrorHandler() will be invoked.
|
||||
This can be a standard C/C++ function, a lambda function, or a functor.
|
||||
The default handler simply calls exit(5); The error handler is a static
|
||||
member, so need only be set up once, not once per spirvbin_t instance.
|
||||
|
||||
Log messages are supplied to registerLogHandler(). By default, log
|
||||
messages are eaten silently. The log handler is also a static member.
|
||||
|
||||
BUILD DEPENDENCIES:
|
||||
--------------------------------------------------------------------------------
|
||||
1. C++11 compatible compiler
|
||||
2. cmake
|
||||
3. glslang
|
||||
|
||||
|
||||
BUILDING
|
||||
--------------------------------------------------------------------------------
|
||||
The standalone remapper is built along side glslangValidator through its
|
||||
normal build process.
|
||||
|
||||
|
||||
REMAPPING AND OPTIMIZATION OPTIONS
|
||||
--------------------------------------------------------------------------------
|
||||
API:
|
||||
These are bits defined under spv::spirvbin_t::, and can be
|
||||
bitwise or-ed together as desired.
|
||||
|
||||
MAP_TYPES = canonicalize type IDs
|
||||
MAP_NAMES = canonicalize named data
|
||||
MAP_FUNCS = canonicalize function bodies
|
||||
DCE_FUNCS = remove dead functions
|
||||
DCE_VARS = remove dead variables
|
||||
DCE_TYPES = remove dead types
|
||||
OPT_LOADSTORE = optimize unneeded load/stores
|
||||
MAP_ALL = (MAP_TYPES | MAP_NAMES | MAP_FUNCS)
|
||||
DCE_ALL = (DCE_FUNCS | DCE_VARS | DCE_TYPES)
|
||||
OPT_ALL = (OPT_LOADSTORE)
|
||||
ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL)
|
||||
DO_EVERYTHING = (STRIP | ALL_BUT_STRIP)
|
||||
|
||||
@@ -1,442 +0,0 @@
|
||||
# News
|
||||
|
||||
[](https://travis-ci.org/KhronosGroup/glslang)
|
||||
[](https://ci.appveyor.com/project/Khronoswebmaster/glslang/branch/master)
|
||||
|
||||
## Planned Deprecations/Removals
|
||||
|
||||
1. **SPIRV Folder, 1-May, 2020.** Glslang, when installed through CMake,
|
||||
will install a `SPIRV` folder into `${CMAKE_INSTALL_INCLUDEDIR}`.
|
||||
This `SPIRV` folder is being moved to `glslang/SPIRV`.
|
||||
During the transition the `SPIRV` folder will be installed into both locations.
|
||||
The old install of `SPIRV/` will be removed as a CMake install target no sooner than May 1, 2020.
|
||||
See issue #1964.
|
||||
|
||||
2. **Visual Studio 2013, 20-July, 2020.** Keeping code compiling for MS Visual Studio 2013 will no longer be
|
||||
a goal as of July 20, 2020, the fifth anniversary of the release of Visual Studio 2015.
|
||||
|
||||
# Glslang Components and Status
|
||||
|
||||
There are several components:
|
||||
|
||||
### Reference Validator and GLSL/ESSL -> AST Front End
|
||||
|
||||
An OpenGL GLSL and OpenGL|ES GLSL (ESSL) front-end for reference validation and translation of GLSL/ESSL into an internal abstract syntax tree (AST).
|
||||
|
||||
**Status**: Virtually complete, with results carrying similar weight as the specifications.
|
||||
|
||||
### HLSL -> AST Front End
|
||||
|
||||
An HLSL front-end for translation of an approximation of HLSL to glslang's AST form.
|
||||
|
||||
**Status**: Partially complete. Semantics are not reference quality and input is not validated.
|
||||
This is in contrast to the [DXC project](https://github.com/Microsoft/DirectXShaderCompiler), which receives a much larger investment and attempts to have definitive/reference-level semantics.
|
||||
|
||||
See [issue 362](https://github.com/KhronosGroup/glslang/issues/362) and [issue 701](https://github.com/KhronosGroup/glslang/issues/701) for current status.
|
||||
|
||||
### AST -> SPIR-V Back End
|
||||
|
||||
Translates glslang's AST to the Khronos-specified SPIR-V intermediate language.
|
||||
|
||||
**Status**: Virtually complete.
|
||||
|
||||
### Reflector
|
||||
|
||||
An API for getting reflection information from the AST, reflection types/variables/etc. from the HLL source (not the SPIR-V).
|
||||
|
||||
**Status**: There is a large amount of functionality present, but no specification/goal to measure completeness against. It is accurate for the input HLL and AST, but only approximate for what would later be emitted for SPIR-V.
|
||||
|
||||
### Standalone Wrapper
|
||||
|
||||
`glslangValidator` is command-line tool for accessing the functionality above.
|
||||
|
||||
Status: Complete.
|
||||
|
||||
Tasks waiting to be done are documented as GitHub issues.
|
||||
|
||||
## Other References
|
||||
|
||||
Also see the Khronos landing page for glslang as a reference front end:
|
||||
|
||||
https://www.khronos.org/opengles/sdk/tools/Reference-Compiler/
|
||||
|
||||
The above page, while not kept up to date, includes additional information regarding glslang as a reference validator.
|
||||
|
||||
# How to Use Glslang
|
||||
|
||||
## Execution of Standalone Wrapper
|
||||
|
||||
To use the standalone binary form, execute `glslangValidator`, and it will print
|
||||
a usage statement. Basic operation is to give it a file containing a shader,
|
||||
and it will print out warnings/errors and optionally an AST.
|
||||
|
||||
The applied stage-specific rules are based on the file extension:
|
||||
* `.vert` for a vertex shader
|
||||
* `.tesc` for a tessellation control shader
|
||||
* `.tese` for a tessellation evaluation shader
|
||||
* `.geom` for a geometry shader
|
||||
* `.frag` for a fragment shader
|
||||
* `.comp` for a compute shader
|
||||
|
||||
There is also a non-shader extension
|
||||
* `.conf` for a configuration file of limits, see usage statement for example
|
||||
|
||||
## Building
|
||||
|
||||
Instead of building manually, you can also download the binaries for your
|
||||
platform directly from the [master-tot release][master-tot-release] on GitHub.
|
||||
Those binaries are automatically uploaded by the buildbots after successful
|
||||
testing and they always reflect the current top of the tree of the master
|
||||
branch.
|
||||
|
||||
### Dependencies
|
||||
|
||||
* A C++11 compiler.
|
||||
(For MSVS: 2015 is recommended, 2013 is fully supported/tested, and 2010 support is attempted, but not tested.)
|
||||
* [CMake][cmake]: for generating compilation targets.
|
||||
* make: _Linux_, ninja is an alternative, if configured.
|
||||
* [Python 3.x][python]: for executing SPIRV-Tools scripts. (Optional if not using SPIRV-Tools and the 'External' subdirectory does not exist.)
|
||||
* [bison][bison]: _optional_, but needed when changing the grammar (glslang.y).
|
||||
* [googletest][googletest]: _optional_, but should use if making any changes to glslang.
|
||||
|
||||
### Build steps
|
||||
|
||||
The following steps assume a Bash shell. On Windows, that could be the Git Bash
|
||||
shell or some other shell of your choosing.
|
||||
|
||||
#### 1) Check-Out this project
|
||||
|
||||
```bash
|
||||
cd <parent of where you want glslang to be>
|
||||
git clone https://github.com/KhronosGroup/glslang.git
|
||||
```
|
||||
|
||||
#### 2) Check-Out External Projects
|
||||
|
||||
```bash
|
||||
cd <the directory glslang was cloned to, "External" will be a subdirectory>
|
||||
git clone https://github.com/google/googletest.git External/googletest
|
||||
```
|
||||
|
||||
If you want to use googletest with Visual Studio 2013, you also need to check out an older version:
|
||||
|
||||
```bash
|
||||
# to use googletest with Visual Studio 2013
|
||||
cd External/googletest
|
||||
git checkout 440527a61e1c91188195f7de212c63c77e8f0a45
|
||||
cd ../..
|
||||
```
|
||||
|
||||
If you wish to assure that SPIR-V generated from HLSL is legal for Vulkan,
|
||||
wish to invoke -Os to reduce SPIR-V size from HLSL or GLSL, or wish to run the
|
||||
integrated test suite, install spirv-tools with this:
|
||||
|
||||
```bash
|
||||
./update_glslang_sources.py
|
||||
```
|
||||
|
||||
#### 3) Configure
|
||||
|
||||
Assume the source directory is `$SOURCE_DIR` and the build directory is
|
||||
`$BUILD_DIR`. First ensure the build directory exists, then navigate to it:
|
||||
|
||||
```bash
|
||||
mkdir -p $BUILD_DIR
|
||||
cd $BUILD_DIR
|
||||
```
|
||||
|
||||
For building on Linux:
|
||||
|
||||
```bash
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$(pwd)/install" $SOURCE_DIR
|
||||
# "Release" (for CMAKE_BUILD_TYPE) could also be "Debug" or "RelWithDebInfo"
|
||||
```
|
||||
|
||||
For building on Android:
|
||||
```bash
|
||||
cmake $SOURCE_DIR -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="$(pwd)/install" -DANDROID_ABI=arm64-v8a -DCMAKE_BUILD_TYPE=Release -DANDROID_STL=c++_static -DANDROID_PLATFORM=android-24 -DCMAKE_SYSTEM_NAME=Android -DANDROID_TOOLCHAIN=clang -DANDROID_ARM_MODE=arm -DCMAKE_MAKE_PROGRAM=$ANDROID_NDK_ROOT/prebuilt/linux-x86_64/bin/make -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake
|
||||
# If on Windows will be -DCMAKE_MAKE_PROGRAM=%ANDROID_NDK_ROOT%\prebuilt\windows-x86_64\bin\make.exe
|
||||
# -G is needed for building on Windows
|
||||
# -DANDROID_ABI can also be armeabi-v7a for 32 bit
|
||||
```
|
||||
|
||||
For building on Windows:
|
||||
|
||||
```bash
|
||||
cmake $SOURCE_DIR -DCMAKE_INSTALL_PREFIX="$(pwd)/install"
|
||||
# The CMAKE_INSTALL_PREFIX part is for testing (explained later).
|
||||
```
|
||||
|
||||
The CMake GUI also works for Windows (version 3.4.1 tested).
|
||||
|
||||
Also, consider using `git config --global core.fileMode false` (or with `--local`) on Windows
|
||||
to prevent the addition of execution permission on files.
|
||||
|
||||
#### 4) Build and Install
|
||||
|
||||
```bash
|
||||
# for Linux:
|
||||
make -j4 install
|
||||
|
||||
# for Windows:
|
||||
cmake --build . --config Release --target install
|
||||
# "Release" (for --config) could also be "Debug", "MinSizeRel", or "RelWithDebInfo"
|
||||
```
|
||||
|
||||
If using MSVC, after running CMake to configure, use the
|
||||
Configuration Manager to check the `INSTALL` project.
|
||||
|
||||
### If you need to change the GLSL grammar
|
||||
|
||||
The grammar in `glslang/MachineIndependent/glslang.y` has to be recompiled with
|
||||
bison if it changes, the output files are committed to the repo to avoid every
|
||||
developer needing to have bison configured to compile the project when grammar
|
||||
changes are quite infrequent. For windows you can get binaries from
|
||||
[GnuWin32][bison-gnu-win32].
|
||||
|
||||
The command to rebuild is:
|
||||
|
||||
```bash
|
||||
m4 -P MachineIndependent/glslang.m4 > MachineIndependent/glslang.y
|
||||
bison --defines=MachineIndependent/glslang_tab.cpp.h
|
||||
-t MachineIndependent/glslang.y
|
||||
-o MachineIndependent/glslang_tab.cpp
|
||||
```
|
||||
|
||||
The above commands are also available in the bash script in `updateGrammar`,
|
||||
when executed from the glslang subdirectory of the glslang repository.
|
||||
With no arguments it builds the full grammar, and with a "web" argument,
|
||||
the web grammar subset (see more about the web subset in the next section).
|
||||
|
||||
### Building to WASM for the Web and Node
|
||||
### Building a standalone JS/WASM library for the Web and Node
|
||||
|
||||
Use the steps in [Build Steps](#build-steps), with the following notes/exceptions:
|
||||
* `emsdk` needs to be present in your executable search path, *PATH* for
|
||||
Bash-like environments:
|
||||
+ [Instructions located here](https://emscripten.org/docs/getting_started/downloads.html#sdk-download-and-install)
|
||||
* Wrap cmake call: `emcmake cmake`
|
||||
* Set `-DBUILD_TESTING=OFF -DENABLE_OPT=OFF -DINSTALL_GTEST=OFF`.
|
||||
* Set `-DENABLE_HLSL=OFF` if HLSL is not needed.
|
||||
* For a standalone JS/WASM library, turn on `-DENABLE_GLSLANG_JS=ON`.
|
||||
* For building a minimum-size web subset of core glslang:
|
||||
+ turn on `-DENABLE_GLSLANG_WEBMIN=ON` (disables HLSL)
|
||||
+ execute `updateGrammar web` from the glslang subdirectory
|
||||
(or if using your own scripts, `m4` needs a `-DGLSLANG_WEB` argument)
|
||||
+ optionally, for GLSL compilation error messages, turn on
|
||||
`-DENABLE_GLSLANG_WEBMIN_DEVEL=ON`
|
||||
* To get a fully minimized build, make sure to use `brotli` to compress the .js
|
||||
and .wasm files
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
emcmake cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_GLSLANG_JS=ON \
|
||||
-DENABLE_HLSL=OFF -DBUILD_TESTING=OFF -DENABLE_OPT=OFF -DINSTALL_GTEST=OFF ..
|
||||
```
|
||||
|
||||
## Building glslang - Using vcpkg
|
||||
|
||||
You can download and install glslang using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
|
||||
|
||||
git clone https://github.com/Microsoft/vcpkg.git
|
||||
cd vcpkg
|
||||
./bootstrap-vcpkg.sh
|
||||
./vcpkg integrate install
|
||||
./vcpkg install glslang
|
||||
|
||||
The glslang port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
|
||||
|
||||
## Testing
|
||||
|
||||
Right now, there are two test harnesses existing in glslang: one is [Google
|
||||
Test](gtests/), one is the [`runtests` script](Test/runtests). The former
|
||||
runs unit tests and single-shader single-threaded integration tests, while
|
||||
the latter runs multiple-shader linking tests and multi-threaded tests.
|
||||
|
||||
### Running tests
|
||||
|
||||
The [`runtests` script](Test/runtests) requires compiled binaries to be
|
||||
installed into `$BUILD_DIR/install`. Please make sure you have supplied the
|
||||
correct configuration to CMake (using `-DCMAKE_INSTALL_PREFIX`) when building;
|
||||
otherwise, you may want to modify the path in the `runtests` script.
|
||||
|
||||
Running Google Test-backed tests:
|
||||
|
||||
```bash
|
||||
cd $BUILD_DIR
|
||||
|
||||
# for Linux:
|
||||
ctest
|
||||
|
||||
# for Windows:
|
||||
ctest -C {Debug|Release|RelWithDebInfo|MinSizeRel}
|
||||
|
||||
# or, run the test binary directly
|
||||
# (which gives more fine-grained control like filtering):
|
||||
<dir-to-glslangtests-in-build-dir>/glslangtests
|
||||
```
|
||||
|
||||
Running `runtests` script-backed tests:
|
||||
|
||||
```bash
|
||||
cd $SOURCE_DIR/Test && ./runtests
|
||||
```
|
||||
|
||||
If some tests fail with validation errors, there may be a mismatch between the
|
||||
version of `spirv-val` on the system and the version of glslang. In this
|
||||
case, it is necessary to run `update_glslang_sources.py`. See "Check-Out
|
||||
External Projects" above for more details.
|
||||
|
||||
### Contributing tests
|
||||
|
||||
Test results should always be included with a pull request that modifies
|
||||
functionality.
|
||||
|
||||
If you are writing unit tests, please use the Google Test framework and
|
||||
place the tests under the `gtests/` directory.
|
||||
|
||||
Integration tests are placed in the `Test/` directory. It contains test input
|
||||
and a subdirectory `baseResults/` that contains the expected results of the
|
||||
tests. Both the tests and `baseResults/` are under source-code control.
|
||||
|
||||
Google Test runs those integration tests by reading the test input, compiling
|
||||
them, and then compare against the expected results in `baseResults/`. The
|
||||
integration tests to run via Google Test is registered in various
|
||||
`gtests/*.FromFile.cpp` source files. `glslangtests` provides a command-line
|
||||
option `--update-mode`, which, if supplied, will overwrite the golden files
|
||||
under the `baseResults/` directory with real output from that invocation.
|
||||
For more information, please check `gtests/` directory's
|
||||
[README](gtests/README.md).
|
||||
|
||||
For the `runtests` script, it will generate current results in the
|
||||
`localResults/` directory and `diff` them against the `baseResults/`.
|
||||
When you want to update the tracked test results, they need to be
|
||||
copied from `localResults/` to `baseResults/`. This can be done by
|
||||
the `bump` shell script.
|
||||
|
||||
You can add your own private list of tests, not tracked publicly, by using
|
||||
`localtestlist` to list non-tracked tests. This is automatically read
|
||||
by `runtests` and included in the `diff` and `bump` process.
|
||||
|
||||
## Programmatic Interfaces
|
||||
|
||||
Another piece of software can programmatically translate shaders to an AST
|
||||
using one of two different interfaces:
|
||||
* A new C++ class-oriented interface, or
|
||||
* The original C functional interface
|
||||
|
||||
The `main()` in `StandAlone/StandAlone.cpp` shows examples using both styles.
|
||||
|
||||
### C++ Class Interface (new, preferred)
|
||||
|
||||
This interface is in roughly the last 1/3 of `ShaderLang.h`. It is in the
|
||||
glslang namespace and contains the following, here with suggested calls
|
||||
for generating SPIR-V:
|
||||
|
||||
```cxx
|
||||
const char* GetEsslVersionString();
|
||||
const char* GetGlslVersionString();
|
||||
bool InitializeProcess();
|
||||
void FinalizeProcess();
|
||||
|
||||
class TShader
|
||||
setStrings(...);
|
||||
setEnvInput(EShSourceHlsl or EShSourceGlsl, stage, EShClientVulkan or EShClientOpenGL, 100);
|
||||
setEnvClient(EShClientVulkan or EShClientOpenGL, EShTargetVulkan_1_0 or EShTargetVulkan_1_1 or EShTargetOpenGL_450);
|
||||
setEnvTarget(EShTargetSpv, EShTargetSpv_1_0 or EShTargetSpv_1_3);
|
||||
bool parse(...);
|
||||
const char* getInfoLog();
|
||||
|
||||
class TProgram
|
||||
void addShader(...);
|
||||
bool link(...);
|
||||
const char* getInfoLog();
|
||||
Reflection queries
|
||||
```
|
||||
|
||||
For just validating (not generating code), substitute these calls:
|
||||
|
||||
```cxx
|
||||
setEnvInput(EShSourceHlsl or EShSourceGlsl, stage, EShClientNone, 0);
|
||||
setEnvClient(EShClientNone, 0);
|
||||
setEnvTarget(EShTargetNone, 0);
|
||||
```
|
||||
|
||||
See `ShaderLang.h` and the usage of it in `StandAlone/StandAlone.cpp` for more
|
||||
details. There is a block comment giving more detail above the calls for
|
||||
`setEnvInput, setEnvClient, and setEnvTarget`.
|
||||
|
||||
### C Functional Interface (original)
|
||||
|
||||
This interface is in roughly the first 2/3 of `ShaderLang.h`, and referred to
|
||||
as the `Sh*()` interface, as all the entry points start `Sh`.
|
||||
|
||||
The `Sh*()` interface takes a "compiler" call-back object, which it calls after
|
||||
building call back that is passed the AST and can then execute a back end on it.
|
||||
|
||||
The following is a simplified resulting run-time call stack:
|
||||
|
||||
```c
|
||||
ShCompile(shader, compiler) -> compiler(AST) -> <back end>
|
||||
```
|
||||
|
||||
In practice, `ShCompile()` takes shader strings, default version, and
|
||||
warning/error and other options for controlling compilation.
|
||||
|
||||
## Basic Internal Operation
|
||||
|
||||
* Initial lexical analysis is done by the preprocessor in
|
||||
`MachineIndependent/Preprocessor`, and then refined by a GLSL scanner
|
||||
in `MachineIndependent/Scan.cpp`. There is currently no use of flex.
|
||||
|
||||
* Code is parsed using bison on `MachineIndependent/glslang.y` with the
|
||||
aid of a symbol table and an AST. The symbol table is not passed on to
|
||||
the back-end; the intermediate representation stands on its own.
|
||||
The tree is built by the grammar productions, many of which are
|
||||
offloaded into `ParseHelper.cpp`, and by `Intermediate.cpp`.
|
||||
|
||||
* The intermediate representation is very high-level, and represented
|
||||
as an in-memory tree. This serves to lose no information from the
|
||||
original program, and to have efficient transfer of the result from
|
||||
parsing to the back-end. In the AST, constants are propagated and
|
||||
folded, and a very small amount of dead code is eliminated.
|
||||
|
||||
To aid linking and reflection, the last top-level branch in the AST
|
||||
lists all global symbols.
|
||||
|
||||
* The primary algorithm of the back-end compiler is to traverse the
|
||||
tree (high-level intermediate representation), and create an internal
|
||||
object code representation. There is an example of how to do this
|
||||
in `MachineIndependent/intermOut.cpp`.
|
||||
|
||||
* Reduction of the tree to a linear byte-code style low-level intermediate
|
||||
representation is likely a good way to generate fully optimized code.
|
||||
|
||||
* There is currently some dead old-style linker-type code still lying around.
|
||||
|
||||
* Memory pool: parsing uses types derived from C++ `std` types, using a
|
||||
custom allocator that puts them in a memory pool. This makes allocation
|
||||
of individual container/contents just few cycles and deallocation free.
|
||||
This pool is popped after the AST is made and processed.
|
||||
|
||||
The use is simple: if you are going to call `new`, there are three cases:
|
||||
|
||||
- the object comes from the pool (its base class has the macro
|
||||
`POOL_ALLOCATOR_NEW_DELETE` in it) and you do not have to call `delete`
|
||||
|
||||
- it is a `TString`, in which case call `NewPoolTString()`, which gets
|
||||
it from the pool, and there is no corresponding `delete`
|
||||
|
||||
- the object does not come from the pool, and you have to do normal
|
||||
C++ memory management of what you `new`
|
||||
|
||||
* Features can be protected by version/extension/stage/profile:
|
||||
See the comment in `glslang/MachineIndependent/Versions.cpp`.
|
||||
|
||||
[cmake]: https://cmake.org/
|
||||
[python]: https://www.python.org/
|
||||
[bison]: https://www.gnu.org/software/bison/
|
||||
[googletest]: https://github.com/google/googletest
|
||||
[bison-gnu-win32]: http://gnuwin32.sourceforge.net/packages/bison.htm
|
||||
[master-tot-release]: https://github.com/KhronosGroup/glslang/releases/tag/master-tot
|
||||
@@ -1,103 +0,0 @@
|
||||
set(SOURCES
|
||||
GlslangToSpv.cpp
|
||||
InReadableOrder.cpp
|
||||
Logger.cpp
|
||||
SpvBuilder.cpp
|
||||
SpvPostProcess.cpp
|
||||
doc.cpp
|
||||
SpvTools.cpp
|
||||
disassemble.cpp)
|
||||
|
||||
set(SPVREMAP_SOURCES
|
||||
SPVRemapper.cpp
|
||||
doc.cpp)
|
||||
|
||||
set(HEADERS
|
||||
bitutils.h
|
||||
spirv.hpp
|
||||
GLSL.std.450.h
|
||||
GLSL.ext.EXT.h
|
||||
GLSL.ext.KHR.h
|
||||
GlslangToSpv.h
|
||||
hex_float.h
|
||||
Logger.h
|
||||
SpvBuilder.h
|
||||
spvIR.h
|
||||
doc.h
|
||||
SpvTools.h
|
||||
disassemble.h
|
||||
GLSL.ext.AMD.h
|
||||
GLSL.ext.NV.h
|
||||
NonSemanticDebugPrintf.h)
|
||||
|
||||
set(SPVREMAP_HEADERS
|
||||
SPVRemapper.h
|
||||
doc.h)
|
||||
|
||||
add_library(SPIRV ${LIB_TYPE} ${SOURCES} ${HEADERS})
|
||||
set_property(TARGET SPIRV PROPERTY FOLDER glslang)
|
||||
set_property(TARGET SPIRV PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
target_include_directories(SPIRV PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||
|
||||
if (ENABLE_SPVREMAPPER)
|
||||
add_library(SPVRemapper ${LIB_TYPE} ${SPVREMAP_SOURCES} ${SPVREMAP_HEADERS})
|
||||
set_property(TARGET SPVRemapper PROPERTY FOLDER glslang)
|
||||
set_property(TARGET SPVRemapper PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
|
||||
if(WIN32 AND BUILD_SHARED_LIBS)
|
||||
set_target_properties(SPIRV PROPERTIES PREFIX "")
|
||||
if (ENABLE_SPVREMAPPER)
|
||||
set_target_properties(SPVRemapper PROPERTIES PREFIX "")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_OPT)
|
||||
target_include_directories(SPIRV
|
||||
PRIVATE ${spirv-tools_SOURCE_DIR}/include
|
||||
PRIVATE ${spirv-tools_SOURCE_DIR}/source
|
||||
)
|
||||
target_link_libraries(SPIRV glslang SPIRV-Tools-opt)
|
||||
target_include_directories(SPIRV PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../External>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/External>)
|
||||
else()
|
||||
target_link_libraries(SPIRV glslang)
|
||||
endif(ENABLE_OPT)
|
||||
|
||||
if(WIN32)
|
||||
source_group("Source" FILES ${SOURCES} ${HEADERS})
|
||||
source_group("Source" FILES ${SPVREMAP_SOURCES} ${SPVREMAP_HEADERS})
|
||||
endif(WIN32)
|
||||
|
||||
if(ENABLE_GLSLANG_INSTALL)
|
||||
if(BUILD_SHARED_LIBS)
|
||||
if (ENABLE_SPVREMAPPER)
|
||||
install(TARGETS SPVRemapper EXPORT SPVRemapperTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
||||
install(TARGETS SPIRV EXPORT SPIRVTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
else()
|
||||
if (ENABLE_SPVREMAPPER)
|
||||
install(TARGETS SPVRemapper EXPORT SPVRemapperTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
||||
install(TARGETS SPIRV EXPORT SPIRVTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
||||
|
||||
if (ENABLE_SPVREMAPPER)
|
||||
install(EXPORT SPVRemapperTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
|
||||
endif()
|
||||
|
||||
install(EXPORT SPIRVTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
|
||||
|
||||
install(FILES ${HEADERS} ${SPVREMAP_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/SPIRV/)
|
||||
install(FILES ${HEADERS} ${SPVREMAP_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/glslang/SPIRV/)
|
||||
endif(ENABLE_GLSLANG_INSTALL)
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
** Copyright (c) 2014-2016 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and/or associated documentation files (the "Materials"),
|
||||
** to deal in the Materials without restriction, including without limitation
|
||||
** the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
** and/or sell copies of the Materials, and to permit persons to whom the
|
||||
** Materials are furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Materials.
|
||||
**
|
||||
** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
|
||||
** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
|
||||
** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
|
||||
** IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
#ifndef GLSLextAMD_H
|
||||
#define GLSLextAMD_H
|
||||
|
||||
static const int GLSLextAMDVersion = 100;
|
||||
static const int GLSLextAMDRevision = 7;
|
||||
|
||||
// SPV_AMD_shader_ballot
|
||||
static const char* const E_SPV_AMD_shader_ballot = "SPV_AMD_shader_ballot";
|
||||
|
||||
enum ShaderBallotAMD {
|
||||
ShaderBallotBadAMD = 0, // Don't use
|
||||
|
||||
SwizzleInvocationsAMD = 1,
|
||||
SwizzleInvocationsMaskedAMD = 2,
|
||||
WriteInvocationAMD = 3,
|
||||
MbcntAMD = 4,
|
||||
|
||||
ShaderBallotCountAMD
|
||||
};
|
||||
|
||||
// SPV_AMD_shader_trinary_minmax
|
||||
static const char* const E_SPV_AMD_shader_trinary_minmax = "SPV_AMD_shader_trinary_minmax";
|
||||
|
||||
enum ShaderTrinaryMinMaxAMD {
|
||||
ShaderTrinaryMinMaxBadAMD = 0, // Don't use
|
||||
|
||||
FMin3AMD = 1,
|
||||
UMin3AMD = 2,
|
||||
SMin3AMD = 3,
|
||||
FMax3AMD = 4,
|
||||
UMax3AMD = 5,
|
||||
SMax3AMD = 6,
|
||||
FMid3AMD = 7,
|
||||
UMid3AMD = 8,
|
||||
SMid3AMD = 9,
|
||||
|
||||
ShaderTrinaryMinMaxCountAMD
|
||||
};
|
||||
|
||||
// SPV_AMD_shader_explicit_vertex_parameter
|
||||
static const char* const E_SPV_AMD_shader_explicit_vertex_parameter = "SPV_AMD_shader_explicit_vertex_parameter";
|
||||
|
||||
enum ShaderExplicitVertexParameterAMD {
|
||||
ShaderExplicitVertexParameterBadAMD = 0, // Don't use
|
||||
|
||||
InterpolateAtVertexAMD = 1,
|
||||
|
||||
ShaderExplicitVertexParameterCountAMD
|
||||
};
|
||||
|
||||
// SPV_AMD_gcn_shader
|
||||
static const char* const E_SPV_AMD_gcn_shader = "SPV_AMD_gcn_shader";
|
||||
|
||||
enum GcnShaderAMD {
|
||||
GcnShaderBadAMD = 0, // Don't use
|
||||
|
||||
CubeFaceIndexAMD = 1,
|
||||
CubeFaceCoordAMD = 2,
|
||||
TimeAMD = 3,
|
||||
|
||||
GcnShaderCountAMD
|
||||
};
|
||||
|
||||
// SPV_AMD_gpu_shader_half_float
|
||||
static const char* const E_SPV_AMD_gpu_shader_half_float = "SPV_AMD_gpu_shader_half_float";
|
||||
|
||||
// SPV_AMD_texture_gather_bias_lod
|
||||
static const char* const E_SPV_AMD_texture_gather_bias_lod = "SPV_AMD_texture_gather_bias_lod";
|
||||
|
||||
// SPV_AMD_gpu_shader_int16
|
||||
static const char* const E_SPV_AMD_gpu_shader_int16 = "SPV_AMD_gpu_shader_int16";
|
||||
|
||||
// SPV_AMD_shader_image_load_store_lod
|
||||
static const char* const E_SPV_AMD_shader_image_load_store_lod = "SPV_AMD_shader_image_load_store_lod";
|
||||
|
||||
// SPV_AMD_shader_fragment_mask
|
||||
static const char* const E_SPV_AMD_shader_fragment_mask = "SPV_AMD_shader_fragment_mask";
|
||||
|
||||
// SPV_AMD_gpu_shader_half_float_fetch
|
||||
static const char* const E_SPV_AMD_gpu_shader_half_float_fetch = "SPV_AMD_gpu_shader_half_float_fetch";
|
||||
|
||||
#endif // #ifndef GLSLextAMD_H
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
** Copyright (c) 2014-2016 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and/or associated documentation files (the "Materials"),
|
||||
** to deal in the Materials without restriction, including without limitation
|
||||
** the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
** and/or sell copies of the Materials, and to permit persons to whom the
|
||||
** Materials are furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Materials.
|
||||
**
|
||||
** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
|
||||
** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
|
||||
** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
|
||||
** IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
#ifndef GLSLextEXT_H
|
||||
#define GLSLextEXT_H
|
||||
|
||||
static const int GLSLextEXTVersion = 100;
|
||||
static const int GLSLextEXTRevision = 2;
|
||||
|
||||
static const char* const E_SPV_EXT_shader_stencil_export = "SPV_EXT_shader_stencil_export";
|
||||
static const char* const E_SPV_EXT_shader_viewport_index_layer = "SPV_EXT_shader_viewport_index_layer";
|
||||
static const char* const E_SPV_EXT_fragment_fully_covered = "SPV_EXT_fragment_fully_covered";
|
||||
static const char* const E_SPV_EXT_fragment_invocation_density = "SPV_EXT_fragment_invocation_density";
|
||||
static const char* const E_SPV_EXT_demote_to_helper_invocation = "SPV_EXT_demote_to_helper_invocation";
|
||||
|
||||
#endif // #ifndef GLSLextEXT_H
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
** Copyright (c) 2014-2020 The Khronos Group Inc.
|
||||
** Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and/or associated documentation files (the "Materials"),
|
||||
** to deal in the Materials without restriction, including without limitation
|
||||
** the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
** and/or sell copies of the Materials, and to permit persons to whom the
|
||||
** Materials are furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Materials.
|
||||
**
|
||||
** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
|
||||
** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
|
||||
** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
|
||||
** IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
#ifndef GLSLextKHR_H
|
||||
#define GLSLextKHR_H
|
||||
|
||||
static const int GLSLextKHRVersion = 100;
|
||||
static const int GLSLextKHRRevision = 2;
|
||||
|
||||
static const char* const E_SPV_KHR_shader_ballot = "SPV_KHR_shader_ballot";
|
||||
static const char* const E_SPV_KHR_subgroup_vote = "SPV_KHR_subgroup_vote";
|
||||
static const char* const E_SPV_KHR_device_group = "SPV_KHR_device_group";
|
||||
static const char* const E_SPV_KHR_multiview = "SPV_KHR_multiview";
|
||||
static const char* const E_SPV_KHR_shader_draw_parameters = "SPV_KHR_shader_draw_parameters";
|
||||
static const char* const E_SPV_KHR_16bit_storage = "SPV_KHR_16bit_storage";
|
||||
static const char* const E_SPV_KHR_8bit_storage = "SPV_KHR_8bit_storage";
|
||||
static const char* const E_SPV_KHR_storage_buffer_storage_class = "SPV_KHR_storage_buffer_storage_class";
|
||||
static const char* const E_SPV_KHR_post_depth_coverage = "SPV_KHR_post_depth_coverage";
|
||||
static const char* const E_SPV_KHR_vulkan_memory_model = "SPV_KHR_vulkan_memory_model";
|
||||
static const char* const E_SPV_EXT_physical_storage_buffer = "SPV_EXT_physical_storage_buffer";
|
||||
static const char* const E_SPV_KHR_physical_storage_buffer = "SPV_KHR_physical_storage_buffer";
|
||||
static const char* const E_SPV_EXT_fragment_shader_interlock = "SPV_EXT_fragment_shader_interlock";
|
||||
static const char* const E_SPV_KHR_shader_clock = "SPV_KHR_shader_clock";
|
||||
static const char* const E_SPV_KHR_non_semantic_info = "SPV_KHR_non_semantic_info";
|
||||
static const char* const E_SPV_KHR_ray_tracing = "SPV_KHR_ray_tracing";
|
||||
static const char* const E_SPV_KHR_ray_query = "SPV_KHR_ray_query";
|
||||
#endif // #ifndef GLSLextKHR_H
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
** Copyright (c) 2014-2017 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and/or associated documentation files (the "Materials"),
|
||||
** to deal in the Materials without restriction, including without limitation
|
||||
** the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
** and/or sell copies of the Materials, and to permit persons to whom the
|
||||
** Materials are furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Materials.
|
||||
**
|
||||
** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
|
||||
** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
|
||||
** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
|
||||
** IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
#ifndef GLSLextNV_H
|
||||
#define GLSLextNV_H
|
||||
|
||||
enum BuiltIn;
|
||||
enum Decoration;
|
||||
enum Op;
|
||||
enum Capability;
|
||||
|
||||
static const int GLSLextNVVersion = 100;
|
||||
static const int GLSLextNVRevision = 11;
|
||||
|
||||
//SPV_NV_sample_mask_override_coverage
|
||||
const char* const E_SPV_NV_sample_mask_override_coverage = "SPV_NV_sample_mask_override_coverage";
|
||||
|
||||
//SPV_NV_geometry_shader_passthrough
|
||||
const char* const E_SPV_NV_geometry_shader_passthrough = "SPV_NV_geometry_shader_passthrough";
|
||||
|
||||
//SPV_NV_viewport_array2
|
||||
const char* const E_SPV_NV_viewport_array2 = "SPV_NV_viewport_array2";
|
||||
const char* const E_ARB_shader_viewport_layer_array = "SPV_ARB_shader_viewport_layer_array";
|
||||
|
||||
//SPV_NV_stereo_view_rendering
|
||||
const char* const E_SPV_NV_stereo_view_rendering = "SPV_NV_stereo_view_rendering";
|
||||
|
||||
//SPV_NVX_multiview_per_view_attributes
|
||||
const char* const E_SPV_NVX_multiview_per_view_attributes = "SPV_NVX_multiview_per_view_attributes";
|
||||
|
||||
//SPV_NV_shader_subgroup_partitioned
|
||||
const char* const E_SPV_NV_shader_subgroup_partitioned = "SPV_NV_shader_subgroup_partitioned";
|
||||
|
||||
//SPV_NV_fragment_shader_barycentric
|
||||
const char* const E_SPV_NV_fragment_shader_barycentric = "SPV_NV_fragment_shader_barycentric";
|
||||
|
||||
//SPV_NV_compute_shader_derivatives
|
||||
const char* const E_SPV_NV_compute_shader_derivatives = "SPV_NV_compute_shader_derivatives";
|
||||
|
||||
//SPV_NV_shader_image_footprint
|
||||
const char* const E_SPV_NV_shader_image_footprint = "SPV_NV_shader_image_footprint";
|
||||
|
||||
//SPV_NV_mesh_shader
|
||||
const char* const E_SPV_NV_mesh_shader = "SPV_NV_mesh_shader";
|
||||
|
||||
//SPV_NV_raytracing
|
||||
const char* const E_SPV_NV_ray_tracing = "SPV_NV_ray_tracing";
|
||||
|
||||
//SPV_NV_shading_rate
|
||||
const char* const E_SPV_NV_shading_rate = "SPV_NV_shading_rate";
|
||||
|
||||
//SPV_NV_cooperative_matrix
|
||||
const char* const E_SPV_NV_cooperative_matrix = "SPV_NV_cooperative_matrix";
|
||||
|
||||
//SPV_NV_shader_sm_builtins
|
||||
const char* const E_SPV_NV_shader_sm_builtins = "SPV_NV_shader_sm_builtins";
|
||||
|
||||
#endif // #ifndef GLSLextNV_H
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
** Copyright (c) 2014-2016 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
** of this software and/or associated documentation files (the "Materials"),
|
||||
** to deal in the Materials without restriction, including without limitation
|
||||
** the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
** and/or sell copies of the Materials, and to permit persons to whom the
|
||||
** Materials are furnished to do so, subject to the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Materials.
|
||||
**
|
||||
** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
|
||||
** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
|
||||
** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
** FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
|
||||
** IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
#ifndef GLSLstd450_H
|
||||
#define GLSLstd450_H
|
||||
|
||||
static const int GLSLstd450Version = 100;
|
||||
static const int GLSLstd450Revision = 1;
|
||||
|
||||
enum GLSLstd450 {
|
||||
GLSLstd450Bad = 0, // Don't use
|
||||
|
||||
GLSLstd450Round = 1,
|
||||
GLSLstd450RoundEven = 2,
|
||||
GLSLstd450Trunc = 3,
|
||||
GLSLstd450FAbs = 4,
|
||||
GLSLstd450SAbs = 5,
|
||||
GLSLstd450FSign = 6,
|
||||
GLSLstd450SSign = 7,
|
||||
GLSLstd450Floor = 8,
|
||||
GLSLstd450Ceil = 9,
|
||||
GLSLstd450Fract = 10,
|
||||
|
||||
GLSLstd450Radians = 11,
|
||||
GLSLstd450Degrees = 12,
|
||||
GLSLstd450Sin = 13,
|
||||
GLSLstd450Cos = 14,
|
||||
GLSLstd450Tan = 15,
|
||||
GLSLstd450Asin = 16,
|
||||
GLSLstd450Acos = 17,
|
||||
GLSLstd450Atan = 18,
|
||||
GLSLstd450Sinh = 19,
|
||||
GLSLstd450Cosh = 20,
|
||||
GLSLstd450Tanh = 21,
|
||||
GLSLstd450Asinh = 22,
|
||||
GLSLstd450Acosh = 23,
|
||||
GLSLstd450Atanh = 24,
|
||||
GLSLstd450Atan2 = 25,
|
||||
|
||||
GLSLstd450Pow = 26,
|
||||
GLSLstd450Exp = 27,
|
||||
GLSLstd450Log = 28,
|
||||
GLSLstd450Exp2 = 29,
|
||||
GLSLstd450Log2 = 30,
|
||||
GLSLstd450Sqrt = 31,
|
||||
GLSLstd450InverseSqrt = 32,
|
||||
|
||||
GLSLstd450Determinant = 33,
|
||||
GLSLstd450MatrixInverse = 34,
|
||||
|
||||
GLSLstd450Modf = 35, // second operand needs an OpVariable to write to
|
||||
GLSLstd450ModfStruct = 36, // no OpVariable operand
|
||||
GLSLstd450FMin = 37,
|
||||
GLSLstd450UMin = 38,
|
||||
GLSLstd450SMin = 39,
|
||||
GLSLstd450FMax = 40,
|
||||
GLSLstd450UMax = 41,
|
||||
GLSLstd450SMax = 42,
|
||||
GLSLstd450FClamp = 43,
|
||||
GLSLstd450UClamp = 44,
|
||||
GLSLstd450SClamp = 45,
|
||||
GLSLstd450FMix = 46,
|
||||
GLSLstd450IMix = 47, // Reserved
|
||||
GLSLstd450Step = 48,
|
||||
GLSLstd450SmoothStep = 49,
|
||||
|
||||
GLSLstd450Fma = 50,
|
||||
GLSLstd450Frexp = 51, // second operand needs an OpVariable to write to
|
||||
GLSLstd450FrexpStruct = 52, // no OpVariable operand
|
||||
GLSLstd450Ldexp = 53,
|
||||
|
||||
GLSLstd450PackSnorm4x8 = 54,
|
||||
GLSLstd450PackUnorm4x8 = 55,
|
||||
GLSLstd450PackSnorm2x16 = 56,
|
||||
GLSLstd450PackUnorm2x16 = 57,
|
||||
GLSLstd450PackHalf2x16 = 58,
|
||||
GLSLstd450PackDouble2x32 = 59,
|
||||
GLSLstd450UnpackSnorm2x16 = 60,
|
||||
GLSLstd450UnpackUnorm2x16 = 61,
|
||||
GLSLstd450UnpackHalf2x16 = 62,
|
||||
GLSLstd450UnpackSnorm4x8 = 63,
|
||||
GLSLstd450UnpackUnorm4x8 = 64,
|
||||
GLSLstd450UnpackDouble2x32 = 65,
|
||||
|
||||
GLSLstd450Length = 66,
|
||||
GLSLstd450Distance = 67,
|
||||
GLSLstd450Cross = 68,
|
||||
GLSLstd450Normalize = 69,
|
||||
GLSLstd450FaceForward = 70,
|
||||
GLSLstd450Reflect = 71,
|
||||
GLSLstd450Refract = 72,
|
||||
|
||||
GLSLstd450FindILsb = 73,
|
||||
GLSLstd450FindSMsb = 74,
|
||||
GLSLstd450FindUMsb = 75,
|
||||
|
||||
GLSLstd450InterpolateAtCentroid = 76,
|
||||
GLSLstd450InterpolateAtSample = 77,
|
||||
GLSLstd450InterpolateAtOffset = 78,
|
||||
|
||||
GLSLstd450NMin = 79,
|
||||
GLSLstd450NMax = 80,
|
||||
GLSLstd450NClamp = 81,
|
||||
|
||||
GLSLstd450Count
|
||||
};
|
||||
|
||||
#endif // #ifndef GLSLstd450_H
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,61 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2014 LunarG, Inc.
|
||||
// Copyright (C) 2015-2018 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
#pragma warning(disable : 4464) // relative include path contains '..'
|
||||
#endif
|
||||
|
||||
#include "SpvTools.h"
|
||||
#include "glslang/Include/intermediate.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
void GetSpirvVersion(std::string&);
|
||||
int GetSpirvGeneratorVersion();
|
||||
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
|
||||
SpvOptions* options = nullptr);
|
||||
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
|
||||
spv::SpvBuildLogger* logger, SpvOptions* options = nullptr);
|
||||
void OutputSpvBin(const std::vector<unsigned int>& spirv, const char* baseName);
|
||||
void OutputSpvHex(const std::vector<unsigned int>& spirv, const char* baseName, const char* varName);
|
||||
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2016 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// The SPIR-V spec requires code blocks to appear in an order satisfying the
|
||||
// dominator-tree direction (ie, dominator before the dominated). This is,
|
||||
// actually, easy to achieve: any pre-order CFG traversal algorithm will do it.
|
||||
// Because such algorithms visit a block only after traversing some path to it
|
||||
// from the root, they necessarily visit the block's idom first.
|
||||
//
|
||||
// But not every graph-traversal algorithm outputs blocks in an order that
|
||||
// appears logical to human readers. The problem is that unrelated branches may
|
||||
// be interspersed with each other, and merge blocks may come before some of the
|
||||
// branches being merged.
|
||||
//
|
||||
// A good, human-readable order of blocks may be achieved by performing
|
||||
// depth-first search but delaying merge nodes until after all their branches
|
||||
// have been visited. This is implemented below by the inReadableOrder()
|
||||
// function.
|
||||
|
||||
#include "spvIR.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <unordered_set>
|
||||
|
||||
using spv::Block;
|
||||
using spv::Id;
|
||||
|
||||
namespace {
|
||||
// Traverses CFG in a readable order, invoking a pre-set callback on each block.
|
||||
// Use by calling visit() on the root block.
|
||||
class ReadableOrderTraverser {
|
||||
public:
|
||||
ReadableOrderTraverser(std::function<void(Block*, spv::ReachReason, Block*)> callback)
|
||||
: callback_(callback) {}
|
||||
// Visits the block if it hasn't been visited already and isn't currently
|
||||
// being delayed. Invokes callback(block, why, header), then descends into its
|
||||
// successors. Delays merge-block and continue-block processing until all
|
||||
// the branches have been completed. If |block| is an unreachable merge block or
|
||||
// an unreachable continue target, then |header| is the corresponding header block.
|
||||
void visit(Block* block, spv::ReachReason why, Block* header)
|
||||
{
|
||||
assert(block);
|
||||
if (why == spv::ReachViaControlFlow) {
|
||||
reachableViaControlFlow_.insert(block);
|
||||
}
|
||||
if (visited_.count(block) || delayed_.count(block))
|
||||
return;
|
||||
callback_(block, why, header);
|
||||
visited_.insert(block);
|
||||
Block* mergeBlock = nullptr;
|
||||
Block* continueBlock = nullptr;
|
||||
auto mergeInst = block->getMergeInstruction();
|
||||
if (mergeInst) {
|
||||
Id mergeId = mergeInst->getIdOperand(0);
|
||||
mergeBlock = block->getParent().getParent().getInstruction(mergeId)->getBlock();
|
||||
delayed_.insert(mergeBlock);
|
||||
if (mergeInst->getOpCode() == spv::OpLoopMerge) {
|
||||
Id continueId = mergeInst->getIdOperand(1);
|
||||
continueBlock =
|
||||
block->getParent().getParent().getInstruction(continueId)->getBlock();
|
||||
delayed_.insert(continueBlock);
|
||||
}
|
||||
}
|
||||
if (why == spv::ReachViaControlFlow) {
|
||||
const auto& successors = block->getSuccessors();
|
||||
for (auto it = successors.cbegin(); it != successors.cend(); ++it)
|
||||
visit(*it, why, nullptr);
|
||||
}
|
||||
if (continueBlock) {
|
||||
const spv::ReachReason continueWhy =
|
||||
(reachableViaControlFlow_.count(continueBlock) > 0)
|
||||
? spv::ReachViaControlFlow
|
||||
: spv::ReachDeadContinue;
|
||||
delayed_.erase(continueBlock);
|
||||
visit(continueBlock, continueWhy, block);
|
||||
}
|
||||
if (mergeBlock) {
|
||||
const spv::ReachReason mergeWhy =
|
||||
(reachableViaControlFlow_.count(mergeBlock) > 0)
|
||||
? spv::ReachViaControlFlow
|
||||
: spv::ReachDeadMerge;
|
||||
delayed_.erase(mergeBlock);
|
||||
visit(mergeBlock, mergeWhy, block);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void(Block*, spv::ReachReason, Block*)> callback_;
|
||||
// Whether a block has already been visited or is being delayed.
|
||||
std::unordered_set<Block *> visited_, delayed_;
|
||||
|
||||
// The set of blocks that actually are reached via control flow.
|
||||
std::unordered_set<Block *> reachableViaControlFlow_;
|
||||
};
|
||||
}
|
||||
|
||||
void spv::inReadableOrder(Block* root, std::function<void(Block*, spv::ReachReason, Block*)> callback)
|
||||
{
|
||||
ReadableOrderTraverser(callback).visit(root, spv::ReachViaControlFlow, nullptr);
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2016 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GLSLANG_WEB
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
|
||||
namespace spv {
|
||||
|
||||
void SpvBuildLogger::tbdFunctionality(const std::string& f)
|
||||
{
|
||||
if (std::find(std::begin(tbdFeatures), std::end(tbdFeatures), f) == std::end(tbdFeatures))
|
||||
tbdFeatures.push_back(f);
|
||||
}
|
||||
|
||||
void SpvBuildLogger::missingFunctionality(const std::string& f)
|
||||
{
|
||||
if (std::find(std::begin(missingFeatures), std::end(missingFeatures), f) == std::end(missingFeatures))
|
||||
missingFeatures.push_back(f);
|
||||
}
|
||||
|
||||
std::string SpvBuildLogger::getAllMessages() const {
|
||||
std::ostringstream messages;
|
||||
for (auto it = tbdFeatures.cbegin(); it != tbdFeatures.cend(); ++it)
|
||||
messages << "TBD functionality: " << *it << "\n";
|
||||
for (auto it = missingFeatures.cbegin(); it != missingFeatures.cend(); ++it)
|
||||
messages << "Missing functionality: " << *it << "\n";
|
||||
for (auto it = warnings.cbegin(); it != warnings.cend(); ++it)
|
||||
messages << "warning: " << *it << "\n";
|
||||
for (auto it = errors.cbegin(); it != errors.cend(); ++it)
|
||||
messages << "error: " << *it << "\n";
|
||||
return messages.str();
|
||||
}
|
||||
|
||||
} // end spv namespace
|
||||
|
||||
#endif
|
||||
@@ -1,83 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2016 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GLSLANG_SPIRV_LOGGER_H
|
||||
#define GLSLANG_SPIRV_LOGGER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace spv {
|
||||
|
||||
// A class for holding all SPIR-V build status messages, including
|
||||
// missing/TBD functionalities, warnings, and errors.
|
||||
class SpvBuildLogger {
|
||||
public:
|
||||
SpvBuildLogger() {}
|
||||
|
||||
#ifdef GLSLANG_WEB
|
||||
void tbdFunctionality(const std::string& f) { }
|
||||
void missingFunctionality(const std::string& f) { }
|
||||
void warning(const std::string& w) { }
|
||||
void error(const std::string& e) { errors.push_back(e); }
|
||||
std::string getAllMessages() { return ""; }
|
||||
#else
|
||||
|
||||
// Registers a TBD functionality.
|
||||
void tbdFunctionality(const std::string& f);
|
||||
// Registers a missing functionality.
|
||||
void missingFunctionality(const std::string& f);
|
||||
|
||||
// Logs a warning.
|
||||
void warning(const std::string& w) { warnings.push_back(w); }
|
||||
// Logs an error.
|
||||
void error(const std::string& e) { errors.push_back(e); }
|
||||
|
||||
// Returns all messages accumulated in the order of:
|
||||
// TBD functionalities, missing functionalities, warnings, errors.
|
||||
std::string getAllMessages() const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
SpvBuildLogger(const SpvBuildLogger&);
|
||||
|
||||
std::vector<std::string> tbdFeatures;
|
||||
std::vector<std::string> missingFeatures;
|
||||
std::vector<std::string> warnings;
|
||||
std::vector<std::string> errors;
|
||||
};
|
||||
|
||||
} // end spv namespace
|
||||
|
||||
#endif // GLSLANG_SPIRV_LOGGER_H
|
||||
@@ -1,50 +0,0 @@
|
||||
// Copyright (c) 2020 The Khronos Group Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and/or associated documentation files (the
|
||||
// "Materials"), to deal in the Materials without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
// permit persons to whom the Materials are furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Materials.
|
||||
//
|
||||
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
|
||||
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
|
||||
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
|
||||
// https://www.khronos.org/registry/
|
||||
//
|
||||
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
//
|
||||
|
||||
#ifndef SPIRV_UNIFIED1_NonSemanticDebugPrintf_H_
|
||||
#define SPIRV_UNIFIED1_NonSemanticDebugPrintf_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
NonSemanticDebugPrintfRevision = 1,
|
||||
NonSemanticDebugPrintfRevision_BitWidthPadding = 0x7fffffff
|
||||
};
|
||||
|
||||
enum NonSemanticDebugPrintfInstructions {
|
||||
NonSemanticDebugPrintfDebugPrintf = 1,
|
||||
NonSemanticDebugPrintfInstructionsMax = 0x7fffffff
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SPIRV_UNIFIED1_NonSemanticDebugPrintf_H_
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,304 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2015 LunarG, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef SPIRVREMAPPER_H
|
||||
#define SPIRVREMAPPER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
|
||||
namespace spv {
|
||||
|
||||
// MSVC defines __cplusplus as an older value, even when it supports almost all of 11.
|
||||
// We handle that here by making our own symbol.
|
||||
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1700)
|
||||
# define use_cpp11 1
|
||||
#endif
|
||||
|
||||
class spirvbin_base_t
|
||||
{
|
||||
public:
|
||||
enum Options {
|
||||
NONE = 0,
|
||||
STRIP = (1<<0),
|
||||
MAP_TYPES = (1<<1),
|
||||
MAP_NAMES = (1<<2),
|
||||
MAP_FUNCS = (1<<3),
|
||||
DCE_FUNCS = (1<<4),
|
||||
DCE_VARS = (1<<5),
|
||||
DCE_TYPES = (1<<6),
|
||||
OPT_LOADSTORE = (1<<7),
|
||||
OPT_FWD_LS = (1<<8), // EXPERIMENTAL: PRODUCES INVALID SCHEMA-0 SPIRV
|
||||
MAP_ALL = (MAP_TYPES | MAP_NAMES | MAP_FUNCS),
|
||||
DCE_ALL = (DCE_FUNCS | DCE_VARS | DCE_TYPES),
|
||||
OPT_ALL = (OPT_LOADSTORE),
|
||||
|
||||
ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL),
|
||||
DO_EVERYTHING = (STRIP | ALL_BUT_STRIP)
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace SPV
|
||||
|
||||
#if !defined (use_cpp11)
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
|
||||
namespace spv {
|
||||
class spirvbin_t : public spirvbin_base_t
|
||||
{
|
||||
public:
|
||||
spirvbin_t(int /*verbose = 0*/) { }
|
||||
|
||||
void remap(std::vector<std::uint32_t>& /*spv*/, unsigned int /*opts = 0*/)
|
||||
{
|
||||
printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n");
|
||||
exit(5);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace SPV
|
||||
|
||||
#else // defined (use_cpp11)
|
||||
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
|
||||
#include "spirv.hpp"
|
||||
#include "spvIR.h"
|
||||
|
||||
namespace spv {
|
||||
|
||||
// class to hold SPIR-V binary data for remapping, DCE, and debug stripping
|
||||
class spirvbin_t : public spirvbin_base_t
|
||||
{
|
||||
public:
|
||||
spirvbin_t(int verbose = 0) : entryPoint(spv::NoResult), largestNewId(0), verbose(verbose), errorLatch(false)
|
||||
{ }
|
||||
|
||||
virtual ~spirvbin_t() { }
|
||||
|
||||
// remap on an existing binary in memory
|
||||
void remap(std::vector<std::uint32_t>& spv, std::uint32_t opts = DO_EVERYTHING);
|
||||
|
||||
// Type for error/log handler functions
|
||||
typedef std::function<void(const std::string&)> errorfn_t;
|
||||
typedef std::function<void(const std::string&)> logfn_t;
|
||||
|
||||
// Register error/log handling functions (can be lambda fn / functor / etc)
|
||||
static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; }
|
||||
static void registerLogHandler(logfn_t handler) { logHandler = handler; }
|
||||
|
||||
protected:
|
||||
// This can be overridden to provide other message behavior if needed
|
||||
virtual void msg(int minVerbosity, int indent, const std::string& txt) const;
|
||||
|
||||
private:
|
||||
// Local to global, or global to local ID map
|
||||
typedef std::unordered_map<spv::Id, spv::Id> idmap_t;
|
||||
typedef std::unordered_set<spv::Id> idset_t;
|
||||
typedef std::unordered_map<spv::Id, int> blockmap_t;
|
||||
|
||||
void remap(std::uint32_t opts = DO_EVERYTHING);
|
||||
|
||||
// Map of names to IDs
|
||||
typedef std::unordered_map<std::string, spv::Id> namemap_t;
|
||||
|
||||
typedef std::uint32_t spirword_t;
|
||||
|
||||
typedef std::pair<unsigned, unsigned> range_t;
|
||||
typedef std::function<void(spv::Id&)> idfn_t;
|
||||
typedef std::function<bool(spv::Op, unsigned start)> instfn_t;
|
||||
|
||||
// Special Values for ID map:
|
||||
static const spv::Id unmapped; // unchanged from default value
|
||||
static const spv::Id unused; // unused ID
|
||||
static const int header_size; // SPIR header = 5 words
|
||||
|
||||
class id_iterator_t;
|
||||
|
||||
// For mapping type entries between different shaders
|
||||
typedef std::vector<spirword_t> typeentry_t;
|
||||
typedef std::map<spv::Id, typeentry_t> globaltypes_t;
|
||||
|
||||
// A set that preserves position order, and a reverse map
|
||||
typedef std::set<int> posmap_t;
|
||||
typedef std::unordered_map<spv::Id, int> posmap_rev_t;
|
||||
|
||||
// Maps and ID to the size of its base type, if known.
|
||||
typedef std::unordered_map<spv::Id, unsigned> typesize_map_t;
|
||||
|
||||
// handle error
|
||||
void error(const std::string& txt) const { errorLatch = true; errorHandler(txt); }
|
||||
|
||||
bool isConstOp(spv::Op opCode) const;
|
||||
bool isTypeOp(spv::Op opCode) const;
|
||||
bool isStripOp(spv::Op opCode) const;
|
||||
bool isFlowCtrl(spv::Op opCode) const;
|
||||
range_t literalRange(spv::Op opCode) const;
|
||||
range_t typeRange(spv::Op opCode) const;
|
||||
range_t constRange(spv::Op opCode) const;
|
||||
unsigned typeSizeInWords(spv::Id id) const;
|
||||
unsigned idTypeSizeInWords(spv::Id id) const;
|
||||
|
||||
spv::Id& asId(unsigned word) { return spv[word]; }
|
||||
const spv::Id& asId(unsigned word) const { return spv[word]; }
|
||||
spv::Op asOpCode(unsigned word) const { return opOpCode(spv[word]); }
|
||||
std::uint32_t asOpCodeHash(unsigned word);
|
||||
spv::Decoration asDecoration(unsigned word) const { return spv::Decoration(spv[word]); }
|
||||
unsigned asWordCount(unsigned word) const { return opWordCount(spv[word]); }
|
||||
spv::Id asTypeConstId(unsigned word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }
|
||||
unsigned idPos(spv::Id id) const;
|
||||
|
||||
static unsigned opWordCount(spirword_t data) { return data >> spv::WordCountShift; }
|
||||
static spv::Op opOpCode(spirword_t data) { return spv::Op(data & spv::OpCodeMask); }
|
||||
|
||||
// Header access & set methods
|
||||
spirword_t magic() const { return spv[0]; } // return magic number
|
||||
spirword_t bound() const { return spv[3]; } // return Id bound from header
|
||||
spirword_t bound(spirword_t b) { return spv[3] = b; }
|
||||
spirword_t genmagic() const { return spv[2]; } // generator magic
|
||||
spirword_t genmagic(spirword_t m) { return spv[2] = m; }
|
||||
spirword_t schemaNum() const { return spv[4]; } // schema number from header
|
||||
|
||||
// Mapping fns: get
|
||||
spv::Id localId(spv::Id id) const { return idMapL[id]; }
|
||||
|
||||
// Mapping fns: set
|
||||
inline spv::Id localId(spv::Id id, spv::Id newId);
|
||||
void countIds(spv::Id id);
|
||||
|
||||
// Return next unused new local ID.
|
||||
// NOTE: boost::dynamic_bitset would be more efficient due to find_next(),
|
||||
// which std::vector<bool> doens't have.
|
||||
inline spv::Id nextUnusedId(spv::Id id);
|
||||
|
||||
void buildLocalMaps();
|
||||
std::string literalString(unsigned word) const; // Return literal as a std::string
|
||||
int literalStringWords(const std::string& str) const { return (int(str.size())+4)/4; }
|
||||
|
||||
bool isNewIdMapped(spv::Id newId) const { return isMapped(newId); }
|
||||
bool isOldIdUnmapped(spv::Id oldId) const { return localId(oldId) == unmapped; }
|
||||
bool isOldIdUnused(spv::Id oldId) const { return localId(oldId) == unused; }
|
||||
bool isOldIdMapped(spv::Id oldId) const { return !isOldIdUnused(oldId) && !isOldIdUnmapped(oldId); }
|
||||
bool isFunction(spv::Id oldId) const { return fnPos.find(oldId) != fnPos.end(); }
|
||||
|
||||
// bool matchType(const globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const;
|
||||
// spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const;
|
||||
std::uint32_t hashType(unsigned typeStart) const;
|
||||
|
||||
spirvbin_t& process(instfn_t, idfn_t, unsigned begin = 0, unsigned end = 0);
|
||||
int processInstruction(unsigned word, instfn_t, idfn_t);
|
||||
|
||||
void validate() const;
|
||||
void mapTypeConst();
|
||||
void mapFnBodies();
|
||||
void optLoadStore();
|
||||
void dceFuncs();
|
||||
void dceVars();
|
||||
void dceTypes();
|
||||
void mapNames();
|
||||
void foldIds(); // fold IDs to smallest space
|
||||
void forwardLoadStores(); // load store forwarding (EXPERIMENTAL)
|
||||
void offsetIds(); // create relative offset IDs
|
||||
|
||||
void applyMap(); // remap per local name map
|
||||
void mapRemainder(); // map any IDs we haven't touched yet
|
||||
void stripDebug(); // strip all debug info
|
||||
void stripDeadRefs(); // strips debug info for now-dead references after DCE
|
||||
void strip(); // remove debug symbols
|
||||
|
||||
std::vector<spirword_t> spv; // SPIR words
|
||||
|
||||
namemap_t nameMap; // ID names from OpName
|
||||
|
||||
// Since we want to also do binary ops, we can't use std::vector<bool>. we could use
|
||||
// boost::dynamic_bitset, but we're trying to avoid a boost dependency.
|
||||
typedef std::uint64_t bits_t;
|
||||
std::vector<bits_t> mapped; // which new IDs have been mapped
|
||||
static const int mBits = sizeof(bits_t) * 4;
|
||||
|
||||
bool isMapped(spv::Id id) const { return id < maxMappedId() && ((mapped[id/mBits] & (1LL<<(id%mBits))) != 0); }
|
||||
void setMapped(spv::Id id) { resizeMapped(id); mapped[id/mBits] |= (1LL<<(id%mBits)); }
|
||||
void resizeMapped(spv::Id id) { if (id >= maxMappedId()) mapped.resize(id/mBits+1, 0); }
|
||||
size_t maxMappedId() const { return mapped.size() * mBits; }
|
||||
|
||||
// Add a strip range for a given instruction starting at 'start'
|
||||
// Note: avoiding brace initializers to please older versions os MSVC.
|
||||
void stripInst(unsigned start) { stripRange.push_back(range_t(start, start + asWordCount(start))); }
|
||||
|
||||
// Function start and end. use unordered_map because we'll have
|
||||
// many fewer functions than IDs.
|
||||
std::unordered_map<spv::Id, range_t> fnPos;
|
||||
|
||||
// Which functions are called, anywhere in the module, with a call count
|
||||
std::unordered_map<spv::Id, int> fnCalls;
|
||||
|
||||
posmap_t typeConstPos; // word positions that define types & consts (ordered)
|
||||
posmap_rev_t idPosR; // reverse map from IDs to positions
|
||||
typesize_map_t idTypeSizeMap; // maps each ID to its type size, if known.
|
||||
|
||||
std::vector<spv::Id> idMapL; // ID {M}ap from {L}ocal to {G}lobal IDs
|
||||
|
||||
spv::Id entryPoint; // module entry point
|
||||
spv::Id largestNewId; // biggest new ID we have mapped anything to
|
||||
|
||||
// Sections of the binary to strip, given as [begin,end)
|
||||
std::vector<range_t> stripRange;
|
||||
|
||||
// processing options:
|
||||
std::uint32_t options;
|
||||
int verbose; // verbosity level
|
||||
|
||||
// Error latch: this is set if the error handler is ever executed. It would be better to
|
||||
// use a try/catch block and throw, but that's not desired for certain environments, so
|
||||
// this is the alternative.
|
||||
mutable bool errorLatch;
|
||||
|
||||
static errorfn_t errorHandler;
|
||||
static logfn_t logHandler;
|
||||
};
|
||||
|
||||
} // namespace SPV
|
||||
|
||||
#endif // defined (use_cpp11)
|
||||
#endif // SPIRVREMAPPER_H
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,838 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2014-2015 LunarG, Inc.
|
||||
// Copyright (C) 2015-2020 Google, Inc.
|
||||
// Copyright (C) 2017 ARM Limited.
|
||||
// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//
|
||||
// "Builder" is an interface to fully build SPIR-V IR. Allocate one of
|
||||
// these to build (a thread safe) internal SPIR-V representation (IR),
|
||||
// and then dump it as a binary stream according to the SPIR-V specification.
|
||||
//
|
||||
// A Builder has a 1:1 relationship with a SPIR-V module.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef SpvBuilder_H
|
||||
#define SpvBuilder_H
|
||||
|
||||
#include "Logger.h"
|
||||
#include "spirv.hpp"
|
||||
#include "spvIR.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
|
||||
namespace spv {
|
||||
|
||||
typedef enum {
|
||||
Spv_1_0 = (1 << 16),
|
||||
Spv_1_1 = (1 << 16) | (1 << 8),
|
||||
Spv_1_2 = (1 << 16) | (2 << 8),
|
||||
Spv_1_3 = (1 << 16) | (3 << 8),
|
||||
Spv_1_4 = (1 << 16) | (4 << 8),
|
||||
Spv_1_5 = (1 << 16) | (5 << 8),
|
||||
} SpvVersion;
|
||||
|
||||
class Builder {
|
||||
public:
|
||||
Builder(unsigned int spvVersion, unsigned int userNumber, SpvBuildLogger* logger);
|
||||
virtual ~Builder();
|
||||
|
||||
static const int maxMatrixSize = 4;
|
||||
|
||||
unsigned int getSpvVersion() const { return spvVersion; }
|
||||
|
||||
void setSource(spv::SourceLanguage lang, int version)
|
||||
{
|
||||
source = lang;
|
||||
sourceVersion = version;
|
||||
}
|
||||
spv::Id getStringId(const std::string& str)
|
||||
{
|
||||
auto sItr = stringIds.find(str);
|
||||
if (sItr != stringIds.end())
|
||||
return sItr->second;
|
||||
spv::Id strId = getUniqueId();
|
||||
Instruction* fileString = new Instruction(strId, NoType, OpString);
|
||||
const char* file_c_str = str.c_str();
|
||||
fileString->addStringOperand(file_c_str);
|
||||
strings.push_back(std::unique_ptr<Instruction>(fileString));
|
||||
module.mapInstruction(fileString);
|
||||
stringIds[file_c_str] = strId;
|
||||
return strId;
|
||||
}
|
||||
void setSourceFile(const std::string& file)
|
||||
{
|
||||
sourceFileStringId = getStringId(file);
|
||||
}
|
||||
void setSourceText(const std::string& text) { sourceText = text; }
|
||||
void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); }
|
||||
void addModuleProcessed(const std::string& p) { moduleProcesses.push_back(p.c_str()); }
|
||||
void setEmitOpLines() { emitOpLines = true; }
|
||||
void addExtension(const char* ext) { extensions.insert(ext); }
|
||||
void removeExtension(const char* ext)
|
||||
{
|
||||
extensions.erase(ext);
|
||||
}
|
||||
void addIncorporatedExtension(const char* ext, SpvVersion incorporatedVersion)
|
||||
{
|
||||
if (getSpvVersion() < static_cast<unsigned>(incorporatedVersion))
|
||||
addExtension(ext);
|
||||
}
|
||||
void promoteIncorporatedExtension(const char* baseExt, const char* promoExt, SpvVersion incorporatedVersion)
|
||||
{
|
||||
removeExtension(baseExt);
|
||||
addIncorporatedExtension(promoExt, incorporatedVersion);
|
||||
}
|
||||
void addInclude(const std::string& name, const std::string& text)
|
||||
{
|
||||
spv::Id incId = getStringId(name);
|
||||
includeFiles[incId] = &text;
|
||||
}
|
||||
Id import(const char*);
|
||||
void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
|
||||
{
|
||||
addressModel = addr;
|
||||
memoryModel = mem;
|
||||
}
|
||||
|
||||
void addCapability(spv::Capability cap) { capabilities.insert(cap); }
|
||||
|
||||
// To get a new <id> for anything needing a new one.
|
||||
Id getUniqueId() { return ++uniqueId; }
|
||||
|
||||
// To get a set of new <id>s, e.g., for a set of function parameters
|
||||
Id getUniqueIds(int numIds)
|
||||
{
|
||||
Id id = uniqueId + 1;
|
||||
uniqueId += numIds;
|
||||
return id;
|
||||
}
|
||||
|
||||
// Generate OpLine for non-filename-based #line directives (ie no filename
|
||||
// seen yet): Log the current line, and if different than the last one,
|
||||
// issue a new OpLine using the new line and current source file name.
|
||||
void setLine(int line);
|
||||
|
||||
// If filename null, generate OpLine for non-filename-based line directives,
|
||||
// else do filename-based: Log the current line and file, and if different
|
||||
// than the last one, issue a new OpLine using the new line and file
|
||||
// name.
|
||||
void setLine(int line, const char* filename);
|
||||
// Low-level OpLine. See setLine() for a layered helper.
|
||||
void addLine(Id fileName, int line, int column);
|
||||
|
||||
// For creating new types (will return old type if the requested one was already made).
|
||||
Id makeVoidType();
|
||||
Id makeBoolType();
|
||||
Id makePointer(StorageClass, Id pointee);
|
||||
Id makeForwardPointer(StorageClass);
|
||||
Id makePointerFromForwardPointer(StorageClass, Id forwardPointerType, Id pointee);
|
||||
Id makeIntegerType(int width, bool hasSign); // generic
|
||||
Id makeIntType(int width) { return makeIntegerType(width, true); }
|
||||
Id makeUintType(int width) { return makeIntegerType(width, false); }
|
||||
Id makeFloatType(int width);
|
||||
Id makeStructType(const std::vector<Id>& members, const char*);
|
||||
Id makeStructResultType(Id type0, Id type1);
|
||||
Id makeVectorType(Id component, int size);
|
||||
Id makeMatrixType(Id component, int cols, int rows);
|
||||
Id makeArrayType(Id element, Id sizeId, int stride); // 0 stride means no stride decoration
|
||||
Id makeRuntimeArray(Id element);
|
||||
Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes);
|
||||
Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
|
||||
Id makeSamplerType();
|
||||
Id makeSampledImageType(Id imageType);
|
||||
Id makeCooperativeMatrixType(Id component, Id scope, Id rows, Id cols);
|
||||
|
||||
// accelerationStructureNV type
|
||||
Id makeAccelerationStructureType();
|
||||
// rayQueryEXT type
|
||||
Id makeRayQueryType();
|
||||
|
||||
// For querying about types.
|
||||
Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
|
||||
Id getDerefTypeId(Id resultId) const;
|
||||
Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
|
||||
Op getTypeClass(Id typeId) const { return getOpCode(typeId); }
|
||||
Op getMostBasicTypeClass(Id typeId) const;
|
||||
int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
|
||||
int getNumTypeConstituents(Id typeId) const;
|
||||
int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); }
|
||||
Id getScalarTypeId(Id typeId) const;
|
||||
Id getContainedTypeId(Id typeId) const;
|
||||
Id getContainedTypeId(Id typeId, int) const;
|
||||
StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); }
|
||||
ImageFormat getImageTypeFormat(Id typeId) const
|
||||
{ return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); }
|
||||
|
||||
bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); }
|
||||
bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); }
|
||||
bool isVector(Id resultId) const { return isVectorType(getTypeId(resultId)); }
|
||||
bool isMatrix(Id resultId) const { return isMatrixType(getTypeId(resultId)); }
|
||||
bool isCooperativeMatrix(Id resultId)const { return isCooperativeMatrixType(getTypeId(resultId)); }
|
||||
bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); }
|
||||
bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); }
|
||||
|
||||
bool isBoolType(Id typeId)
|
||||
{ return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); }
|
||||
bool isIntType(Id typeId) const
|
||||
{ return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) != 0; }
|
||||
bool isUintType(Id typeId) const
|
||||
{ return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) == 0; }
|
||||
bool isFloatType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat; }
|
||||
bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; }
|
||||
bool isScalarType(Id typeId) const
|
||||
{ return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt ||
|
||||
getTypeClass(typeId) == OpTypeBool; }
|
||||
bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; }
|
||||
bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; }
|
||||
bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; }
|
||||
bool isArrayType(Id typeId) const { return getTypeClass(typeId) == OpTypeArray; }
|
||||
#ifdef GLSLANG_WEB
|
||||
bool isCooperativeMatrixType(Id typeId)const { return false; }
|
||||
#else
|
||||
bool isCooperativeMatrixType(Id typeId)const { return getTypeClass(typeId) == OpTypeCooperativeMatrixNV; }
|
||||
#endif
|
||||
bool isAggregateType(Id typeId) const
|
||||
{ return isArrayType(typeId) || isStructType(typeId) || isCooperativeMatrixType(typeId); }
|
||||
bool isImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeImage; }
|
||||
bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }
|
||||
bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; }
|
||||
bool containsType(Id typeId, Op typeOp, unsigned int width) const;
|
||||
bool containsPhysicalStorageBufferOrArray(Id typeId) const;
|
||||
|
||||
bool isConstantOpCode(Op opcode) const;
|
||||
bool isSpecConstantOpCode(Op opcode) const;
|
||||
bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }
|
||||
bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
|
||||
bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); }
|
||||
unsigned int getConstantScalar(Id resultId) const
|
||||
{ return module.getInstruction(resultId)->getImmediateOperand(0); }
|
||||
StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }
|
||||
|
||||
int getScalarTypeWidth(Id typeId) const
|
||||
{
|
||||
Id scalarTypeId = getScalarTypeId(typeId);
|
||||
assert(getTypeClass(scalarTypeId) == OpTypeInt || getTypeClass(scalarTypeId) == OpTypeFloat);
|
||||
return module.getInstruction(scalarTypeId)->getImmediateOperand(0);
|
||||
}
|
||||
|
||||
int getTypeNumColumns(Id typeId) const
|
||||
{
|
||||
assert(isMatrixType(typeId));
|
||||
return getNumTypeConstituents(typeId);
|
||||
}
|
||||
int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
|
||||
int getTypeNumRows(Id typeId) const
|
||||
{
|
||||
assert(isMatrixType(typeId));
|
||||
return getNumTypeComponents(getContainedTypeId(typeId));
|
||||
}
|
||||
int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
|
||||
|
||||
Dim getTypeDimensionality(Id typeId) const
|
||||
{
|
||||
assert(isImageType(typeId));
|
||||
return (Dim)module.getInstruction(typeId)->getImmediateOperand(1);
|
||||
}
|
||||
Id getImageType(Id resultId) const
|
||||
{
|
||||
Id typeId = getTypeId(resultId);
|
||||
assert(isImageType(typeId) || isSampledImageType(typeId));
|
||||
return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId;
|
||||
}
|
||||
bool isArrayedImageType(Id typeId) const
|
||||
{
|
||||
assert(isImageType(typeId));
|
||||
return module.getInstruction(typeId)->getImmediateOperand(3) != 0;
|
||||
}
|
||||
|
||||
// For making new constants (will return old constant if the requested one was already made).
|
||||
Id makeBoolConstant(bool b, bool specConstant = false);
|
||||
Id makeInt8Constant(int i, bool specConstant = false)
|
||||
{ return makeIntConstant(makeIntType(8), (unsigned)i, specConstant); }
|
||||
Id makeUint8Constant(unsigned u, bool specConstant = false)
|
||||
{ return makeIntConstant(makeUintType(8), u, specConstant); }
|
||||
Id makeInt16Constant(int i, bool specConstant = false)
|
||||
{ return makeIntConstant(makeIntType(16), (unsigned)i, specConstant); }
|
||||
Id makeUint16Constant(unsigned u, bool specConstant = false)
|
||||
{ return makeIntConstant(makeUintType(16), u, specConstant); }
|
||||
Id makeIntConstant(int i, bool specConstant = false)
|
||||
{ return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); }
|
||||
Id makeUintConstant(unsigned u, bool specConstant = false)
|
||||
{ return makeIntConstant(makeUintType(32), u, specConstant); }
|
||||
Id makeInt64Constant(long long i, bool specConstant = false)
|
||||
{ return makeInt64Constant(makeIntType(64), (unsigned long long)i, specConstant); }
|
||||
Id makeUint64Constant(unsigned long long u, bool specConstant = false)
|
||||
{ return makeInt64Constant(makeUintType(64), u, specConstant); }
|
||||
Id makeFloatConstant(float f, bool specConstant = false);
|
||||
Id makeDoubleConstant(double d, bool specConstant = false);
|
||||
Id makeFloat16Constant(float f16, bool specConstant = false);
|
||||
Id makeFpConstant(Id type, double d, bool specConstant = false);
|
||||
|
||||
// Turn the array of constants into a proper spv constant of the requested type.
|
||||
Id makeCompositeConstant(Id type, const std::vector<Id>& comps, bool specConst = false);
|
||||
|
||||
// Methods for adding information outside the CFG.
|
||||
Instruction* addEntryPoint(ExecutionModel, Function*, const char* name);
|
||||
void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1);
|
||||
void addName(Id, const char* name);
|
||||
void addMemberName(Id, int member, const char* name);
|
||||
void addDecoration(Id, Decoration, int num = -1);
|
||||
void addDecoration(Id, Decoration, const char*);
|
||||
void addDecorationId(Id id, Decoration, Id idDecoration);
|
||||
void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
|
||||
void addMemberDecoration(Id, unsigned int member, Decoration, const char*);
|
||||
|
||||
// At the end of what block do the next create*() instructions go?
|
||||
void setBuildPoint(Block* bp) { buildPoint = bp; }
|
||||
Block* getBuildPoint() const { return buildPoint; }
|
||||
|
||||
// Make the entry-point function. The returned pointer is only valid
|
||||
// for the lifetime of this builder.
|
||||
Function* makeEntryPoint(const char*);
|
||||
|
||||
// Make a shader-style function, and create its entry block if entry is non-zero.
|
||||
// Return the function, pass back the entry.
|
||||
// The returned pointer is only valid for the lifetime of this builder.
|
||||
Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name,
|
||||
const std::vector<Id>& paramTypes, const std::vector<std::vector<Decoration>>& precisions, Block **entry = 0);
|
||||
|
||||
// Create a return. An 'implicit' return is one not appearing in the source
|
||||
// code. In the case of an implicit return, no post-return block is inserted.
|
||||
void makeReturn(bool implicit, Id retVal = 0);
|
||||
|
||||
// Generate all the code needed to finish up a function.
|
||||
void leaveFunction();
|
||||
|
||||
// Create a discard.
|
||||
void makeDiscard();
|
||||
|
||||
// Create a global or function local or IO variable.
|
||||
Id createVariable(StorageClass, Id type, const char* name = 0, Id initializer = NoResult);
|
||||
|
||||
// Create an intermediate with an undefined value.
|
||||
Id createUndefined(Id type);
|
||||
|
||||
// Store into an Id and return the l-value
|
||||
void createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone,
|
||||
spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
|
||||
|
||||
// Load from an Id and return it
|
||||
Id createLoad(Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone,
|
||||
spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
|
||||
|
||||
// Create an OpAccessChain instruction
|
||||
Id createAccessChain(StorageClass, Id base, const std::vector<Id>& offsets);
|
||||
|
||||
// Create an OpArrayLength instruction
|
||||
Id createArrayLength(Id base, unsigned int member);
|
||||
|
||||
// Create an OpCooperativeMatrixLengthNV instruction
|
||||
Id createCooperativeMatrixLength(Id type);
|
||||
|
||||
// Create an OpCompositeExtract instruction
|
||||
Id createCompositeExtract(Id composite, Id typeId, unsigned index);
|
||||
Id createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes);
|
||||
Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
|
||||
Id createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes);
|
||||
|
||||
Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);
|
||||
Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);
|
||||
|
||||
void createNoResultOp(Op);
|
||||
void createNoResultOp(Op, Id operand);
|
||||
void createNoResultOp(Op, const std::vector<Id>& operands);
|
||||
void createNoResultOp(Op, const std::vector<IdImmediate>& operands);
|
||||
void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);
|
||||
void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
|
||||
Id createUnaryOp(Op, Id typeId, Id operand);
|
||||
Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
|
||||
Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
|
||||
Id createOp(Op, Id typeId, const std::vector<Id>& operands);
|
||||
Id createOp(Op, Id typeId, const std::vector<IdImmediate>& operands);
|
||||
Id createFunctionCall(spv::Function*, const std::vector<spv::Id>&);
|
||||
Id createSpecConstantOp(Op, Id typeId, const std::vector<spv::Id>& operands, const std::vector<unsigned>& literals);
|
||||
|
||||
// Take an rvalue (source) and a set of channels to extract from it to
|
||||
// make a new rvalue, which is returned.
|
||||
Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels);
|
||||
|
||||
// Take a copy of an lvalue (target) and a source of components, and set the
|
||||
// source components into the lvalue where the 'channels' say to put them.
|
||||
// An updated version of the target is returned.
|
||||
// (No true lvalue or stores are used.)
|
||||
Id createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels);
|
||||
|
||||
// If both the id and precision are valid, the id
|
||||
// gets tagged with the requested precision.
|
||||
// The passed in id is always the returned id, to simplify use patterns.
|
||||
Id setPrecision(Id id, Decoration precision)
|
||||
{
|
||||
if (precision != NoPrecision && id != NoResult)
|
||||
addDecoration(id, precision);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
// Can smear a scalar to a vector for the following forms:
|
||||
// - promoteScalar(scalar, vector) // smear scalar to width of vector
|
||||
// - promoteScalar(vector, scalar) // smear scalar to width of vector
|
||||
// - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
|
||||
// - promoteScalar(scalar, scalar) // do nothing
|
||||
// Other forms are not allowed.
|
||||
//
|
||||
// Generally, the type of 'scalar' does not need to be the same type as the components in 'vector'.
|
||||
// The type of the created vector is a vector of components of the same type as the scalar.
|
||||
//
|
||||
// Note: One of the arguments will change, with the result coming back that way rather than
|
||||
// through the return value.
|
||||
void promoteScalar(Decoration precision, Id& left, Id& right);
|
||||
|
||||
// Make a value by smearing the scalar to fill the type.
|
||||
// vectorType should be the correct type for making a vector of scalarVal.
|
||||
// (No conversions are done.)
|
||||
Id smearScalar(Decoration precision, Id scalarVal, Id vectorType);
|
||||
|
||||
// Create a call to a built-in function.
|
||||
Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args);
|
||||
|
||||
// List of parameters used to create a texture operation
|
||||
struct TextureParameters {
|
||||
Id sampler;
|
||||
Id coords;
|
||||
Id bias;
|
||||
Id lod;
|
||||
Id Dref;
|
||||
Id offset;
|
||||
Id offsets;
|
||||
Id gradX;
|
||||
Id gradY;
|
||||
Id sample;
|
||||
Id component;
|
||||
Id texelOut;
|
||||
Id lodClamp;
|
||||
Id granularity;
|
||||
Id coarse;
|
||||
bool nonprivate;
|
||||
bool volatil;
|
||||
};
|
||||
|
||||
// Select the correct texture operation based on all inputs, and emit the correct instruction
|
||||
Id createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather,
|
||||
bool noImplicit, const TextureParameters&, ImageOperandsMask);
|
||||
|
||||
// Emit the OpTextureQuery* instruction that was passed in.
|
||||
// Figure out the right return value and type, and return it.
|
||||
Id createTextureQueryCall(Op, const TextureParameters&, bool isUnsignedResult);
|
||||
|
||||
Id createSamplePositionCall(Decoration precision, Id, Id);
|
||||
|
||||
Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
|
||||
Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
|
||||
|
||||
// Reduction comparison for composites: For equal and not-equal resulting in a scalar.
|
||||
Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */);
|
||||
|
||||
// OpCompositeConstruct
|
||||
Id createCompositeConstruct(Id typeId, const std::vector<Id>& constituents);
|
||||
|
||||
// vector or scalar constructor
|
||||
Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
|
||||
|
||||
// matrix constructor
|
||||
Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
|
||||
|
||||
// Helper to use for building nested control flow with if-then-else.
|
||||
class If {
|
||||
public:
|
||||
If(Id condition, unsigned int ctrl, Builder& builder);
|
||||
~If() {}
|
||||
|
||||
void makeBeginElse();
|
||||
void makeEndIf();
|
||||
|
||||
private:
|
||||
If(const If&);
|
||||
If& operator=(If&);
|
||||
|
||||
Builder& builder;
|
||||
Id condition;
|
||||
unsigned int control;
|
||||
Function* function;
|
||||
Block* headerBlock;
|
||||
Block* thenBlock;
|
||||
Block* elseBlock;
|
||||
Block* mergeBlock;
|
||||
};
|
||||
|
||||
// Make a switch statement. A switch has 'numSegments' of pieces of code, not containing
|
||||
// any case/default labels, all separated by one or more case/default labels. Each possible
|
||||
// case value v is a jump to the caseValues[v] segment. The defaultSegment is also in this
|
||||
// number space. How to compute the value is given by 'condition', as in switch(condition).
|
||||
//
|
||||
// The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
|
||||
//
|
||||
// Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
|
||||
//
|
||||
// Returns the right set of basic blocks to start each code segment with, so that the caller's
|
||||
// recursion stack can hold the memory for it.
|
||||
//
|
||||
void makeSwitch(Id condition, unsigned int control, int numSegments, const std::vector<int>& caseValues,
|
||||
const std::vector<int>& valueToSegment, int defaultSegment, std::vector<Block*>& segmentBB);
|
||||
|
||||
// Add a branch to the innermost switch's merge block.
|
||||
void addSwitchBreak();
|
||||
|
||||
// Move to the next code segment, passing in the return argument in makeSwitch()
|
||||
void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
|
||||
|
||||
// Finish off the innermost switch.
|
||||
void endSwitch(std::vector<Block*>& segmentBB);
|
||||
|
||||
struct LoopBlocks {
|
||||
LoopBlocks(Block& head, Block& body, Block& merge, Block& continue_target) :
|
||||
head(head), body(body), merge(merge), continue_target(continue_target) { }
|
||||
Block &head, &body, &merge, &continue_target;
|
||||
private:
|
||||
LoopBlocks();
|
||||
LoopBlocks& operator=(const LoopBlocks&) = delete;
|
||||
};
|
||||
|
||||
// Start a new loop and prepare the builder to generate code for it. Until
|
||||
// closeLoop() is called for this loop, createLoopContinue() and
|
||||
// createLoopExit() will target its corresponding blocks.
|
||||
LoopBlocks& makeNewLoop();
|
||||
|
||||
// Create a new block in the function containing the build point. Memory is
|
||||
// owned by the function object.
|
||||
Block& makeNewBlock();
|
||||
|
||||
// Add a branch to the continue_target of the current (innermost) loop.
|
||||
void createLoopContinue();
|
||||
|
||||
// Add an exit (e.g. "break") from the innermost loop that we're currently
|
||||
// in.
|
||||
void createLoopExit();
|
||||
|
||||
// Close the innermost loop that you're in
|
||||
void closeLoop();
|
||||
|
||||
//
|
||||
// Access chain design for an R-Value vs. L-Value:
|
||||
//
|
||||
// There is a single access chain the builder is building at
|
||||
// any particular time. Such a chain can be used to either to a load or
|
||||
// a store, when desired.
|
||||
//
|
||||
// Expressions can be r-values, l-values, or both, or only r-values:
|
||||
// a[b.c].d = .... // l-value
|
||||
// ... = a[b.c].d; // r-value, that also looks like an l-value
|
||||
// ++a[b.c].d; // r-value and l-value
|
||||
// (x + y)[2]; // r-value only, can't possibly be l-value
|
||||
//
|
||||
// Computing an r-value means generating code. Hence,
|
||||
// r-values should only be computed when they are needed, not speculatively.
|
||||
//
|
||||
// Computing an l-value means saving away information for later use in the compiler,
|
||||
// no code is generated until the l-value is later dereferenced. It is okay
|
||||
// to speculatively generate an l-value, just not okay to speculatively dereference it.
|
||||
//
|
||||
// The base of the access chain (the left-most variable or expression
|
||||
// from which everything is based) can be set either as an l-value
|
||||
// or as an r-value. Most efficient would be to set an l-value if one
|
||||
// is available. If an expression was evaluated, the resulting r-value
|
||||
// can be set as the chain base.
|
||||
//
|
||||
// The users of this single access chain can save and restore if they
|
||||
// want to nest or manage multiple chains.
|
||||
//
|
||||
|
||||
struct AccessChain {
|
||||
Id base; // for l-values, pointer to the base object, for r-values, the base object
|
||||
std::vector<Id> indexChain;
|
||||
Id instr; // cache the instruction that generates this access chain
|
||||
std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number
|
||||
Id component; // a dynamic component index, can coexist with a swizzle,
|
||||
// done after the swizzle, NoResult if not present
|
||||
Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied;
|
||||
// NoType unless a swizzle or component is present
|
||||
bool isRValue; // true if 'base' is an r-value, otherwise, base is an l-value
|
||||
unsigned int alignment; // bitwise OR of alignment values passed in. Accumulates worst alignment.
|
||||
// Only tracks base and (optional) component selection alignment.
|
||||
|
||||
// Accumulate whether anything in the chain of structures has coherent decorations.
|
||||
struct CoherentFlags {
|
||||
CoherentFlags() { clear(); }
|
||||
#ifdef GLSLANG_WEB
|
||||
void clear() { }
|
||||
bool isVolatile() const { return false; }
|
||||
CoherentFlags operator |=(const CoherentFlags &other) { return *this; }
|
||||
#else
|
||||
bool isVolatile() const { return volatil; }
|
||||
bool anyCoherent() const {
|
||||
return coherent || devicecoherent || queuefamilycoherent || workgroupcoherent ||
|
||||
subgroupcoherent || shadercallcoherent;
|
||||
}
|
||||
|
||||
unsigned coherent : 1;
|
||||
unsigned devicecoherent : 1;
|
||||
unsigned queuefamilycoherent : 1;
|
||||
unsigned workgroupcoherent : 1;
|
||||
unsigned subgroupcoherent : 1;
|
||||
unsigned shadercallcoherent : 1;
|
||||
unsigned nonprivate : 1;
|
||||
unsigned volatil : 1;
|
||||
unsigned isImage : 1;
|
||||
|
||||
void clear() {
|
||||
coherent = 0;
|
||||
devicecoherent = 0;
|
||||
queuefamilycoherent = 0;
|
||||
workgroupcoherent = 0;
|
||||
subgroupcoherent = 0;
|
||||
shadercallcoherent = 0;
|
||||
nonprivate = 0;
|
||||
volatil = 0;
|
||||
isImage = 0;
|
||||
}
|
||||
|
||||
CoherentFlags operator |=(const CoherentFlags &other) {
|
||||
coherent |= other.coherent;
|
||||
devicecoherent |= other.devicecoherent;
|
||||
queuefamilycoherent |= other.queuefamilycoherent;
|
||||
workgroupcoherent |= other.workgroupcoherent;
|
||||
subgroupcoherent |= other.subgroupcoherent;
|
||||
shadercallcoherent |= other.shadercallcoherent;
|
||||
nonprivate |= other.nonprivate;
|
||||
volatil |= other.volatil;
|
||||
isImage |= other.isImage;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
CoherentFlags coherentFlags;
|
||||
};
|
||||
|
||||
//
|
||||
// the SPIR-V builder maintains a single active chain that
|
||||
// the following methods operate on
|
||||
//
|
||||
|
||||
// for external save and restore
|
||||
AccessChain getAccessChain() { return accessChain; }
|
||||
void setAccessChain(AccessChain newChain) { accessChain = newChain; }
|
||||
|
||||
// clear accessChain
|
||||
void clearAccessChain();
|
||||
|
||||
// set new base as an l-value base
|
||||
void setAccessChainLValue(Id lValue)
|
||||
{
|
||||
assert(isPointer(lValue));
|
||||
accessChain.base = lValue;
|
||||
}
|
||||
|
||||
// set new base value as an r-value
|
||||
void setAccessChainRValue(Id rValue)
|
||||
{
|
||||
accessChain.isRValue = true;
|
||||
accessChain.base = rValue;
|
||||
}
|
||||
|
||||
// push offset onto the end of the chain
|
||||
void accessChainPush(Id offset, AccessChain::CoherentFlags coherentFlags, unsigned int alignment)
|
||||
{
|
||||
accessChain.indexChain.push_back(offset);
|
||||
accessChain.coherentFlags |= coherentFlags;
|
||||
accessChain.alignment |= alignment;
|
||||
}
|
||||
|
||||
// push new swizzle onto the end of any existing swizzle, merging into a single swizzle
|
||||
void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType,
|
||||
AccessChain::CoherentFlags coherentFlags, unsigned int alignment);
|
||||
|
||||
// push a dynamic component selection onto the access chain, only applicable with a
|
||||
// non-trivial swizzle or no swizzle
|
||||
void accessChainPushComponent(Id component, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags,
|
||||
unsigned int alignment)
|
||||
{
|
||||
if (accessChain.swizzle.size() != 1) {
|
||||
accessChain.component = component;
|
||||
if (accessChain.preSwizzleBaseType == NoType)
|
||||
accessChain.preSwizzleBaseType = preSwizzleBaseType;
|
||||
}
|
||||
accessChain.coherentFlags |= coherentFlags;
|
||||
accessChain.alignment |= alignment;
|
||||
}
|
||||
|
||||
// use accessChain and swizzle to store value
|
||||
void accessChainStore(Id rvalue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone,
|
||||
spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
|
||||
|
||||
// use accessChain and swizzle to load an r-value
|
||||
Id accessChainLoad(Decoration precision, Decoration nonUniform, Id ResultType,
|
||||
spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax,
|
||||
unsigned int alignment = 0);
|
||||
|
||||
// Return whether or not the access chain can be represented in SPIR-V
|
||||
// as an l-value.
|
||||
// E.g., a[3].yx cannot be, while a[3].y and a[3].y[x] can be.
|
||||
bool isSpvLvalue() const { return accessChain.swizzle.size() <= 1; }
|
||||
|
||||
// get the direct pointer for an l-value
|
||||
Id accessChainGetLValue();
|
||||
|
||||
// Get the inferred SPIR-V type of the result of the current access chain,
|
||||
// based on the type of the base and the chain of dereferences.
|
||||
Id accessChainGetInferredType();
|
||||
|
||||
// Add capabilities, extensions, remove unneeded decorations, etc.,
|
||||
// based on the resulting SPIR-V.
|
||||
void postProcess();
|
||||
|
||||
// Prune unreachable blocks in the CFG and remove unneeded decorations.
|
||||
void postProcessCFG();
|
||||
|
||||
#ifndef GLSLANG_WEB
|
||||
// Add capabilities, extensions based on instructions in the module.
|
||||
void postProcessFeatures();
|
||||
// Hook to visit each instruction in a block in a function
|
||||
void postProcess(Instruction&);
|
||||
// Hook to visit each non-32-bit sized float/int operation in a block.
|
||||
void postProcessType(const Instruction&, spv::Id typeId);
|
||||
#endif
|
||||
|
||||
void dump(std::vector<unsigned int>&) const;
|
||||
|
||||
void createBranch(Block* block);
|
||||
void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
|
||||
void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control,
|
||||
const std::vector<unsigned int>& operands);
|
||||
|
||||
// Sets to generate opcode for specialization constants.
|
||||
void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
|
||||
// Sets to generate opcode for non-specialization constants (normal mode).
|
||||
void setToNormalCodeGenMode() { generatingOpCodeForSpecConst = false; }
|
||||
// Check if the builder is generating code for spec constants.
|
||||
bool isInSpecConstCodeGenMode() { return generatingOpCodeForSpecConst; }
|
||||
|
||||
protected:
|
||||
Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
|
||||
Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant);
|
||||
Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value);
|
||||
Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2);
|
||||
Id findCompositeConstant(Op typeClass, Id typeId, const std::vector<Id>& comps);
|
||||
Id findStructConstant(Id typeId, const std::vector<Id>& comps);
|
||||
Id collapseAccessChain();
|
||||
void remapDynamicSwizzle();
|
||||
void transferAccessChainSwizzle(bool dynamic);
|
||||
void simplifyAccessChainSwizzle();
|
||||
void createAndSetNoPredecessorBlock(const char*);
|
||||
void createSelectionMerge(Block* mergeBlock, unsigned int control);
|
||||
void dumpSourceInstructions(std::vector<unsigned int>&) const;
|
||||
void dumpSourceInstructions(const spv::Id fileId, const std::string& text, std::vector<unsigned int>&) const;
|
||||
void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const;
|
||||
void dumpModuleProcesses(std::vector<unsigned int>&) const;
|
||||
spv::MemoryAccessMask sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc)
|
||||
const;
|
||||
|
||||
unsigned int spvVersion; // the version of SPIR-V to emit in the header
|
||||
SourceLanguage source;
|
||||
int sourceVersion;
|
||||
spv::Id sourceFileStringId;
|
||||
std::string sourceText;
|
||||
int currentLine;
|
||||
const char* currentFile;
|
||||
bool emitOpLines;
|
||||
std::set<std::string> extensions;
|
||||
std::vector<const char*> sourceExtensions;
|
||||
std::vector<const char*> moduleProcesses;
|
||||
AddressingModel addressModel;
|
||||
MemoryModel memoryModel;
|
||||
std::set<spv::Capability> capabilities;
|
||||
int builderNumber;
|
||||
Module module;
|
||||
Block* buildPoint;
|
||||
Id uniqueId;
|
||||
Function* entryPointFunction;
|
||||
bool generatingOpCodeForSpecConst;
|
||||
AccessChain accessChain;
|
||||
|
||||
// special blocks of instructions for output
|
||||
std::vector<std::unique_ptr<Instruction> > strings;
|
||||
std::vector<std::unique_ptr<Instruction> > imports;
|
||||
std::vector<std::unique_ptr<Instruction> > entryPoints;
|
||||
std::vector<std::unique_ptr<Instruction> > executionModes;
|
||||
std::vector<std::unique_ptr<Instruction> > names;
|
||||
std::vector<std::unique_ptr<Instruction> > decorations;
|
||||
std::vector<std::unique_ptr<Instruction> > constantsTypesGlobals;
|
||||
std::vector<std::unique_ptr<Instruction> > externals;
|
||||
std::vector<std::unique_ptr<Function> > functions;
|
||||
|
||||
// not output, internally used for quick & dirty canonical (unique) creation
|
||||
|
||||
// map type opcodes to constant inst.
|
||||
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedConstants;
|
||||
// map struct-id to constant instructions
|
||||
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedStructConstants;
|
||||
// map type opcodes to type instructions
|
||||
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedTypes;
|
||||
|
||||
// stack of switches
|
||||
std::stack<Block*> switchMerges;
|
||||
|
||||
// Our loop stack.
|
||||
std::stack<LoopBlocks> loops;
|
||||
|
||||
// map from strings to their string ids
|
||||
std::unordered_map<std::string, spv::Id> stringIds;
|
||||
|
||||
// map from include file name ids to their contents
|
||||
std::map<spv::Id, const std::string*> includeFiles;
|
||||
|
||||
// The stream for outputting warnings and errors.
|
||||
SpvBuildLogger* logger;
|
||||
}; // end Builder class
|
||||
|
||||
}; // end spv namespace
|
||||
|
||||
#endif // SpvBuilder_H
|
||||
@@ -1,450 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2018 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//
|
||||
// Post-processing for SPIR-V IR, in internal form, not standard binary form.
|
||||
//
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <algorithm>
|
||||
|
||||
#include "SpvBuilder.h"
|
||||
|
||||
#include "spirv.hpp"
|
||||
#include "GlslangToSpv.h"
|
||||
#include "SpvBuilder.h"
|
||||
namespace spv {
|
||||
#include "GLSL.std.450.h"
|
||||
#include "GLSL.ext.KHR.h"
|
||||
#include "GLSL.ext.EXT.h"
|
||||
#include "GLSL.ext.AMD.h"
|
||||
#include "GLSL.ext.NV.h"
|
||||
}
|
||||
|
||||
namespace spv {
|
||||
|
||||
#ifndef GLSLANG_WEB
|
||||
// Hook to visit each operand type and result type of an instruction.
|
||||
// Will be called multiple times for one instruction, once for each typed
|
||||
// operand and the result.
|
||||
void Builder::postProcessType(const Instruction& inst, Id typeId)
|
||||
{
|
||||
// Characterize the type being questioned
|
||||
Id basicTypeOp = getMostBasicTypeClass(typeId);
|
||||
int width = 0;
|
||||
if (basicTypeOp == OpTypeFloat || basicTypeOp == OpTypeInt)
|
||||
width = getScalarTypeWidth(typeId);
|
||||
|
||||
// Do opcode-specific checks
|
||||
switch (inst.getOpCode()) {
|
||||
case OpLoad:
|
||||
case OpStore:
|
||||
if (basicTypeOp == OpTypeStruct) {
|
||||
if (containsType(typeId, OpTypeInt, 8))
|
||||
addCapability(CapabilityInt8);
|
||||
if (containsType(typeId, OpTypeInt, 16))
|
||||
addCapability(CapabilityInt16);
|
||||
if (containsType(typeId, OpTypeFloat, 16))
|
||||
addCapability(CapabilityFloat16);
|
||||
} else {
|
||||
StorageClass storageClass = getStorageClass(inst.getIdOperand(0));
|
||||
if (width == 8) {
|
||||
switch (storageClass) {
|
||||
case StorageClassPhysicalStorageBufferEXT:
|
||||
case StorageClassUniform:
|
||||
case StorageClassStorageBuffer:
|
||||
case StorageClassPushConstant:
|
||||
break;
|
||||
default:
|
||||
addCapability(CapabilityInt8);
|
||||
break;
|
||||
}
|
||||
} else if (width == 16) {
|
||||
switch (storageClass) {
|
||||
case StorageClassPhysicalStorageBufferEXT:
|
||||
case StorageClassUniform:
|
||||
case StorageClassStorageBuffer:
|
||||
case StorageClassPushConstant:
|
||||
case StorageClassInput:
|
||||
case StorageClassOutput:
|
||||
break;
|
||||
default:
|
||||
if (basicTypeOp == OpTypeInt)
|
||||
addCapability(CapabilityInt16);
|
||||
if (basicTypeOp == OpTypeFloat)
|
||||
addCapability(CapabilityFloat16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OpAccessChain:
|
||||
case OpPtrAccessChain:
|
||||
case OpCopyObject:
|
||||
break;
|
||||
case OpFConvert:
|
||||
case OpSConvert:
|
||||
case OpUConvert:
|
||||
// Look for any 8/16-bit storage capabilities. If there are none, assume that
|
||||
// the convert instruction requires the Float16/Int8/16 capability.
|
||||
if (containsType(typeId, OpTypeFloat, 16) || containsType(typeId, OpTypeInt, 16)) {
|
||||
bool foundStorage = false;
|
||||
for (auto it = capabilities.begin(); it != capabilities.end(); ++it) {
|
||||
spv::Capability cap = *it;
|
||||
if (cap == spv::CapabilityStorageInputOutput16 ||
|
||||
cap == spv::CapabilityStoragePushConstant16 ||
|
||||
cap == spv::CapabilityStorageUniformBufferBlock16 ||
|
||||
cap == spv::CapabilityStorageUniform16) {
|
||||
foundStorage = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundStorage) {
|
||||
if (containsType(typeId, OpTypeFloat, 16))
|
||||
addCapability(CapabilityFloat16);
|
||||
if (containsType(typeId, OpTypeInt, 16))
|
||||
addCapability(CapabilityInt16);
|
||||
}
|
||||
}
|
||||
if (containsType(typeId, OpTypeInt, 8)) {
|
||||
bool foundStorage = false;
|
||||
for (auto it = capabilities.begin(); it != capabilities.end(); ++it) {
|
||||
spv::Capability cap = *it;
|
||||
if (cap == spv::CapabilityStoragePushConstant8 ||
|
||||
cap == spv::CapabilityUniformAndStorageBuffer8BitAccess ||
|
||||
cap == spv::CapabilityStorageBuffer8BitAccess) {
|
||||
foundStorage = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundStorage) {
|
||||
addCapability(CapabilityInt8);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OpExtInst:
|
||||
switch (inst.getImmediateOperand(1)) {
|
||||
case GLSLstd450Frexp:
|
||||
case GLSLstd450FrexpStruct:
|
||||
if (getSpvVersion() < glslang::EShTargetSpv_1_3 && containsType(typeId, OpTypeInt, 16))
|
||||
addExtension(spv::E_SPV_AMD_gpu_shader_int16);
|
||||
break;
|
||||
case GLSLstd450InterpolateAtCentroid:
|
||||
case GLSLstd450InterpolateAtSample:
|
||||
case GLSLstd450InterpolateAtOffset:
|
||||
if (getSpvVersion() < glslang::EShTargetSpv_1_3 && containsType(typeId, OpTypeFloat, 16))
|
||||
addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (basicTypeOp == OpTypeFloat && width == 16)
|
||||
addCapability(CapabilityFloat16);
|
||||
if (basicTypeOp == OpTypeInt && width == 16)
|
||||
addCapability(CapabilityInt16);
|
||||
if (basicTypeOp == OpTypeInt && width == 8)
|
||||
addCapability(CapabilityInt8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Called for each instruction that resides in a block.
|
||||
void Builder::postProcess(Instruction& inst)
|
||||
{
|
||||
// Add capabilities based simply on the opcode.
|
||||
switch (inst.getOpCode()) {
|
||||
case OpExtInst:
|
||||
switch (inst.getImmediateOperand(1)) {
|
||||
case GLSLstd450InterpolateAtCentroid:
|
||||
case GLSLstd450InterpolateAtSample:
|
||||
case GLSLstd450InterpolateAtOffset:
|
||||
addCapability(CapabilityInterpolationFunction);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case OpDPdxFine:
|
||||
case OpDPdyFine:
|
||||
case OpFwidthFine:
|
||||
case OpDPdxCoarse:
|
||||
case OpDPdyCoarse:
|
||||
case OpFwidthCoarse:
|
||||
addCapability(CapabilityDerivativeControl);
|
||||
break;
|
||||
|
||||
case OpImageQueryLod:
|
||||
case OpImageQuerySize:
|
||||
case OpImageQuerySizeLod:
|
||||
case OpImageQuerySamples:
|
||||
case OpImageQueryLevels:
|
||||
addCapability(CapabilityImageQuery);
|
||||
break;
|
||||
|
||||
case OpGroupNonUniformPartitionNV:
|
||||
addExtension(E_SPV_NV_shader_subgroup_partitioned);
|
||||
addCapability(CapabilityGroupNonUniformPartitionedNV);
|
||||
break;
|
||||
|
||||
case OpLoad:
|
||||
case OpStore:
|
||||
{
|
||||
// For any load/store to a PhysicalStorageBufferEXT, walk the accesschain
|
||||
// index list to compute the misalignment. The pre-existing alignment value
|
||||
// (set via Builder::AccessChain::alignment) only accounts for the base of
|
||||
// the reference type and any scalar component selection in the accesschain,
|
||||
// and this function computes the rest from the SPIR-V Offset decorations.
|
||||
Instruction *accessChain = module.getInstruction(inst.getIdOperand(0));
|
||||
if (accessChain->getOpCode() == OpAccessChain) {
|
||||
Instruction *base = module.getInstruction(accessChain->getIdOperand(0));
|
||||
// Get the type of the base of the access chain. It must be a pointer type.
|
||||
Id typeId = base->getTypeId();
|
||||
Instruction *type = module.getInstruction(typeId);
|
||||
assert(type->getOpCode() == OpTypePointer);
|
||||
if (type->getImmediateOperand(0) != StorageClassPhysicalStorageBufferEXT) {
|
||||
break;
|
||||
}
|
||||
// Get the pointee type.
|
||||
typeId = type->getIdOperand(1);
|
||||
type = module.getInstruction(typeId);
|
||||
// Walk the index list for the access chain. For each index, find any
|
||||
// misalignment that can apply when accessing the member/element via
|
||||
// Offset/ArrayStride/MatrixStride decorations, and bitwise OR them all
|
||||
// together.
|
||||
int alignment = 0;
|
||||
for (int i = 1; i < accessChain->getNumOperands(); ++i) {
|
||||
Instruction *idx = module.getInstruction(accessChain->getIdOperand(i));
|
||||
if (type->getOpCode() == OpTypeStruct) {
|
||||
assert(idx->getOpCode() == OpConstant);
|
||||
unsigned int c = idx->getImmediateOperand(0);
|
||||
|
||||
const auto function = [&](const std::unique_ptr<Instruction>& decoration) {
|
||||
if (decoration.get()->getOpCode() == OpMemberDecorate &&
|
||||
decoration.get()->getIdOperand(0) == typeId &&
|
||||
decoration.get()->getImmediateOperand(1) == c &&
|
||||
(decoration.get()->getImmediateOperand(2) == DecorationOffset ||
|
||||
decoration.get()->getImmediateOperand(2) == DecorationMatrixStride)) {
|
||||
alignment |= decoration.get()->getImmediateOperand(3);
|
||||
}
|
||||
};
|
||||
std::for_each(decorations.begin(), decorations.end(), function);
|
||||
// get the next member type
|
||||
typeId = type->getIdOperand(c);
|
||||
type = module.getInstruction(typeId);
|
||||
} else if (type->getOpCode() == OpTypeArray ||
|
||||
type->getOpCode() == OpTypeRuntimeArray) {
|
||||
const auto function = [&](const std::unique_ptr<Instruction>& decoration) {
|
||||
if (decoration.get()->getOpCode() == OpDecorate &&
|
||||
decoration.get()->getIdOperand(0) == typeId &&
|
||||
decoration.get()->getImmediateOperand(1) == DecorationArrayStride) {
|
||||
alignment |= decoration.get()->getImmediateOperand(2);
|
||||
}
|
||||
};
|
||||
std::for_each(decorations.begin(), decorations.end(), function);
|
||||
// Get the element type
|
||||
typeId = type->getIdOperand(0);
|
||||
type = module.getInstruction(typeId);
|
||||
} else {
|
||||
// Once we get to any non-aggregate type, we're done.
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(inst.getNumOperands() >= 3);
|
||||
unsigned int memoryAccess = inst.getImmediateOperand((inst.getOpCode() == OpStore) ? 2 : 1);
|
||||
assert(memoryAccess & MemoryAccessAlignedMask);
|
||||
static_cast<void>(memoryAccess);
|
||||
// Compute the index of the alignment operand.
|
||||
int alignmentIdx = 2;
|
||||
if (inst.getOpCode() == OpStore)
|
||||
alignmentIdx++;
|
||||
// Merge new and old (mis)alignment
|
||||
alignment |= inst.getImmediateOperand(alignmentIdx);
|
||||
// Pick the LSB
|
||||
alignment = alignment & ~(alignment & (alignment-1));
|
||||
// update the Aligned operand
|
||||
inst.setImmediateOperand(alignmentIdx, alignment);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Checks based on type
|
||||
if (inst.getTypeId() != NoType)
|
||||
postProcessType(inst, inst.getTypeId());
|
||||
for (int op = 0; op < inst.getNumOperands(); ++op) {
|
||||
if (inst.isIdOperand(op)) {
|
||||
// In blocks, these are always result ids, but we are relying on
|
||||
// getTypeId() to return NoType for things like OpLabel.
|
||||
if (getTypeId(inst.getIdOperand(op)) != NoType)
|
||||
postProcessType(inst, getTypeId(inst.getIdOperand(op)));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// comment in header
|
||||
void Builder::postProcessCFG()
|
||||
{
|
||||
// reachableBlocks is the set of blockss reached via control flow, or which are
|
||||
// unreachable continue targert or unreachable merge.
|
||||
std::unordered_set<const Block*> reachableBlocks;
|
||||
std::unordered_map<Block*, Block*> headerForUnreachableContinue;
|
||||
std::unordered_set<Block*> unreachableMerges;
|
||||
std::unordered_set<Id> unreachableDefinitions;
|
||||
// Collect IDs defined in unreachable blocks. For each function, label the
|
||||
// reachable blocks first. Then for each unreachable block, collect the
|
||||
// result IDs of the instructions in it.
|
||||
for (auto fi = module.getFunctions().cbegin(); fi != module.getFunctions().cend(); fi++) {
|
||||
Function* f = *fi;
|
||||
Block* entry = f->getEntryBlock();
|
||||
inReadableOrder(entry,
|
||||
[&reachableBlocks, &unreachableMerges, &headerForUnreachableContinue]
|
||||
(Block* b, ReachReason why, Block* header) {
|
||||
reachableBlocks.insert(b);
|
||||
if (why == ReachDeadContinue) headerForUnreachableContinue[b] = header;
|
||||
if (why == ReachDeadMerge) unreachableMerges.insert(b);
|
||||
});
|
||||
for (auto bi = f->getBlocks().cbegin(); bi != f->getBlocks().cend(); bi++) {
|
||||
Block* b = *bi;
|
||||
if (unreachableMerges.count(b) != 0 || headerForUnreachableContinue.count(b) != 0) {
|
||||
auto ii = b->getInstructions().cbegin();
|
||||
++ii; // Keep potential decorations on the label.
|
||||
for (; ii != b->getInstructions().cend(); ++ii)
|
||||
unreachableDefinitions.insert(ii->get()->getResultId());
|
||||
} else if (reachableBlocks.count(b) == 0) {
|
||||
// The normal case for unreachable code. All definitions are considered dead.
|
||||
for (auto ii = b->getInstructions().cbegin(); ii != b->getInstructions().cend(); ++ii)
|
||||
unreachableDefinitions.insert(ii->get()->getResultId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modify unreachable merge blocks and unreachable continue targets.
|
||||
// Delete their contents.
|
||||
for (auto mergeIter = unreachableMerges.begin(); mergeIter != unreachableMerges.end(); ++mergeIter) {
|
||||
(*mergeIter)->rewriteAsCanonicalUnreachableMerge();
|
||||
}
|
||||
for (auto continueIter = headerForUnreachableContinue.begin();
|
||||
continueIter != headerForUnreachableContinue.end();
|
||||
++continueIter) {
|
||||
Block* continue_target = continueIter->first;
|
||||
Block* header = continueIter->second;
|
||||
continue_target->rewriteAsCanonicalUnreachableContinue(header);
|
||||
}
|
||||
|
||||
// Remove unneeded decorations, for unreachable instructions
|
||||
decorations.erase(std::remove_if(decorations.begin(), decorations.end(),
|
||||
[&unreachableDefinitions](std::unique_ptr<Instruction>& I) -> bool {
|
||||
Id decoration_id = I.get()->getIdOperand(0);
|
||||
return unreachableDefinitions.count(decoration_id) != 0;
|
||||
}),
|
||||
decorations.end());
|
||||
}
|
||||
|
||||
#ifndef GLSLANG_WEB
|
||||
// comment in header
|
||||
void Builder::postProcessFeatures() {
|
||||
// Add per-instruction capabilities, extensions, etc.,
|
||||
|
||||
// Look for any 8/16 bit type in physical storage buffer class, and set the
|
||||
// appropriate capability. This happens in createSpvVariable for other storage
|
||||
// classes, but there isn't always a variable for physical storage buffer.
|
||||
for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
|
||||
Instruction* type = groupedTypes[OpTypePointer][t];
|
||||
if (type->getImmediateOperand(0) == (unsigned)StorageClassPhysicalStorageBufferEXT) {
|
||||
if (containsType(type->getIdOperand(1), OpTypeInt, 8)) {
|
||||
addIncorporatedExtension(spv::E_SPV_KHR_8bit_storage, spv::Spv_1_5);
|
||||
addCapability(spv::CapabilityStorageBuffer8BitAccess);
|
||||
}
|
||||
if (containsType(type->getIdOperand(1), OpTypeInt, 16) ||
|
||||
containsType(type->getIdOperand(1), OpTypeFloat, 16)) {
|
||||
addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3);
|
||||
addCapability(spv::CapabilityStorageBuffer16BitAccess);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// process all block-contained instructions
|
||||
for (auto fi = module.getFunctions().cbegin(); fi != module.getFunctions().cend(); fi++) {
|
||||
Function* f = *fi;
|
||||
for (auto bi = f->getBlocks().cbegin(); bi != f->getBlocks().cend(); bi++) {
|
||||
Block* b = *bi;
|
||||
for (auto ii = b->getInstructions().cbegin(); ii != b->getInstructions().cend(); ii++)
|
||||
postProcess(*ii->get());
|
||||
|
||||
// For all local variables that contain pointers to PhysicalStorageBufferEXT, check whether
|
||||
// there is an existing restrict/aliased decoration. If we don't find one, add Aliased as the
|
||||
// default.
|
||||
for (auto vi = b->getLocalVariables().cbegin(); vi != b->getLocalVariables().cend(); vi++) {
|
||||
const Instruction& inst = *vi->get();
|
||||
Id resultId = inst.getResultId();
|
||||
if (containsPhysicalStorageBufferOrArray(getDerefTypeId(resultId))) {
|
||||
bool foundDecoration = false;
|
||||
const auto function = [&](const std::unique_ptr<Instruction>& decoration) {
|
||||
if (decoration.get()->getIdOperand(0) == resultId &&
|
||||
decoration.get()->getOpCode() == OpDecorate &&
|
||||
(decoration.get()->getImmediateOperand(1) == spv::DecorationAliasedPointerEXT ||
|
||||
decoration.get()->getImmediateOperand(1) == spv::DecorationRestrictPointerEXT)) {
|
||||
foundDecoration = true;
|
||||
}
|
||||
};
|
||||
std::for_each(decorations.begin(), decorations.end(), function);
|
||||
if (!foundDecoration) {
|
||||
addDecoration(resultId, spv::DecorationAliasedPointerEXT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// comment in header
|
||||
void Builder::postProcess() {
|
||||
postProcessCFG();
|
||||
#ifndef GLSLANG_WEB
|
||||
postProcessFeatures();
|
||||
#endif
|
||||
}
|
||||
|
||||
}; // end spv namespace
|
||||
@@ -1,217 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2014-2016 LunarG, Inc.
|
||||
// Copyright (C) 2018-2020 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//
|
||||
// Call into SPIRV-Tools to disassemble, validate, and optimize.
|
||||
//
|
||||
|
||||
#if ENABLE_OPT
|
||||
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
|
||||
#include "SpvTools.h"
|
||||
#include "spirv-tools/optimizer.hpp"
|
||||
#include "spirv-tools/libspirv.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
// Translate glslang's view of target versioning to what SPIRV-Tools uses.
|
||||
spv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLogger* logger)
|
||||
{
|
||||
switch (spvVersion.vulkan) {
|
||||
case glslang::EShTargetVulkan_1_0:
|
||||
return spv_target_env::SPV_ENV_VULKAN_1_0;
|
||||
case glslang::EShTargetVulkan_1_1:
|
||||
switch (spvVersion.spv) {
|
||||
case EShTargetSpv_1_0:
|
||||
case EShTargetSpv_1_1:
|
||||
case EShTargetSpv_1_2:
|
||||
case EShTargetSpv_1_3:
|
||||
return spv_target_env::SPV_ENV_VULKAN_1_1;
|
||||
case EShTargetSpv_1_4:
|
||||
return spv_target_env::SPV_ENV_VULKAN_1_1_SPIRV_1_4;
|
||||
default:
|
||||
logger->missingFunctionality("Target version for SPIRV-Tools validator");
|
||||
return spv_target_env::SPV_ENV_VULKAN_1_1;
|
||||
}
|
||||
case glslang::EShTargetVulkan_1_2:
|
||||
return spv_target_env::SPV_ENV_VULKAN_1_2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (spvVersion.openGl > 0)
|
||||
return spv_target_env::SPV_ENV_OPENGL_4_5;
|
||||
|
||||
logger->missingFunctionality("Target version for SPIRV-Tools validator");
|
||||
return spv_target_env::SPV_ENV_UNIVERSAL_1_0;
|
||||
}
|
||||
|
||||
|
||||
// Use the SPIRV-Tools disassembler to print SPIR-V.
|
||||
void SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv)
|
||||
{
|
||||
// disassemble
|
||||
spv_context context = spvContextCreate(SPV_ENV_UNIVERSAL_1_3);
|
||||
spv_text text;
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
spvBinaryToText(context, spirv.data(), spirv.size(),
|
||||
SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_INDENT,
|
||||
&text, &diagnostic);
|
||||
|
||||
// dump
|
||||
if (diagnostic == nullptr)
|
||||
out << text->str;
|
||||
else
|
||||
spvDiagnosticPrint(diagnostic);
|
||||
|
||||
// teardown
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
spvContextDestroy(context);
|
||||
}
|
||||
|
||||
// Apply the SPIRV-Tools validator to generated SPIR-V.
|
||||
void SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
|
||||
spv::SpvBuildLogger* logger, bool prelegalization)
|
||||
{
|
||||
// validate
|
||||
spv_context context = spvContextCreate(MapToSpirvToolsEnv(intermediate.getSpv(), logger));
|
||||
spv_const_binary_t binary = { spirv.data(), spirv.size() };
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
spv_validator_options options = spvValidatorOptionsCreate();
|
||||
spvValidatorOptionsSetRelaxBlockLayout(options, intermediate.usingHlslOffsets());
|
||||
spvValidatorOptionsSetBeforeHlslLegalization(options, prelegalization);
|
||||
spvValidateWithOptions(context, options, &binary, &diagnostic);
|
||||
|
||||
// report
|
||||
if (diagnostic != nullptr) {
|
||||
logger->error("SPIRV-Tools Validation Errors");
|
||||
logger->error(diagnostic->error);
|
||||
}
|
||||
|
||||
// tear down
|
||||
spvValidatorOptionsDestroy(options);
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
spvContextDestroy(context);
|
||||
}
|
||||
|
||||
// Apply the SPIRV-Tools optimizer to generated SPIR-V, for the purpose of
|
||||
// legalizing HLSL SPIR-V.
|
||||
void SpirvToolsLegalize(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
|
||||
spv::SpvBuildLogger* logger, const SpvOptions* options)
|
||||
{
|
||||
spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2;
|
||||
|
||||
spvtools::Optimizer optimizer(target_env);
|
||||
optimizer.SetMessageConsumer(
|
||||
[](spv_message_level_t level, const char *source, const spv_position_t &position, const char *message) {
|
||||
auto &out = std::cerr;
|
||||
switch (level)
|
||||
{
|
||||
case SPV_MSG_FATAL:
|
||||
case SPV_MSG_INTERNAL_ERROR:
|
||||
case SPV_MSG_ERROR:
|
||||
out << "error: ";
|
||||
break;
|
||||
case SPV_MSG_WARNING:
|
||||
out << "warning: ";
|
||||
break;
|
||||
case SPV_MSG_INFO:
|
||||
case SPV_MSG_DEBUG:
|
||||
out << "info: ";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (source)
|
||||
{
|
||||
out << source << ":";
|
||||
}
|
||||
out << position.line << ":" << position.column << ":" << position.index << ":";
|
||||
if (message)
|
||||
{
|
||||
out << " " << message;
|
||||
}
|
||||
out << std::endl;
|
||||
});
|
||||
|
||||
// If debug (specifically source line info) is being generated, propagate
|
||||
// line information into all SPIR-V instructions. This avoids loss of
|
||||
// information when instructions are deleted or moved. Later, remove
|
||||
// redundant information to minimize final SPRIR-V size.
|
||||
if (options->generateDebugInfo) {
|
||||
optimizer.RegisterPass(spvtools::CreatePropagateLineInfoPass());
|
||||
}
|
||||
optimizer.RegisterPass(spvtools::CreateWrapOpKillPass());
|
||||
optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass());
|
||||
optimizer.RegisterPass(spvtools::CreateMergeReturnPass());
|
||||
optimizer.RegisterPass(spvtools::CreateInlineExhaustivePass());
|
||||
optimizer.RegisterPass(spvtools::CreateEliminateDeadFunctionsPass());
|
||||
optimizer.RegisterPass(spvtools::CreateScalarReplacementPass());
|
||||
optimizer.RegisterPass(spvtools::CreateLocalAccessChainConvertPass());
|
||||
optimizer.RegisterPass(spvtools::CreateLocalSingleBlockLoadStoreElimPass());
|
||||
optimizer.RegisterPass(spvtools::CreateLocalSingleStoreElimPass());
|
||||
optimizer.RegisterPass(spvtools::CreateSimplificationPass());
|
||||
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
|
||||
optimizer.RegisterPass(spvtools::CreateVectorDCEPass());
|
||||
optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass());
|
||||
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
|
||||
optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass());
|
||||
optimizer.RegisterPass(spvtools::CreateBlockMergePass());
|
||||
optimizer.RegisterPass(spvtools::CreateLocalMultiStoreElimPass());
|
||||
optimizer.RegisterPass(spvtools::CreateIfConversionPass());
|
||||
optimizer.RegisterPass(spvtools::CreateSimplificationPass());
|
||||
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
|
||||
optimizer.RegisterPass(spvtools::CreateVectorDCEPass());
|
||||
optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass());
|
||||
if (options->optimizeSize) {
|
||||
optimizer.RegisterPass(spvtools::CreateRedundancyEliminationPass());
|
||||
}
|
||||
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
|
||||
optimizer.RegisterPass(spvtools::CreateCFGCleanupPass());
|
||||
if (options->generateDebugInfo) {
|
||||
optimizer.RegisterPass(spvtools::CreateRedundantLineInfoElimPass());
|
||||
}
|
||||
|
||||
spvtools::OptimizerOptions spvOptOptions;
|
||||
optimizer.SetTargetEnv(MapToSpirvToolsEnv(intermediate.getSpv(), logger));
|
||||
spvOptOptions.set_run_validator(false); // The validator may run as a separate step later on
|
||||
optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);
|
||||
}
|
||||
|
||||
}; // end namespace glslang
|
||||
|
||||
#endif
|
||||
@@ -1,82 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2014-2016 LunarG, Inc.
|
||||
// Copyright (C) 2018 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//
|
||||
// Call into SPIRV-Tools to disassemble, validate, and optimize.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef GLSLANG_SPV_TOOLS_H
|
||||
#define GLSLANG_SPV_TOOLS_H
|
||||
|
||||
#ifdef ENABLE_OPT
|
||||
#include <vector>
|
||||
#include <ostream>
|
||||
#endif
|
||||
|
||||
#include "glslang/MachineIndependent/localintermediate.h"
|
||||
#include "Logger.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
struct SpvOptions {
|
||||
SpvOptions() : generateDebugInfo(false), disableOptimizer(true),
|
||||
optimizeSize(false), disassemble(false), validate(false) { }
|
||||
bool generateDebugInfo;
|
||||
bool disableOptimizer;
|
||||
bool optimizeSize;
|
||||
bool disassemble;
|
||||
bool validate;
|
||||
};
|
||||
|
||||
#ifdef ENABLE_OPT
|
||||
|
||||
// Use the SPIRV-Tools disassembler to print SPIR-V.
|
||||
void SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv);
|
||||
|
||||
// Apply the SPIRV-Tools validator to generated SPIR-V.
|
||||
void SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
|
||||
spv::SpvBuildLogger*, bool prelegalization);
|
||||
|
||||
// Apply the SPIRV-Tools optimizer to generated SPIR-V, for the purpose of
|
||||
// legalizing HLSL SPIR-V.
|
||||
void SpirvToolsLegalize(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
|
||||
spv::SpvBuildLogger*, const SpvOptions*);
|
||||
|
||||
#endif
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // GLSLANG_SPV_TOOLS_H
|
||||
@@ -1,81 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef LIBSPIRV_UTIL_BITUTILS_H_
|
||||
#define LIBSPIRV_UTIL_BITUTILS_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
namespace spvutils {
|
||||
|
||||
// Performs a bitwise copy of source to the destination type Dest.
|
||||
template <typename Dest, typename Src>
|
||||
Dest BitwiseCast(Src source) {
|
||||
Dest dest;
|
||||
static_assert(sizeof(source) == sizeof(dest),
|
||||
"BitwiseCast: Source and destination must have the same size");
|
||||
std::memcpy(static_cast<void*>(&dest), &source, sizeof(dest));
|
||||
return dest;
|
||||
}
|
||||
|
||||
// SetBits<T, First, Num> returns an integer of type <T> with bits set
|
||||
// for position <First> through <First + Num - 1>, counting from the least
|
||||
// significant bit. In particular when Num == 0, no positions are set to 1.
|
||||
// A static assert will be triggered if First + Num > sizeof(T) * 8, that is,
|
||||
// a bit that will not fit in the underlying type is set.
|
||||
template <typename T, size_t First = 0, size_t Num = 0>
|
||||
struct SetBits {
|
||||
static_assert(First < sizeof(T) * 8,
|
||||
"Tried to set a bit that is shifted too far.");
|
||||
const static T get = (T(1) << First) | SetBits<T, First + 1, Num - 1>::get;
|
||||
};
|
||||
|
||||
template <typename T, size_t Last>
|
||||
struct SetBits<T, Last, 0> {
|
||||
const static T get = T(0);
|
||||
};
|
||||
|
||||
// This is all compile-time so we can put our tests right here.
|
||||
static_assert(SetBits<uint32_t, 0, 0>::get == uint32_t(0x00000000),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint32_t, 0, 1>::get == uint32_t(0x00000001),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint32_t, 31, 1>::get == uint32_t(0x80000000),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint32_t, 1, 2>::get == uint32_t(0x00000006),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint32_t, 30, 2>::get == uint32_t(0xc0000000),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint32_t, 0, 31>::get == uint32_t(0x7FFFFFFF),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint32_t, 0, 32>::get == uint32_t(0xFFFFFFFF),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint32_t, 16, 16>::get == uint32_t(0xFFFF0000),
|
||||
"SetBits failed");
|
||||
|
||||
static_assert(SetBits<uint64_t, 0, 1>::get == uint64_t(0x0000000000000001LL),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint64_t, 63, 1>::get == uint64_t(0x8000000000000000LL),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint64_t, 62, 2>::get == uint64_t(0xc000000000000000LL),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint64_t, 31, 1>::get == uint64_t(0x0000000080000000LL),
|
||||
"SetBits failed");
|
||||
static_assert(SetBits<uint64_t, 16, 16>::get == uint64_t(0x00000000FFFF0000LL),
|
||||
"SetBits failed");
|
||||
|
||||
} // namespace spvutils
|
||||
|
||||
#endif // LIBSPIRV_UTIL_BITUTILS_H_
|
||||
@@ -1,743 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2014-2015 LunarG, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//
|
||||
// Disassembler for SPIR-V.
|
||||
//
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <iomanip>
|
||||
#include <stack>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
|
||||
#include "disassemble.h"
|
||||
#include "doc.h"
|
||||
#include "SpvTools.h"
|
||||
|
||||
namespace spv {
|
||||
extern "C" {
|
||||
// Include C-based headers that don't have a namespace
|
||||
#include "GLSL.std.450.h"
|
||||
#include "GLSL.ext.AMD.h"
|
||||
#include "GLSL.ext.NV.h"
|
||||
}
|
||||
}
|
||||
const char* GlslStd450DebugNames[spv::GLSLstd450Count];
|
||||
|
||||
namespace spv {
|
||||
|
||||
static const char* GLSLextAMDGetDebugNames(const char*, unsigned);
|
||||
static const char* GLSLextNVGetDebugNames(const char*, unsigned);
|
||||
|
||||
static void Kill(std::ostream& out, const char* message)
|
||||
{
|
||||
out << std::endl << "Disassembly failed: " << message << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// used to identify the extended instruction library imported when printing
|
||||
enum ExtInstSet {
|
||||
GLSL450Inst,
|
||||
GLSLextAMDInst,
|
||||
GLSLextNVInst,
|
||||
OpenCLExtInst,
|
||||
NonSemanticDebugPrintfExtInst,
|
||||
};
|
||||
|
||||
// Container class for a single instance of a SPIR-V stream, with methods for disassembly.
|
||||
class SpirvStream {
|
||||
public:
|
||||
SpirvStream(std::ostream& out, const std::vector<unsigned int>& stream) : out(out), stream(stream), word(0), nextNestedControl(0) { }
|
||||
virtual ~SpirvStream() { }
|
||||
|
||||
void validate();
|
||||
void processInstructions();
|
||||
|
||||
protected:
|
||||
SpirvStream(const SpirvStream&);
|
||||
SpirvStream& operator=(const SpirvStream&);
|
||||
Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : OpNop; }
|
||||
|
||||
// Output methods
|
||||
void outputIndent();
|
||||
void formatId(Id id, std::stringstream&);
|
||||
void outputResultId(Id id);
|
||||
void outputTypeId(Id id);
|
||||
void outputId(Id id);
|
||||
void outputMask(OperandClass operandClass, unsigned mask);
|
||||
void disassembleImmediates(int numOperands);
|
||||
void disassembleIds(int numOperands);
|
||||
int disassembleString();
|
||||
void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands);
|
||||
|
||||
// Data
|
||||
std::ostream& out; // where to write the disassembly
|
||||
const std::vector<unsigned int>& stream; // the actual word stream
|
||||
int size; // the size of the word stream
|
||||
int word; // the next word of the stream to read
|
||||
|
||||
// map each <id> to the instruction that created it
|
||||
Id bound;
|
||||
std::vector<unsigned int> idInstruction; // the word offset into the stream where the instruction for result [id] starts; 0 if not yet seen (forward reference or function parameter)
|
||||
|
||||
std::vector<std::string> idDescriptor; // the best text string known for explaining the <id>
|
||||
|
||||
// schema
|
||||
unsigned int schema;
|
||||
|
||||
// stack of structured-merge points
|
||||
std::stack<Id> nestedControl;
|
||||
Id nextNestedControl; // need a slight delay for when we are nested
|
||||
};
|
||||
|
||||
void SpirvStream::validate()
|
||||
{
|
||||
size = (int)stream.size();
|
||||
if (size < 4)
|
||||
Kill(out, "stream is too short");
|
||||
|
||||
// Magic number
|
||||
if (stream[word++] != MagicNumber) {
|
||||
out << "Bad magic number";
|
||||
return;
|
||||
}
|
||||
|
||||
// Version
|
||||
out << "// Module Version " << std::hex << stream[word++] << std::endl;
|
||||
|
||||
// Generator's magic number
|
||||
out << "// Generated by (magic number): " << std::hex << stream[word++] << std::dec << std::endl;
|
||||
|
||||
// Result <id> bound
|
||||
bound = stream[word++];
|
||||
idInstruction.resize(bound);
|
||||
idDescriptor.resize(bound);
|
||||
out << "// Id's are bound by " << bound << std::endl;
|
||||
out << std::endl;
|
||||
|
||||
// Reserved schema, must be 0 for now
|
||||
schema = stream[word++];
|
||||
if (schema != 0)
|
||||
Kill(out, "bad schema, must be 0");
|
||||
}
|
||||
|
||||
// Loop over all the instructions, in order, processing each.
|
||||
// Boiler plate for each is handled here directly, the rest is dispatched.
|
||||
void SpirvStream::processInstructions()
|
||||
{
|
||||
// Instructions
|
||||
while (word < size) {
|
||||
int instructionStart = word;
|
||||
|
||||
// Instruction wordCount and opcode
|
||||
unsigned int firstWord = stream[word];
|
||||
unsigned wordCount = firstWord >> WordCountShift;
|
||||
Op opCode = (Op)(firstWord & OpCodeMask);
|
||||
int nextInst = word + wordCount;
|
||||
++word;
|
||||
|
||||
// Presence of full instruction
|
||||
if (nextInst > size)
|
||||
Kill(out, "stream instruction terminated too early");
|
||||
|
||||
// Base for computing number of operands; will be updated as more is learned
|
||||
unsigned numOperands = wordCount - 1;
|
||||
|
||||
// Type <id>
|
||||
Id typeId = 0;
|
||||
if (InstructionDesc[opCode].hasType()) {
|
||||
typeId = stream[word++];
|
||||
--numOperands;
|
||||
}
|
||||
|
||||
// Result <id>
|
||||
Id resultId = 0;
|
||||
if (InstructionDesc[opCode].hasResult()) {
|
||||
resultId = stream[word++];
|
||||
--numOperands;
|
||||
|
||||
// save instruction for future reference
|
||||
idInstruction[resultId] = instructionStart;
|
||||
}
|
||||
|
||||
outputResultId(resultId);
|
||||
outputTypeId(typeId);
|
||||
outputIndent();
|
||||
|
||||
// Hand off the Op and all its operands
|
||||
disassembleInstruction(resultId, typeId, opCode, numOperands);
|
||||
if (word != nextInst) {
|
||||
out << " ERROR, incorrect number of operands consumed. At " << word << " instead of " << nextInst << " instruction start was " << instructionStart;
|
||||
word = nextInst;
|
||||
}
|
||||
out << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void SpirvStream::outputIndent()
|
||||
{
|
||||
for (int i = 0; i < (int)nestedControl.size(); ++i)
|
||||
out << " ";
|
||||
}
|
||||
|
||||
void SpirvStream::formatId(Id id, std::stringstream& idStream)
|
||||
{
|
||||
if (id != 0) {
|
||||
// On instructions with no IDs, this is called with "0", which does not
|
||||
// have to be within ID bounds on null shaders.
|
||||
if (id >= bound)
|
||||
Kill(out, "Bad <id>");
|
||||
|
||||
idStream << id;
|
||||
if (idDescriptor[id].size() > 0)
|
||||
idStream << "(" << idDescriptor[id] << ")";
|
||||
}
|
||||
}
|
||||
|
||||
void SpirvStream::outputResultId(Id id)
|
||||
{
|
||||
const int width = 16;
|
||||
std::stringstream idStream;
|
||||
formatId(id, idStream);
|
||||
out << std::setw(width) << std::right << idStream.str();
|
||||
if (id != 0)
|
||||
out << ":";
|
||||
else
|
||||
out << " ";
|
||||
|
||||
if (nestedControl.size() && id == nestedControl.top())
|
||||
nestedControl.pop();
|
||||
}
|
||||
|
||||
void SpirvStream::outputTypeId(Id id)
|
||||
{
|
||||
const int width = 12;
|
||||
std::stringstream idStream;
|
||||
formatId(id, idStream);
|
||||
out << std::setw(width) << std::right << idStream.str() << " ";
|
||||
}
|
||||
|
||||
void SpirvStream::outputId(Id id)
|
||||
{
|
||||
if (id >= bound)
|
||||
Kill(out, "Bad <id>");
|
||||
|
||||
out << id;
|
||||
if (idDescriptor[id].size() > 0)
|
||||
out << "(" << idDescriptor[id] << ")";
|
||||
}
|
||||
|
||||
void SpirvStream::outputMask(OperandClass operandClass, unsigned mask)
|
||||
{
|
||||
if (mask == 0)
|
||||
out << "None";
|
||||
else {
|
||||
for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) {
|
||||
if (mask & (1 << m))
|
||||
out << OperandClassParams[operandClass].getName(m) << " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpirvStream::disassembleImmediates(int numOperands)
|
||||
{
|
||||
for (int i = 0; i < numOperands; ++i) {
|
||||
out << stream[word++];
|
||||
if (i < numOperands - 1)
|
||||
out << " ";
|
||||
}
|
||||
}
|
||||
|
||||
void SpirvStream::disassembleIds(int numOperands)
|
||||
{
|
||||
for (int i = 0; i < numOperands; ++i) {
|
||||
outputId(stream[word++]);
|
||||
if (i < numOperands - 1)
|
||||
out << " ";
|
||||
}
|
||||
}
|
||||
|
||||
// return the number of operands consumed by the string
|
||||
int SpirvStream::disassembleString()
|
||||
{
|
||||
int startWord = word;
|
||||
|
||||
out << " \"";
|
||||
|
||||
const char* wordString;
|
||||
bool done = false;
|
||||
do {
|
||||
unsigned int content = stream[word];
|
||||
wordString = (const char*)&content;
|
||||
for (int charCount = 0; charCount < 4; ++charCount) {
|
||||
if (*wordString == 0) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
out << *(wordString++);
|
||||
}
|
||||
++word;
|
||||
} while (! done);
|
||||
|
||||
out << "\"";
|
||||
|
||||
return word - startWord;
|
||||
}
|
||||
|
||||
void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands)
|
||||
{
|
||||
// Process the opcode
|
||||
|
||||
out << (OpcodeString(opCode) + 2); // leave out the "Op"
|
||||
|
||||
if (opCode == OpLoopMerge || opCode == OpSelectionMerge)
|
||||
nextNestedControl = stream[word];
|
||||
else if (opCode == OpBranchConditional || opCode == OpSwitch) {
|
||||
if (nextNestedControl) {
|
||||
nestedControl.push(nextNestedControl);
|
||||
nextNestedControl = 0;
|
||||
}
|
||||
} else if (opCode == OpExtInstImport) {
|
||||
idDescriptor[resultId] = (const char*)(&stream[word]);
|
||||
}
|
||||
else {
|
||||
if (resultId != 0 && idDescriptor[resultId].size() == 0) {
|
||||
switch (opCode) {
|
||||
case OpTypeInt:
|
||||
switch (stream[word]) {
|
||||
case 8: idDescriptor[resultId] = "int8_t"; break;
|
||||
case 16: idDescriptor[resultId] = "int16_t"; break;
|
||||
default: assert(0); // fallthrough
|
||||
case 32: idDescriptor[resultId] = "int"; break;
|
||||
case 64: idDescriptor[resultId] = "int64_t"; break;
|
||||
}
|
||||
break;
|
||||
case OpTypeFloat:
|
||||
switch (stream[word]) {
|
||||
case 16: idDescriptor[resultId] = "float16_t"; break;
|
||||
default: assert(0); // fallthrough
|
||||
case 32: idDescriptor[resultId] = "float"; break;
|
||||
case 64: idDescriptor[resultId] = "float64_t"; break;
|
||||
}
|
||||
break;
|
||||
case OpTypeBool:
|
||||
idDescriptor[resultId] = "bool";
|
||||
break;
|
||||
case OpTypeStruct:
|
||||
idDescriptor[resultId] = "struct";
|
||||
break;
|
||||
case OpTypePointer:
|
||||
idDescriptor[resultId] = "ptr";
|
||||
break;
|
||||
case OpTypeVector:
|
||||
if (idDescriptor[stream[word]].size() > 0) {
|
||||
idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1);
|
||||
if (strstr(idDescriptor[stream[word]].c_str(), "8")) {
|
||||
idDescriptor[resultId].append("8");
|
||||
}
|
||||
if (strstr(idDescriptor[stream[word]].c_str(), "16")) {
|
||||
idDescriptor[resultId].append("16");
|
||||
}
|
||||
if (strstr(idDescriptor[stream[word]].c_str(), "64")) {
|
||||
idDescriptor[resultId].append("64");
|
||||
}
|
||||
}
|
||||
idDescriptor[resultId].append("vec");
|
||||
switch (stream[word + 1]) {
|
||||
case 2: idDescriptor[resultId].append("2"); break;
|
||||
case 3: idDescriptor[resultId].append("3"); break;
|
||||
case 4: idDescriptor[resultId].append("4"); break;
|
||||
case 8: idDescriptor[resultId].append("8"); break;
|
||||
case 16: idDescriptor[resultId].append("16"); break;
|
||||
case 32: idDescriptor[resultId].append("32"); break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process the operands. Note, a new context-dependent set could be
|
||||
// swapped in mid-traversal.
|
||||
|
||||
// Handle images specially, so can put out helpful strings.
|
||||
if (opCode == OpTypeImage) {
|
||||
out << " ";
|
||||
disassembleIds(1);
|
||||
out << " " << DimensionString((Dim)stream[word++]);
|
||||
out << (stream[word++] != 0 ? " depth" : "");
|
||||
out << (stream[word++] != 0 ? " array" : "");
|
||||
out << (stream[word++] != 0 ? " multi-sampled" : "");
|
||||
switch (stream[word++]) {
|
||||
case 0: out << " runtime"; break;
|
||||
case 1: out << " sampled"; break;
|
||||
case 2: out << " nonsampled"; break;
|
||||
}
|
||||
out << " format:" << ImageFormatString((ImageFormat)stream[word++]);
|
||||
|
||||
if (numOperands == 8) {
|
||||
out << " " << AccessQualifierString(stream[word++]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle all the parameterized operands
|
||||
for (int op = 0; op < InstructionDesc[opCode].operands.getNum() && numOperands > 0; ++op) {
|
||||
out << " ";
|
||||
OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op);
|
||||
switch (operandClass) {
|
||||
case OperandId:
|
||||
case OperandScope:
|
||||
case OperandMemorySemantics:
|
||||
disassembleIds(1);
|
||||
--numOperands;
|
||||
// Get names for printing "(XXX)" for readability, *after* this id
|
||||
if (opCode == OpName)
|
||||
idDescriptor[stream[word - 1]] = (const char*)(&stream[word]);
|
||||
break;
|
||||
case OperandVariableIds:
|
||||
disassembleIds(numOperands);
|
||||
return;
|
||||
case OperandImageOperands:
|
||||
outputMask(OperandImageOperands, stream[word++]);
|
||||
--numOperands;
|
||||
disassembleIds(numOperands);
|
||||
return;
|
||||
case OperandOptionalLiteral:
|
||||
case OperandVariableLiterals:
|
||||
if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) ||
|
||||
(opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) {
|
||||
out << BuiltInString(stream[word++]);
|
||||
--numOperands;
|
||||
++op;
|
||||
}
|
||||
disassembleImmediates(numOperands);
|
||||
return;
|
||||
case OperandVariableIdLiteral:
|
||||
while (numOperands > 0) {
|
||||
out << std::endl;
|
||||
outputResultId(0);
|
||||
outputTypeId(0);
|
||||
outputIndent();
|
||||
out << " Type ";
|
||||
disassembleIds(1);
|
||||
out << ", member ";
|
||||
disassembleImmediates(1);
|
||||
numOperands -= 2;
|
||||
}
|
||||
return;
|
||||
case OperandVariableLiteralId:
|
||||
while (numOperands > 0) {
|
||||
out << std::endl;
|
||||
outputResultId(0);
|
||||
outputTypeId(0);
|
||||
outputIndent();
|
||||
out << " case ";
|
||||
disassembleImmediates(1);
|
||||
out << ": ";
|
||||
disassembleIds(1);
|
||||
numOperands -= 2;
|
||||
}
|
||||
return;
|
||||
case OperandLiteralNumber:
|
||||
disassembleImmediates(1);
|
||||
--numOperands;
|
||||
if (opCode == OpExtInst) {
|
||||
ExtInstSet extInstSet = GLSL450Inst;
|
||||
const char* name = idDescriptor[stream[word - 2]].c_str();
|
||||
if (strcmp("OpenCL.std", name) == 0) {
|
||||
extInstSet = OpenCLExtInst;
|
||||
} else if (strcmp("OpenCL.DebugInfo.100", name) == 0) {
|
||||
extInstSet = OpenCLExtInst;
|
||||
} else if (strcmp("NonSemantic.DebugPrintf", name) == 0) {
|
||||
extInstSet = NonSemanticDebugPrintfExtInst;
|
||||
} else if (strcmp(spv::E_SPV_AMD_shader_ballot, name) == 0 ||
|
||||
strcmp(spv::E_SPV_AMD_shader_trinary_minmax, name) == 0 ||
|
||||
strcmp(spv::E_SPV_AMD_shader_explicit_vertex_parameter, name) == 0 ||
|
||||
strcmp(spv::E_SPV_AMD_gcn_shader, name) == 0) {
|
||||
extInstSet = GLSLextAMDInst;
|
||||
} else if (strcmp(spv::E_SPV_NV_sample_mask_override_coverage, name) == 0 ||
|
||||
strcmp(spv::E_SPV_NV_geometry_shader_passthrough, name) == 0 ||
|
||||
strcmp(spv::E_SPV_NV_viewport_array2, name) == 0 ||
|
||||
strcmp(spv::E_SPV_NVX_multiview_per_view_attributes, name) == 0 ||
|
||||
strcmp(spv::E_SPV_NV_fragment_shader_barycentric, name) == 0 ||
|
||||
strcmp(spv::E_SPV_NV_mesh_shader, name) == 0) {
|
||||
extInstSet = GLSLextNVInst;
|
||||
}
|
||||
unsigned entrypoint = stream[word - 1];
|
||||
if (extInstSet == GLSL450Inst) {
|
||||
if (entrypoint < GLSLstd450Count) {
|
||||
out << "(" << GlslStd450DebugNames[entrypoint] << ")";
|
||||
}
|
||||
} else if (extInstSet == GLSLextAMDInst) {
|
||||
out << "(" << GLSLextAMDGetDebugNames(name, entrypoint) << ")";
|
||||
}
|
||||
else if (extInstSet == GLSLextNVInst) {
|
||||
out << "(" << GLSLextNVGetDebugNames(name, entrypoint) << ")";
|
||||
} else if (extInstSet == NonSemanticDebugPrintfExtInst) {
|
||||
out << "(DebugPrintf)";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OperandOptionalLiteralString:
|
||||
case OperandLiteralString:
|
||||
numOperands -= disassembleString();
|
||||
break;
|
||||
case OperandMemoryAccess:
|
||||
outputMask(OperandMemoryAccess, stream[word++]);
|
||||
--numOperands;
|
||||
// Aligned is the only memory access operand that uses an immediate
|
||||
// value, and it is also the first operand that uses a value at all.
|
||||
if (stream[word-1] & MemoryAccessAlignedMask) {
|
||||
disassembleImmediates(1);
|
||||
numOperands--;
|
||||
if (numOperands)
|
||||
out << " ";
|
||||
}
|
||||
disassembleIds(numOperands);
|
||||
return;
|
||||
default:
|
||||
assert(operandClass >= OperandSource && operandClass < OperandOpcode);
|
||||
|
||||
if (OperandClassParams[operandClass].bitmask)
|
||||
outputMask(operandClass, stream[word++]);
|
||||
else
|
||||
out << OperandClassParams[operandClass].getName(stream[word++]);
|
||||
--numOperands;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void GLSLstd450GetDebugNames(const char** names)
|
||||
{
|
||||
for (int i = 0; i < GLSLstd450Count; ++i)
|
||||
names[i] = "Unknown";
|
||||
|
||||
names[GLSLstd450Round] = "Round";
|
||||
names[GLSLstd450RoundEven] = "RoundEven";
|
||||
names[GLSLstd450Trunc] = "Trunc";
|
||||
names[GLSLstd450FAbs] = "FAbs";
|
||||
names[GLSLstd450SAbs] = "SAbs";
|
||||
names[GLSLstd450FSign] = "FSign";
|
||||
names[GLSLstd450SSign] = "SSign";
|
||||
names[GLSLstd450Floor] = "Floor";
|
||||
names[GLSLstd450Ceil] = "Ceil";
|
||||
names[GLSLstd450Fract] = "Fract";
|
||||
names[GLSLstd450Radians] = "Radians";
|
||||
names[GLSLstd450Degrees] = "Degrees";
|
||||
names[GLSLstd450Sin] = "Sin";
|
||||
names[GLSLstd450Cos] = "Cos";
|
||||
names[GLSLstd450Tan] = "Tan";
|
||||
names[GLSLstd450Asin] = "Asin";
|
||||
names[GLSLstd450Acos] = "Acos";
|
||||
names[GLSLstd450Atan] = "Atan";
|
||||
names[GLSLstd450Sinh] = "Sinh";
|
||||
names[GLSLstd450Cosh] = "Cosh";
|
||||
names[GLSLstd450Tanh] = "Tanh";
|
||||
names[GLSLstd450Asinh] = "Asinh";
|
||||
names[GLSLstd450Acosh] = "Acosh";
|
||||
names[GLSLstd450Atanh] = "Atanh";
|
||||
names[GLSLstd450Atan2] = "Atan2";
|
||||
names[GLSLstd450Pow] = "Pow";
|
||||
names[GLSLstd450Exp] = "Exp";
|
||||
names[GLSLstd450Log] = "Log";
|
||||
names[GLSLstd450Exp2] = "Exp2";
|
||||
names[GLSLstd450Log2] = "Log2";
|
||||
names[GLSLstd450Sqrt] = "Sqrt";
|
||||
names[GLSLstd450InverseSqrt] = "InverseSqrt";
|
||||
names[GLSLstd450Determinant] = "Determinant";
|
||||
names[GLSLstd450MatrixInverse] = "MatrixInverse";
|
||||
names[GLSLstd450Modf] = "Modf";
|
||||
names[GLSLstd450ModfStruct] = "ModfStruct";
|
||||
names[GLSLstd450FMin] = "FMin";
|
||||
names[GLSLstd450SMin] = "SMin";
|
||||
names[GLSLstd450UMin] = "UMin";
|
||||
names[GLSLstd450FMax] = "FMax";
|
||||
names[GLSLstd450SMax] = "SMax";
|
||||
names[GLSLstd450UMax] = "UMax";
|
||||
names[GLSLstd450FClamp] = "FClamp";
|
||||
names[GLSLstd450SClamp] = "SClamp";
|
||||
names[GLSLstd450UClamp] = "UClamp";
|
||||
names[GLSLstd450FMix] = "FMix";
|
||||
names[GLSLstd450Step] = "Step";
|
||||
names[GLSLstd450SmoothStep] = "SmoothStep";
|
||||
names[GLSLstd450Fma] = "Fma";
|
||||
names[GLSLstd450Frexp] = "Frexp";
|
||||
names[GLSLstd450FrexpStruct] = "FrexpStruct";
|
||||
names[GLSLstd450Ldexp] = "Ldexp";
|
||||
names[GLSLstd450PackSnorm4x8] = "PackSnorm4x8";
|
||||
names[GLSLstd450PackUnorm4x8] = "PackUnorm4x8";
|
||||
names[GLSLstd450PackSnorm2x16] = "PackSnorm2x16";
|
||||
names[GLSLstd450PackUnorm2x16] = "PackUnorm2x16";
|
||||
names[GLSLstd450PackHalf2x16] = "PackHalf2x16";
|
||||
names[GLSLstd450PackDouble2x32] = "PackDouble2x32";
|
||||
names[GLSLstd450UnpackSnorm2x16] = "UnpackSnorm2x16";
|
||||
names[GLSLstd450UnpackUnorm2x16] = "UnpackUnorm2x16";
|
||||
names[GLSLstd450UnpackHalf2x16] = "UnpackHalf2x16";
|
||||
names[GLSLstd450UnpackSnorm4x8] = "UnpackSnorm4x8";
|
||||
names[GLSLstd450UnpackUnorm4x8] = "UnpackUnorm4x8";
|
||||
names[GLSLstd450UnpackDouble2x32] = "UnpackDouble2x32";
|
||||
names[GLSLstd450Length] = "Length";
|
||||
names[GLSLstd450Distance] = "Distance";
|
||||
names[GLSLstd450Cross] = "Cross";
|
||||
names[GLSLstd450Normalize] = "Normalize";
|
||||
names[GLSLstd450FaceForward] = "FaceForward";
|
||||
names[GLSLstd450Reflect] = "Reflect";
|
||||
names[GLSLstd450Refract] = "Refract";
|
||||
names[GLSLstd450FindILsb] = "FindILsb";
|
||||
names[GLSLstd450FindSMsb] = "FindSMsb";
|
||||
names[GLSLstd450FindUMsb] = "FindUMsb";
|
||||
names[GLSLstd450InterpolateAtCentroid] = "InterpolateAtCentroid";
|
||||
names[GLSLstd450InterpolateAtSample] = "InterpolateAtSample";
|
||||
names[GLSLstd450InterpolateAtOffset] = "InterpolateAtOffset";
|
||||
names[GLSLstd450NMin] = "NMin";
|
||||
names[GLSLstd450NMax] = "NMax";
|
||||
names[GLSLstd450NClamp] = "NClamp";
|
||||
}
|
||||
|
||||
static const char* GLSLextAMDGetDebugNames(const char* name, unsigned entrypoint)
|
||||
{
|
||||
if (strcmp(name, spv::E_SPV_AMD_shader_ballot) == 0) {
|
||||
switch (entrypoint) {
|
||||
case SwizzleInvocationsAMD: return "SwizzleInvocationsAMD";
|
||||
case SwizzleInvocationsMaskedAMD: return "SwizzleInvocationsMaskedAMD";
|
||||
case WriteInvocationAMD: return "WriteInvocationAMD";
|
||||
case MbcntAMD: return "MbcntAMD";
|
||||
default: return "Bad";
|
||||
}
|
||||
} else if (strcmp(name, spv::E_SPV_AMD_shader_trinary_minmax) == 0) {
|
||||
switch (entrypoint) {
|
||||
case FMin3AMD: return "FMin3AMD";
|
||||
case UMin3AMD: return "UMin3AMD";
|
||||
case SMin3AMD: return "SMin3AMD";
|
||||
case FMax3AMD: return "FMax3AMD";
|
||||
case UMax3AMD: return "UMax3AMD";
|
||||
case SMax3AMD: return "SMax3AMD";
|
||||
case FMid3AMD: return "FMid3AMD";
|
||||
case UMid3AMD: return "UMid3AMD";
|
||||
case SMid3AMD: return "SMid3AMD";
|
||||
default: return "Bad";
|
||||
}
|
||||
} else if (strcmp(name, spv::E_SPV_AMD_shader_explicit_vertex_parameter) == 0) {
|
||||
switch (entrypoint) {
|
||||
case InterpolateAtVertexAMD: return "InterpolateAtVertexAMD";
|
||||
default: return "Bad";
|
||||
}
|
||||
}
|
||||
else if (strcmp(name, spv::E_SPV_AMD_gcn_shader) == 0) {
|
||||
switch (entrypoint) {
|
||||
case CubeFaceIndexAMD: return "CubeFaceIndexAMD";
|
||||
case CubeFaceCoordAMD: return "CubeFaceCoordAMD";
|
||||
case TimeAMD: return "TimeAMD";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return "Bad";
|
||||
}
|
||||
|
||||
static const char* GLSLextNVGetDebugNames(const char* name, unsigned entrypoint)
|
||||
{
|
||||
if (strcmp(name, spv::E_SPV_NV_sample_mask_override_coverage) == 0 ||
|
||||
strcmp(name, spv::E_SPV_NV_geometry_shader_passthrough) == 0 ||
|
||||
strcmp(name, spv::E_ARB_shader_viewport_layer_array) == 0 ||
|
||||
strcmp(name, spv::E_SPV_NV_viewport_array2) == 0 ||
|
||||
strcmp(name, spv::E_SPV_NVX_multiview_per_view_attributes) == 0 ||
|
||||
strcmp(name, spv::E_SPV_NV_fragment_shader_barycentric) == 0 ||
|
||||
strcmp(name, spv::E_SPV_NV_mesh_shader) == 0 ||
|
||||
strcmp(name, spv::E_SPV_NV_shader_image_footprint) == 0) {
|
||||
switch (entrypoint) {
|
||||
// NV builtins
|
||||
case BuiltInViewportMaskNV: return "ViewportMaskNV";
|
||||
case BuiltInSecondaryPositionNV: return "SecondaryPositionNV";
|
||||
case BuiltInSecondaryViewportMaskNV: return "SecondaryViewportMaskNV";
|
||||
case BuiltInPositionPerViewNV: return "PositionPerViewNV";
|
||||
case BuiltInViewportMaskPerViewNV: return "ViewportMaskPerViewNV";
|
||||
case BuiltInBaryCoordNV: return "BaryCoordNV";
|
||||
case BuiltInBaryCoordNoPerspNV: return "BaryCoordNoPerspNV";
|
||||
case BuiltInTaskCountNV: return "TaskCountNV";
|
||||
case BuiltInPrimitiveCountNV: return "PrimitiveCountNV";
|
||||
case BuiltInPrimitiveIndicesNV: return "PrimitiveIndicesNV";
|
||||
case BuiltInClipDistancePerViewNV: return "ClipDistancePerViewNV";
|
||||
case BuiltInCullDistancePerViewNV: return "CullDistancePerViewNV";
|
||||
case BuiltInLayerPerViewNV: return "LayerPerViewNV";
|
||||
case BuiltInMeshViewCountNV: return "MeshViewCountNV";
|
||||
case BuiltInMeshViewIndicesNV: return "MeshViewIndicesNV";
|
||||
|
||||
// NV Capabilities
|
||||
case CapabilityGeometryShaderPassthroughNV: return "GeometryShaderPassthroughNV";
|
||||
case CapabilityShaderViewportMaskNV: return "ShaderViewportMaskNV";
|
||||
case CapabilityShaderStereoViewNV: return "ShaderStereoViewNV";
|
||||
case CapabilityPerViewAttributesNV: return "PerViewAttributesNV";
|
||||
case CapabilityFragmentBarycentricNV: return "FragmentBarycentricNV";
|
||||
case CapabilityMeshShadingNV: return "MeshShadingNV";
|
||||
case CapabilityImageFootprintNV: return "ImageFootprintNV";
|
||||
case CapabilitySampleMaskOverrideCoverageNV:return "SampleMaskOverrideCoverageNV";
|
||||
|
||||
// NV Decorations
|
||||
case DecorationOverrideCoverageNV: return "OverrideCoverageNV";
|
||||
case DecorationPassthroughNV: return "PassthroughNV";
|
||||
case DecorationViewportRelativeNV: return "ViewportRelativeNV";
|
||||
case DecorationSecondaryViewportRelativeNV: return "SecondaryViewportRelativeNV";
|
||||
case DecorationPerVertexNV: return "PerVertexNV";
|
||||
case DecorationPerPrimitiveNV: return "PerPrimitiveNV";
|
||||
case DecorationPerViewNV: return "PerViewNV";
|
||||
case DecorationPerTaskNV: return "PerTaskNV";
|
||||
|
||||
default: return "Bad";
|
||||
}
|
||||
}
|
||||
return "Bad";
|
||||
}
|
||||
|
||||
void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
|
||||
{
|
||||
SpirvStream SpirvStream(out, stream);
|
||||
spv::Parameterize();
|
||||
GLSLstd450GetDebugNames(GlslStd450DebugNames);
|
||||
SpirvStream.validate();
|
||||
SpirvStream.processInstructions();
|
||||
}
|
||||
|
||||
}; // end namespace spv
|
||||
@@ -1,53 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2014-2015 LunarG, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//
|
||||
// Disassembler for SPIR-V.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef disassembler_H
|
||||
#define disassembler_H
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
namespace spv {
|
||||
|
||||
// disassemble with glslang custom disassembler
|
||||
void Disassemble(std::ostream& out, const std::vector<unsigned int>&);
|
||||
|
||||
} // end namespace spv
|
||||
|
||||
#endif // disassembler_H
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,258 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2014-2015 LunarG, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//
|
||||
// Parameterize the SPIR-V enumerants.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "spirv.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace spv {
|
||||
|
||||
// Fill in all the parameters
|
||||
void Parameterize();
|
||||
|
||||
// Return the English names of all the enums.
|
||||
const char* SourceString(int);
|
||||
const char* AddressingString(int);
|
||||
const char* MemoryString(int);
|
||||
const char* ExecutionModelString(int);
|
||||
const char* ExecutionModeString(int);
|
||||
const char* StorageClassString(int);
|
||||
const char* DecorationString(int);
|
||||
const char* BuiltInString(int);
|
||||
const char* DimensionString(int);
|
||||
const char* SelectControlString(int);
|
||||
const char* LoopControlString(int);
|
||||
const char* FunctionControlString(int);
|
||||
const char* SamplerAddressingModeString(int);
|
||||
const char* SamplerFilterModeString(int);
|
||||
const char* ImageFormatString(int);
|
||||
const char* ImageChannelOrderString(int);
|
||||
const char* ImageChannelTypeString(int);
|
||||
const char* ImageChannelDataTypeString(int type);
|
||||
const char* ImageOperandsString(int format);
|
||||
const char* ImageOperands(int);
|
||||
const char* FPFastMathString(int);
|
||||
const char* FPRoundingModeString(int);
|
||||
const char* LinkageTypeString(int);
|
||||
const char* FuncParamAttrString(int);
|
||||
const char* AccessQualifierString(int);
|
||||
const char* MemorySemanticsString(int);
|
||||
const char* MemoryAccessString(int);
|
||||
const char* ExecutionScopeString(int);
|
||||
const char* GroupOperationString(int);
|
||||
const char* KernelEnqueueFlagsString(int);
|
||||
const char* KernelProfilingInfoString(int);
|
||||
const char* CapabilityString(int);
|
||||
const char* OpcodeString(int);
|
||||
const char* ScopeString(int mem);
|
||||
|
||||
// For grouping opcodes into subsections
|
||||
enum OpcodeClass {
|
||||
OpClassMisc,
|
||||
OpClassDebug,
|
||||
OpClassAnnotate,
|
||||
OpClassExtension,
|
||||
OpClassMode,
|
||||
OpClassType,
|
||||
OpClassConstant,
|
||||
OpClassMemory,
|
||||
OpClassFunction,
|
||||
OpClassImage,
|
||||
OpClassConvert,
|
||||
OpClassComposite,
|
||||
OpClassArithmetic,
|
||||
OpClassBit,
|
||||
OpClassRelationalLogical,
|
||||
OpClassDerivative,
|
||||
OpClassFlowControl,
|
||||
OpClassAtomic,
|
||||
OpClassPrimitive,
|
||||
OpClassBarrier,
|
||||
OpClassGroup,
|
||||
OpClassDeviceSideEnqueue,
|
||||
OpClassPipe,
|
||||
|
||||
OpClassCount,
|
||||
OpClassMissing // all instructions start out as missing
|
||||
};
|
||||
|
||||
// For parameterizing operands.
|
||||
enum OperandClass {
|
||||
OperandNone,
|
||||
OperandId,
|
||||
OperandVariableIds,
|
||||
OperandOptionalLiteral,
|
||||
OperandOptionalLiteralString,
|
||||
OperandVariableLiterals,
|
||||
OperandVariableIdLiteral,
|
||||
OperandVariableLiteralId,
|
||||
OperandLiteralNumber,
|
||||
OperandLiteralString,
|
||||
OperandSource,
|
||||
OperandExecutionModel,
|
||||
OperandAddressing,
|
||||
OperandMemory,
|
||||
OperandExecutionMode,
|
||||
OperandStorage,
|
||||
OperandDimensionality,
|
||||
OperandSamplerAddressingMode,
|
||||
OperandSamplerFilterMode,
|
||||
OperandSamplerImageFormat,
|
||||
OperandImageChannelOrder,
|
||||
OperandImageChannelDataType,
|
||||
OperandImageOperands,
|
||||
OperandFPFastMath,
|
||||
OperandFPRoundingMode,
|
||||
OperandLinkageType,
|
||||
OperandAccessQualifier,
|
||||
OperandFuncParamAttr,
|
||||
OperandDecoration,
|
||||
OperandBuiltIn,
|
||||
OperandSelect,
|
||||
OperandLoop,
|
||||
OperandFunction,
|
||||
OperandMemorySemantics,
|
||||
OperandMemoryAccess,
|
||||
OperandScope,
|
||||
OperandGroupOperation,
|
||||
OperandKernelEnqueueFlags,
|
||||
OperandKernelProfilingInfo,
|
||||
OperandCapability,
|
||||
|
||||
OperandOpcode,
|
||||
|
||||
OperandCount
|
||||
};
|
||||
|
||||
// Any specific enum can have a set of capabilities that allow it:
|
||||
typedef std::vector<Capability> EnumCaps;
|
||||
|
||||
// Parameterize a set of operands with their OperandClass(es) and descriptions.
|
||||
class OperandParameters {
|
||||
public:
|
||||
OperandParameters() { }
|
||||
void push(OperandClass oc, const char* d, bool opt = false)
|
||||
{
|
||||
opClass.push_back(oc);
|
||||
desc.push_back(d);
|
||||
optional.push_back(opt);
|
||||
}
|
||||
void setOptional();
|
||||
OperandClass getClass(int op) const { return opClass[op]; }
|
||||
const char* getDesc(int op) const { return desc[op]; }
|
||||
bool isOptional(int op) const { return optional[op]; }
|
||||
int getNum() const { return (int)opClass.size(); }
|
||||
|
||||
protected:
|
||||
std::vector<OperandClass> opClass;
|
||||
std::vector<const char*> desc;
|
||||
std::vector<bool> optional;
|
||||
};
|
||||
|
||||
// Parameterize an enumerant
|
||||
class EnumParameters {
|
||||
public:
|
||||
EnumParameters() : desc(0) { }
|
||||
const char* desc;
|
||||
};
|
||||
|
||||
// Parameterize a set of enumerants that form an enum
|
||||
class EnumDefinition : public EnumParameters {
|
||||
public:
|
||||
EnumDefinition() :
|
||||
ceiling(0), bitmask(false), getName(0), enumParams(0), operandParams(0) { }
|
||||
void set(int ceil, const char* (*name)(int), EnumParameters* ep, bool mask = false)
|
||||
{
|
||||
ceiling = ceil;
|
||||
getName = name;
|
||||
bitmask = mask;
|
||||
enumParams = ep;
|
||||
}
|
||||
void setOperands(OperandParameters* op) { operandParams = op; }
|
||||
int ceiling; // ceiling of enumerants
|
||||
bool bitmask; // true if these enumerants combine into a bitmask
|
||||
const char* (*getName)(int); // a function that returns the name for each enumerant value (or shift)
|
||||
EnumParameters* enumParams; // parameters for each individual enumerant
|
||||
OperandParameters* operandParams; // sets of operands
|
||||
};
|
||||
|
||||
// Parameterize an instruction's logical format, including its known set of operands,
|
||||
// per OperandParameters above.
|
||||
class InstructionParameters {
|
||||
public:
|
||||
InstructionParameters() :
|
||||
opDesc("TBD"),
|
||||
opClass(OpClassMissing),
|
||||
typePresent(true), // most normal, only exceptions have to be spelled out
|
||||
resultPresent(true) // most normal, only exceptions have to be spelled out
|
||||
{ }
|
||||
|
||||
void setResultAndType(bool r, bool t)
|
||||
{
|
||||
resultPresent = r;
|
||||
typePresent = t;
|
||||
}
|
||||
|
||||
bool hasResult() const { return resultPresent != 0; }
|
||||
bool hasType() const { return typePresent != 0; }
|
||||
|
||||
const char* opDesc;
|
||||
OpcodeClass opClass;
|
||||
OperandParameters operands;
|
||||
|
||||
protected:
|
||||
int typePresent : 1;
|
||||
int resultPresent : 1;
|
||||
};
|
||||
|
||||
// The set of objects that hold all the instruction/operand
|
||||
// parameterization information.
|
||||
extern InstructionParameters InstructionDesc[];
|
||||
|
||||
// These hold definitions of the enumerants used for operands
|
||||
extern EnumDefinition OperandClassParams[];
|
||||
|
||||
const char* GetOperandDesc(OperandClass operand);
|
||||
void PrintImmediateRow(int imm, const char* name, const EnumParameters* enumParams, bool caps, bool hex = false);
|
||||
const char* AccessQualifierString(int attr);
|
||||
|
||||
void PrintOperands(const OperandParameters& operands, int reservedOperands);
|
||||
|
||||
} // end namespace spv
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,485 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2014 LunarG, Inc.
|
||||
// Copyright (C) 2015-2018 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// SPIRV-IR
|
||||
//
|
||||
// Simple in-memory representation (IR) of SPIRV. Just for holding
|
||||
// Each function's CFG of blocks. Has this hierarchy:
|
||||
// - Module, which is a list of
|
||||
// - Function, which is a list of
|
||||
// - Block, which is a list of
|
||||
// - Instruction
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef spvIR_H
|
||||
#define spvIR_H
|
||||
|
||||
#include "spirv.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace spv {
|
||||
|
||||
class Block;
|
||||
class Function;
|
||||
class Module;
|
||||
|
||||
const Id NoResult = 0;
|
||||
const Id NoType = 0;
|
||||
|
||||
const Decoration NoPrecision = DecorationMax;
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define POTENTIALLY_UNUSED __attribute__((unused))
|
||||
#else
|
||||
# define POTENTIALLY_UNUSED
|
||||
#endif
|
||||
|
||||
POTENTIALLY_UNUSED
|
||||
const MemorySemanticsMask MemorySemanticsAllMemory =
|
||||
(MemorySemanticsMask)(MemorySemanticsUniformMemoryMask |
|
||||
MemorySemanticsWorkgroupMemoryMask |
|
||||
MemorySemanticsAtomicCounterMemoryMask |
|
||||
MemorySemanticsImageMemoryMask);
|
||||
|
||||
struct IdImmediate {
|
||||
bool isId; // true if word is an Id, false if word is an immediate
|
||||
unsigned word;
|
||||
IdImmediate(bool i, unsigned w) : isId(i), word(w) {}
|
||||
};
|
||||
|
||||
//
|
||||
// SPIR-V IR instruction.
|
||||
//
|
||||
|
||||
class Instruction {
|
||||
public:
|
||||
Instruction(Id resultId, Id typeId, Op opCode) : resultId(resultId), typeId(typeId), opCode(opCode), block(nullptr) { }
|
||||
explicit Instruction(Op opCode) : resultId(NoResult), typeId(NoType), opCode(opCode), block(nullptr) { }
|
||||
virtual ~Instruction() {}
|
||||
void addIdOperand(Id id) {
|
||||
operands.push_back(id);
|
||||
idOperand.push_back(true);
|
||||
}
|
||||
void addImmediateOperand(unsigned int immediate) {
|
||||
operands.push_back(immediate);
|
||||
idOperand.push_back(false);
|
||||
}
|
||||
void setImmediateOperand(unsigned idx, unsigned int immediate) {
|
||||
assert(!idOperand[idx]);
|
||||
operands[idx] = immediate;
|
||||
}
|
||||
|
||||
void addStringOperand(const char* str)
|
||||
{
|
||||
unsigned int word;
|
||||
char* wordString = (char*)&word;
|
||||
char* wordPtr = wordString;
|
||||
int charCount = 0;
|
||||
char c;
|
||||
do {
|
||||
c = *(str++);
|
||||
*(wordPtr++) = c;
|
||||
++charCount;
|
||||
if (charCount == 4) {
|
||||
addImmediateOperand(word);
|
||||
wordPtr = wordString;
|
||||
charCount = 0;
|
||||
}
|
||||
} while (c != 0);
|
||||
|
||||
// deal with partial last word
|
||||
if (charCount > 0) {
|
||||
// pad with 0s
|
||||
for (; charCount < 4; ++charCount)
|
||||
*(wordPtr++) = 0;
|
||||
addImmediateOperand(word);
|
||||
}
|
||||
}
|
||||
bool isIdOperand(int op) const { return idOperand[op]; }
|
||||
void setBlock(Block* b) { block = b; }
|
||||
Block* getBlock() const { return block; }
|
||||
Op getOpCode() const { return opCode; }
|
||||
int getNumOperands() const
|
||||
{
|
||||
assert(operands.size() == idOperand.size());
|
||||
return (int)operands.size();
|
||||
}
|
||||
Id getResultId() const { return resultId; }
|
||||
Id getTypeId() const { return typeId; }
|
||||
Id getIdOperand(int op) const {
|
||||
assert(idOperand[op]);
|
||||
return operands[op];
|
||||
}
|
||||
unsigned int getImmediateOperand(int op) const {
|
||||
assert(!idOperand[op]);
|
||||
return operands[op];
|
||||
}
|
||||
|
||||
// Write out the binary form.
|
||||
void dump(std::vector<unsigned int>& out) const
|
||||
{
|
||||
// Compute the wordCount
|
||||
unsigned int wordCount = 1;
|
||||
if (typeId)
|
||||
++wordCount;
|
||||
if (resultId)
|
||||
++wordCount;
|
||||
wordCount += (unsigned int)operands.size();
|
||||
|
||||
// Write out the beginning of the instruction
|
||||
out.push_back(((wordCount) << WordCountShift) | opCode);
|
||||
if (typeId)
|
||||
out.push_back(typeId);
|
||||
if (resultId)
|
||||
out.push_back(resultId);
|
||||
|
||||
// Write out the operands
|
||||
for (int op = 0; op < (int)operands.size(); ++op)
|
||||
out.push_back(operands[op]);
|
||||
}
|
||||
|
||||
protected:
|
||||
Instruction(const Instruction&);
|
||||
Id resultId;
|
||||
Id typeId;
|
||||
Op opCode;
|
||||
std::vector<Id> operands; // operands, both <id> and immediates (both are unsigned int)
|
||||
std::vector<bool> idOperand; // true for operands that are <id>, false for immediates
|
||||
Block* block;
|
||||
};
|
||||
|
||||
//
|
||||
// SPIR-V IR block.
|
||||
//
|
||||
|
||||
class Block {
|
||||
public:
|
||||
Block(Id id, Function& parent);
|
||||
virtual ~Block()
|
||||
{
|
||||
}
|
||||
|
||||
Id getId() { return instructions.front()->getResultId(); }
|
||||
|
||||
Function& getParent() const { return parent; }
|
||||
void addInstruction(std::unique_ptr<Instruction> inst);
|
||||
void addPredecessor(Block* pred) { predecessors.push_back(pred); pred->successors.push_back(this);}
|
||||
void addLocalVariable(std::unique_ptr<Instruction> inst) { localVariables.push_back(std::move(inst)); }
|
||||
const std::vector<Block*>& getPredecessors() const { return predecessors; }
|
||||
const std::vector<Block*>& getSuccessors() const { return successors; }
|
||||
const std::vector<std::unique_ptr<Instruction> >& getInstructions() const {
|
||||
return instructions;
|
||||
}
|
||||
const std::vector<std::unique_ptr<Instruction> >& getLocalVariables() const { return localVariables; }
|
||||
void setUnreachable() { unreachable = true; }
|
||||
bool isUnreachable() const { return unreachable; }
|
||||
// Returns the block's merge instruction, if one exists (otherwise null).
|
||||
const Instruction* getMergeInstruction() const {
|
||||
if (instructions.size() < 2) return nullptr;
|
||||
const Instruction* nextToLast = (instructions.cend() - 2)->get();
|
||||
switch (nextToLast->getOpCode()) {
|
||||
case OpSelectionMerge:
|
||||
case OpLoopMerge:
|
||||
return nextToLast;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Change this block into a canonical dead merge block. Delete instructions
|
||||
// as necessary. A canonical dead merge block has only an OpLabel and an
|
||||
// OpUnreachable.
|
||||
void rewriteAsCanonicalUnreachableMerge() {
|
||||
assert(localVariables.empty());
|
||||
// Delete all instructions except for the label.
|
||||
assert(instructions.size() > 0);
|
||||
instructions.resize(1);
|
||||
successors.clear();
|
||||
addInstruction(std::unique_ptr<Instruction>(new Instruction(OpUnreachable)));
|
||||
}
|
||||
// Change this block into a canonical dead continue target branching to the
|
||||
// given header ID. Delete instructions as necessary. A canonical dead continue
|
||||
// target has only an OpLabel and an unconditional branch back to the corresponding
|
||||
// header.
|
||||
void rewriteAsCanonicalUnreachableContinue(Block* header) {
|
||||
assert(localVariables.empty());
|
||||
// Delete all instructions except for the label.
|
||||
assert(instructions.size() > 0);
|
||||
instructions.resize(1);
|
||||
successors.clear();
|
||||
// Add OpBranch back to the header.
|
||||
assert(header != nullptr);
|
||||
Instruction* branch = new Instruction(OpBranch);
|
||||
branch->addIdOperand(header->getId());
|
||||
addInstruction(std::unique_ptr<Instruction>(branch));
|
||||
successors.push_back(header);
|
||||
}
|
||||
|
||||
bool isTerminated() const
|
||||
{
|
||||
switch (instructions.back()->getOpCode()) {
|
||||
case OpBranch:
|
||||
case OpBranchConditional:
|
||||
case OpSwitch:
|
||||
case OpKill:
|
||||
case OpReturn:
|
||||
case OpReturnValue:
|
||||
case OpUnreachable:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void dump(std::vector<unsigned int>& out) const
|
||||
{
|
||||
instructions[0]->dump(out);
|
||||
for (int i = 0; i < (int)localVariables.size(); ++i)
|
||||
localVariables[i]->dump(out);
|
||||
for (int i = 1; i < (int)instructions.size(); ++i)
|
||||
instructions[i]->dump(out);
|
||||
}
|
||||
|
||||
protected:
|
||||
Block(const Block&);
|
||||
Block& operator=(Block&);
|
||||
|
||||
// To enforce keeping parent and ownership in sync:
|
||||
friend Function;
|
||||
|
||||
std::vector<std::unique_ptr<Instruction> > instructions;
|
||||
std::vector<Block*> predecessors, successors;
|
||||
std::vector<std::unique_ptr<Instruction> > localVariables;
|
||||
Function& parent;
|
||||
|
||||
// track whether this block is known to be uncreachable (not necessarily
|
||||
// true for all unreachable blocks, but should be set at least
|
||||
// for the extraneous ones introduced by the builder).
|
||||
bool unreachable;
|
||||
};
|
||||
|
||||
// The different reasons for reaching a block in the inReadableOrder traversal.
|
||||
enum ReachReason {
|
||||
// Reachable from the entry block via transfers of control, i.e. branches.
|
||||
ReachViaControlFlow = 0,
|
||||
// A continue target that is not reachable via control flow.
|
||||
ReachDeadContinue,
|
||||
// A merge block that is not reachable via control flow.
|
||||
ReachDeadMerge
|
||||
};
|
||||
|
||||
// Traverses the control-flow graph rooted at root in an order suited for
|
||||
// readable code generation. Invokes callback at every node in the traversal
|
||||
// order. The callback arguments are:
|
||||
// - the block,
|
||||
// - the reason we reached the block,
|
||||
// - if the reason was that block is an unreachable continue or unreachable merge block
|
||||
// then the last parameter is the corresponding header block.
|
||||
void inReadableOrder(Block* root, std::function<void(Block*, ReachReason, Block* header)> callback);
|
||||
|
||||
//
|
||||
// SPIR-V IR Function.
|
||||
//
|
||||
|
||||
class Function {
|
||||
public:
|
||||
Function(Id id, Id resultType, Id functionType, Id firstParam, Module& parent);
|
||||
virtual ~Function()
|
||||
{
|
||||
for (int i = 0; i < (int)parameterInstructions.size(); ++i)
|
||||
delete parameterInstructions[i];
|
||||
|
||||
for (int i = 0; i < (int)blocks.size(); ++i)
|
||||
delete blocks[i];
|
||||
}
|
||||
Id getId() const { return functionInstruction.getResultId(); }
|
||||
Id getParamId(int p) const { return parameterInstructions[p]->getResultId(); }
|
||||
Id getParamType(int p) const { return parameterInstructions[p]->getTypeId(); }
|
||||
|
||||
void addBlock(Block* block) { blocks.push_back(block); }
|
||||
void removeBlock(Block* block)
|
||||
{
|
||||
auto found = find(blocks.begin(), blocks.end(), block);
|
||||
assert(found != blocks.end());
|
||||
blocks.erase(found);
|
||||
delete block;
|
||||
}
|
||||
|
||||
Module& getParent() const { return parent; }
|
||||
Block* getEntryBlock() const { return blocks.front(); }
|
||||
Block* getLastBlock() const { return blocks.back(); }
|
||||
const std::vector<Block*>& getBlocks() const { return blocks; }
|
||||
void addLocalVariable(std::unique_ptr<Instruction> inst);
|
||||
Id getReturnType() const { return functionInstruction.getTypeId(); }
|
||||
|
||||
void setImplicitThis() { implicitThis = true; }
|
||||
bool hasImplicitThis() const { return implicitThis; }
|
||||
|
||||
void dump(std::vector<unsigned int>& out) const
|
||||
{
|
||||
// OpFunction
|
||||
functionInstruction.dump(out);
|
||||
|
||||
// OpFunctionParameter
|
||||
for (int p = 0; p < (int)parameterInstructions.size(); ++p)
|
||||
parameterInstructions[p]->dump(out);
|
||||
|
||||
// Blocks
|
||||
inReadableOrder(blocks[0], [&out](const Block* b, ReachReason, Block*) { b->dump(out); });
|
||||
Instruction end(0, 0, OpFunctionEnd);
|
||||
end.dump(out);
|
||||
}
|
||||
|
||||
protected:
|
||||
Function(const Function&);
|
||||
Function& operator=(Function&);
|
||||
|
||||
Module& parent;
|
||||
Instruction functionInstruction;
|
||||
std::vector<Instruction*> parameterInstructions;
|
||||
std::vector<Block*> blocks;
|
||||
bool implicitThis; // true if this is a member function expecting to be passed a 'this' as the first argument
|
||||
};
|
||||
|
||||
//
|
||||
// SPIR-V IR Module.
|
||||
//
|
||||
|
||||
class Module {
|
||||
public:
|
||||
Module() {}
|
||||
virtual ~Module()
|
||||
{
|
||||
// TODO delete things
|
||||
}
|
||||
|
||||
void addFunction(Function *fun) { functions.push_back(fun); }
|
||||
|
||||
void mapInstruction(Instruction *instruction)
|
||||
{
|
||||
spv::Id resultId = instruction->getResultId();
|
||||
// map the instruction's result id
|
||||
if (resultId >= idToInstruction.size())
|
||||
idToInstruction.resize(resultId + 16);
|
||||
idToInstruction[resultId] = instruction;
|
||||
}
|
||||
|
||||
Instruction* getInstruction(Id id) const { return idToInstruction[id]; }
|
||||
const std::vector<Function*>& getFunctions() const { return functions; }
|
||||
spv::Id getTypeId(Id resultId) const {
|
||||
return idToInstruction[resultId] == nullptr ? NoType : idToInstruction[resultId]->getTypeId();
|
||||
}
|
||||
StorageClass getStorageClass(Id typeId) const
|
||||
{
|
||||
assert(idToInstruction[typeId]->getOpCode() == spv::OpTypePointer);
|
||||
return (StorageClass)idToInstruction[typeId]->getImmediateOperand(0);
|
||||
}
|
||||
|
||||
void dump(std::vector<unsigned int>& out) const
|
||||
{
|
||||
for (int f = 0; f < (int)functions.size(); ++f)
|
||||
functions[f]->dump(out);
|
||||
}
|
||||
|
||||
protected:
|
||||
Module(const Module&);
|
||||
std::vector<Function*> functions;
|
||||
|
||||
// map from result id to instruction having that result id
|
||||
std::vector<Instruction*> idToInstruction;
|
||||
|
||||
// map from a result id to its type id
|
||||
};
|
||||
|
||||
//
|
||||
// Implementation (it's here due to circular type definitions).
|
||||
//
|
||||
|
||||
// Add both
|
||||
// - the OpFunction instruction
|
||||
// - all the OpFunctionParameter instructions
|
||||
__inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, Module& parent)
|
||||
: parent(parent), functionInstruction(id, resultType, OpFunction), implicitThis(false)
|
||||
{
|
||||
// OpFunction
|
||||
functionInstruction.addImmediateOperand(FunctionControlMaskNone);
|
||||
functionInstruction.addIdOperand(functionType);
|
||||
parent.mapInstruction(&functionInstruction);
|
||||
parent.addFunction(this);
|
||||
|
||||
// OpFunctionParameter
|
||||
Instruction* typeInst = parent.getInstruction(functionType);
|
||||
int numParams = typeInst->getNumOperands() - 1;
|
||||
for (int p = 0; p < numParams; ++p) {
|
||||
Instruction* param = new Instruction(firstParamId + p, typeInst->getIdOperand(p + 1), OpFunctionParameter);
|
||||
parent.mapInstruction(param);
|
||||
parameterInstructions.push_back(param);
|
||||
}
|
||||
}
|
||||
|
||||
__inline void Function::addLocalVariable(std::unique_ptr<Instruction> inst)
|
||||
{
|
||||
Instruction* raw_instruction = inst.get();
|
||||
blocks[0]->addLocalVariable(std::move(inst));
|
||||
parent.mapInstruction(raw_instruction);
|
||||
}
|
||||
|
||||
__inline Block::Block(Id id, Function& parent) : parent(parent), unreachable(false)
|
||||
{
|
||||
instructions.push_back(std::unique_ptr<Instruction>(new Instruction(id, NoType, OpLabel)));
|
||||
instructions.back()->setBlock(this);
|
||||
parent.getParent().mapInstruction(instructions.back().get());
|
||||
}
|
||||
|
||||
__inline void Block::addInstruction(std::unique_ptr<Instruction> inst)
|
||||
{
|
||||
Instruction* raw_instruction = inst.get();
|
||||
instructions.push_back(std::move(inst));
|
||||
raw_instruction->setBlock(this);
|
||||
if (raw_instruction->getResultId())
|
||||
parent.getParent().mapInstruction(raw_instruction);
|
||||
}
|
||||
|
||||
} // end spv namespace
|
||||
|
||||
#endif // spvIR_H
|
||||
@@ -1,68 +0,0 @@
|
||||
add_library(glslang-default-resource-limits
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ResourceLimits.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/resource_limits_c.cpp)
|
||||
set_property(TARGET glslang-default-resource-limits PROPERTY FOLDER glslang)
|
||||
set_property(TARGET glslang-default-resource-limits PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
target_include_directories(glslang-default-resource-limits
|
||||
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>)
|
||||
|
||||
|
||||
set(SOURCES StandAlone.cpp DirStackFileIncluder.h)
|
||||
|
||||
add_executable(glslangValidator ${SOURCES})
|
||||
set_property(TARGET glslangValidator PROPERTY FOLDER tools)
|
||||
glslang_set_link_args(glslangValidator)
|
||||
|
||||
set(LIBRARIES
|
||||
glslang
|
||||
SPIRV
|
||||
glslang-default-resource-limits)
|
||||
|
||||
if(ENABLE_SPVREMAPPER)
|
||||
set(LIBRARIES ${LIBRARIES} SPVRemapper)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(LIBRARIES ${LIBRARIES} psapi)
|
||||
elseif(UNIX)
|
||||
if(NOT ANDROID)
|
||||
set(LIBRARIES ${LIBRARIES} pthread)
|
||||
endif()
|
||||
endif(WIN32)
|
||||
|
||||
target_link_libraries(glslangValidator ${LIBRARIES})
|
||||
target_include_directories(glslangValidator PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../External>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/External>)
|
||||
|
||||
if(ENABLE_SPVREMAPPER)
|
||||
set(REMAPPER_SOURCES spirv-remap.cpp)
|
||||
add_executable(spirv-remap ${REMAPPER_SOURCES})
|
||||
set_property(TARGET spirv-remap PROPERTY FOLDER tools)
|
||||
glslang_set_link_args(spirv-remap)
|
||||
target_link_libraries(spirv-remap ${LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
source_group("Source" FILES ${SOURCES})
|
||||
endif(WIN32)
|
||||
|
||||
if(ENABLE_GLSLANG_INSTALL)
|
||||
install(TARGETS glslangValidator EXPORT glslangValidatorTargets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install(EXPORT glslangValidatorTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
|
||||
|
||||
if(ENABLE_SPVREMAPPER)
|
||||
install(TARGETS spirv-remap EXPORT spirv-remapTargets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install(EXPORT spirv-remapTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
|
||||
endif()
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
install(TARGETS glslang-default-resource-limits EXPORT glslang-default-resource-limitsTargets
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install(EXPORT glslang-default-resource-limitsTargets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
|
||||
endif()
|
||||
endif(ENABLE_GLSLANG_INSTALL)
|
||||
@@ -1,141 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
// Copyright (C) 2017 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "./../glslang/Public/ShaderLang.h"
|
||||
|
||||
// Default include class for normal include convention of search backward
|
||||
// through the stack of active include paths (for nested includes).
|
||||
// Can be overridden to customize.
|
||||
class DirStackFileIncluder : public glslang::TShader::Includer {
|
||||
public:
|
||||
DirStackFileIncluder() : externalLocalDirectoryCount(0) { }
|
||||
|
||||
virtual IncludeResult* includeLocal(const char* headerName,
|
||||
const char* includerName,
|
||||
size_t inclusionDepth) override
|
||||
{
|
||||
return readLocalPath(headerName, includerName, (int)inclusionDepth);
|
||||
}
|
||||
|
||||
virtual IncludeResult* includeSystem(const char* headerName,
|
||||
const char* /*includerName*/,
|
||||
size_t /*inclusionDepth*/) override
|
||||
{
|
||||
return readSystemPath(headerName);
|
||||
}
|
||||
|
||||
// Externally set directories. E.g., from a command-line -I<dir>.
|
||||
// - Most-recently pushed are checked first.
|
||||
// - All these are checked after the parse-time stack of local directories
|
||||
// is checked.
|
||||
// - This only applies to the "local" form of #include.
|
||||
// - Makes its own copy of the path.
|
||||
virtual void pushExternalLocalDirectory(const std::string& dir)
|
||||
{
|
||||
directoryStack.push_back(dir);
|
||||
externalLocalDirectoryCount = (int)directoryStack.size();
|
||||
}
|
||||
|
||||
virtual void releaseInclude(IncludeResult* result) override
|
||||
{
|
||||
if (result != nullptr) {
|
||||
delete [] static_cast<tUserDataElement*>(result->userData);
|
||||
delete result;
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~DirStackFileIncluder() override { }
|
||||
|
||||
protected:
|
||||
typedef char tUserDataElement;
|
||||
std::vector<std::string> directoryStack;
|
||||
int externalLocalDirectoryCount;
|
||||
|
||||
// Search for a valid "local" path based on combining the stack of include
|
||||
// directories and the nominal name of the header.
|
||||
virtual IncludeResult* readLocalPath(const char* headerName, const char* includerName, int depth)
|
||||
{
|
||||
// Discard popped include directories, and
|
||||
// initialize when at parse-time first level.
|
||||
directoryStack.resize(depth + externalLocalDirectoryCount);
|
||||
if (depth == 1)
|
||||
directoryStack.back() = getDirectory(includerName);
|
||||
|
||||
// Find a directory that works, using a reverse search of the include stack.
|
||||
for (auto it = directoryStack.rbegin(); it != directoryStack.rend(); ++it) {
|
||||
std::string path = *it + '/' + headerName;
|
||||
std::replace(path.begin(), path.end(), '\\', '/');
|
||||
std::ifstream file(path, std::ios_base::binary | std::ios_base::ate);
|
||||
if (file) {
|
||||
directoryStack.push_back(getDirectory(path));
|
||||
return newIncludeResult(path, file, (int)file.tellg());
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Search for a valid <system> path.
|
||||
// Not implemented yet; returning nullptr signals failure to find.
|
||||
virtual IncludeResult* readSystemPath(const char* /*headerName*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Do actual reading of the file, filling in a new include result.
|
||||
virtual IncludeResult* newIncludeResult(const std::string& path, std::ifstream& file, int length) const
|
||||
{
|
||||
char* content = new tUserDataElement [length];
|
||||
file.seekg(0, file.beg);
|
||||
file.read(content, length);
|
||||
return new IncludeResult(path, content, length, content);
|
||||
}
|
||||
|
||||
// If no path markers, return current working directory.
|
||||
// Otherwise, strip file name and return path leading up to it.
|
||||
virtual std::string getDirectory(const std::string path) const
|
||||
{
|
||||
size_t last = path.find_last_of("/\\");
|
||||
return last == std::string::npos ? "." : path.substr(0, last);
|
||||
}
|
||||
};
|
||||
@@ -1,494 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2016 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <cctype>
|
||||
|
||||
#include "ResourceLimits.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
const TBuiltInResource DefaultTBuiltInResource = {
|
||||
/* .MaxLights = */ 32,
|
||||
/* .MaxClipPlanes = */ 6,
|
||||
/* .MaxTextureUnits = */ 32,
|
||||
/* .MaxTextureCoords = */ 32,
|
||||
/* .MaxVertexAttribs = */ 64,
|
||||
/* .MaxVertexUniformComponents = */ 4096,
|
||||
/* .MaxVaryingFloats = */ 64,
|
||||
/* .MaxVertexTextureImageUnits = */ 32,
|
||||
/* .MaxCombinedTextureImageUnits = */ 80,
|
||||
/* .MaxTextureImageUnits = */ 32,
|
||||
/* .MaxFragmentUniformComponents = */ 4096,
|
||||
/* .MaxDrawBuffers = */ 32,
|
||||
/* .MaxVertexUniformVectors = */ 128,
|
||||
/* .MaxVaryingVectors = */ 8,
|
||||
/* .MaxFragmentUniformVectors = */ 16,
|
||||
/* .MaxVertexOutputVectors = */ 16,
|
||||
/* .MaxFragmentInputVectors = */ 15,
|
||||
/* .MinProgramTexelOffset = */ -8,
|
||||
/* .MaxProgramTexelOffset = */ 7,
|
||||
/* .MaxClipDistances = */ 8,
|
||||
/* .MaxComputeWorkGroupCountX = */ 65535,
|
||||
/* .MaxComputeWorkGroupCountY = */ 65535,
|
||||
/* .MaxComputeWorkGroupCountZ = */ 65535,
|
||||
/* .MaxComputeWorkGroupSizeX = */ 1024,
|
||||
/* .MaxComputeWorkGroupSizeY = */ 1024,
|
||||
/* .MaxComputeWorkGroupSizeZ = */ 64,
|
||||
/* .MaxComputeUniformComponents = */ 1024,
|
||||
/* .MaxComputeTextureImageUnits = */ 16,
|
||||
/* .MaxComputeImageUniforms = */ 8,
|
||||
/* .MaxComputeAtomicCounters = */ 8,
|
||||
/* .MaxComputeAtomicCounterBuffers = */ 1,
|
||||
/* .MaxVaryingComponents = */ 60,
|
||||
/* .MaxVertexOutputComponents = */ 64,
|
||||
/* .MaxGeometryInputComponents = */ 64,
|
||||
/* .MaxGeometryOutputComponents = */ 128,
|
||||
/* .MaxFragmentInputComponents = */ 128,
|
||||
/* .MaxImageUnits = */ 8,
|
||||
/* .MaxCombinedImageUnitsAndFragmentOutputs = */ 8,
|
||||
/* .MaxCombinedShaderOutputResources = */ 8,
|
||||
/* .MaxImageSamples = */ 0,
|
||||
/* .MaxVertexImageUniforms = */ 0,
|
||||
/* .MaxTessControlImageUniforms = */ 0,
|
||||
/* .MaxTessEvaluationImageUniforms = */ 0,
|
||||
/* .MaxGeometryImageUniforms = */ 0,
|
||||
/* .MaxFragmentImageUniforms = */ 8,
|
||||
/* .MaxCombinedImageUniforms = */ 8,
|
||||
/* .MaxGeometryTextureImageUnits = */ 16,
|
||||
/* .MaxGeometryOutputVertices = */ 256,
|
||||
/* .MaxGeometryTotalOutputComponents = */ 1024,
|
||||
/* .MaxGeometryUniformComponents = */ 1024,
|
||||
/* .MaxGeometryVaryingComponents = */ 64,
|
||||
/* .MaxTessControlInputComponents = */ 128,
|
||||
/* .MaxTessControlOutputComponents = */ 128,
|
||||
/* .MaxTessControlTextureImageUnits = */ 16,
|
||||
/* .MaxTessControlUniformComponents = */ 1024,
|
||||
/* .MaxTessControlTotalOutputComponents = */ 4096,
|
||||
/* .MaxTessEvaluationInputComponents = */ 128,
|
||||
/* .MaxTessEvaluationOutputComponents = */ 128,
|
||||
/* .MaxTessEvaluationTextureImageUnits = */ 16,
|
||||
/* .MaxTessEvaluationUniformComponents = */ 1024,
|
||||
/* .MaxTessPatchComponents = */ 120,
|
||||
/* .MaxPatchVertices = */ 32,
|
||||
/* .MaxTessGenLevel = */ 64,
|
||||
/* .MaxViewports = */ 16,
|
||||
/* .MaxVertexAtomicCounters = */ 0,
|
||||
/* .MaxTessControlAtomicCounters = */ 0,
|
||||
/* .MaxTessEvaluationAtomicCounters = */ 0,
|
||||
/* .MaxGeometryAtomicCounters = */ 0,
|
||||
/* .MaxFragmentAtomicCounters = */ 8,
|
||||
/* .MaxCombinedAtomicCounters = */ 8,
|
||||
/* .MaxAtomicCounterBindings = */ 1,
|
||||
/* .MaxVertexAtomicCounterBuffers = */ 0,
|
||||
/* .MaxTessControlAtomicCounterBuffers = */ 0,
|
||||
/* .MaxTessEvaluationAtomicCounterBuffers = */ 0,
|
||||
/* .MaxGeometryAtomicCounterBuffers = */ 0,
|
||||
/* .MaxFragmentAtomicCounterBuffers = */ 1,
|
||||
/* .MaxCombinedAtomicCounterBuffers = */ 1,
|
||||
/* .MaxAtomicCounterBufferSize = */ 16384,
|
||||
/* .MaxTransformFeedbackBuffers = */ 4,
|
||||
/* .MaxTransformFeedbackInterleavedComponents = */ 64,
|
||||
/* .MaxCullDistances = */ 8,
|
||||
/* .MaxCombinedClipAndCullDistances = */ 8,
|
||||
/* .MaxSamples = */ 4,
|
||||
/* .maxMeshOutputVerticesNV = */ 256,
|
||||
/* .maxMeshOutputPrimitivesNV = */ 512,
|
||||
/* .maxMeshWorkGroupSizeX_NV = */ 32,
|
||||
/* .maxMeshWorkGroupSizeY_NV = */ 1,
|
||||
/* .maxMeshWorkGroupSizeZ_NV = */ 1,
|
||||
/* .maxTaskWorkGroupSizeX_NV = */ 32,
|
||||
/* .maxTaskWorkGroupSizeY_NV = */ 1,
|
||||
/* .maxTaskWorkGroupSizeZ_NV = */ 1,
|
||||
/* .maxMeshViewCountNV = */ 4,
|
||||
|
||||
/* .limits = */ {
|
||||
/* .nonInductiveForLoops = */ 1,
|
||||
/* .whileLoops = */ 1,
|
||||
/* .doWhileLoops = */ 1,
|
||||
/* .generalUniformIndexing = */ 1,
|
||||
/* .generalAttributeMatrixVectorIndexing = */ 1,
|
||||
/* .generalVaryingIndexing = */ 1,
|
||||
/* .generalSamplerIndexing = */ 1,
|
||||
/* .generalVariableIndexing = */ 1,
|
||||
/* .generalConstantMatrixVectorIndexing = */ 1,
|
||||
}};
|
||||
|
||||
std::string GetDefaultTBuiltInResourceString()
|
||||
{
|
||||
std::ostringstream ostream;
|
||||
|
||||
ostream << "MaxLights " << DefaultTBuiltInResource.maxLights << "\n"
|
||||
<< "MaxClipPlanes " << DefaultTBuiltInResource.maxClipPlanes << "\n"
|
||||
<< "MaxTextureUnits " << DefaultTBuiltInResource.maxTextureUnits << "\n"
|
||||
<< "MaxTextureCoords " << DefaultTBuiltInResource.maxTextureCoords << "\n"
|
||||
<< "MaxVertexAttribs " << DefaultTBuiltInResource.maxVertexAttribs << "\n"
|
||||
<< "MaxVertexUniformComponents " << DefaultTBuiltInResource.maxVertexUniformComponents << "\n"
|
||||
<< "MaxVaryingFloats " << DefaultTBuiltInResource.maxVaryingFloats << "\n"
|
||||
<< "MaxVertexTextureImageUnits " << DefaultTBuiltInResource.maxVertexTextureImageUnits << "\n"
|
||||
<< "MaxCombinedTextureImageUnits " << DefaultTBuiltInResource.maxCombinedTextureImageUnits << "\n"
|
||||
<< "MaxTextureImageUnits " << DefaultTBuiltInResource.maxTextureImageUnits << "\n"
|
||||
<< "MaxFragmentUniformComponents " << DefaultTBuiltInResource.maxFragmentUniformComponents << "\n"
|
||||
<< "MaxDrawBuffers " << DefaultTBuiltInResource.maxDrawBuffers << "\n"
|
||||
<< "MaxVertexUniformVectors " << DefaultTBuiltInResource.maxVertexUniformVectors << "\n"
|
||||
<< "MaxVaryingVectors " << DefaultTBuiltInResource.maxVaryingVectors << "\n"
|
||||
<< "MaxFragmentUniformVectors " << DefaultTBuiltInResource.maxFragmentUniformVectors << "\n"
|
||||
<< "MaxVertexOutputVectors " << DefaultTBuiltInResource.maxVertexOutputVectors << "\n"
|
||||
<< "MaxFragmentInputVectors " << DefaultTBuiltInResource.maxFragmentInputVectors << "\n"
|
||||
<< "MinProgramTexelOffset " << DefaultTBuiltInResource.minProgramTexelOffset << "\n"
|
||||
<< "MaxProgramTexelOffset " << DefaultTBuiltInResource.maxProgramTexelOffset << "\n"
|
||||
<< "MaxClipDistances " << DefaultTBuiltInResource.maxClipDistances << "\n"
|
||||
<< "MaxComputeWorkGroupCountX " << DefaultTBuiltInResource.maxComputeWorkGroupCountX << "\n"
|
||||
<< "MaxComputeWorkGroupCountY " << DefaultTBuiltInResource.maxComputeWorkGroupCountY << "\n"
|
||||
<< "MaxComputeWorkGroupCountZ " << DefaultTBuiltInResource.maxComputeWorkGroupCountZ << "\n"
|
||||
<< "MaxComputeWorkGroupSizeX " << DefaultTBuiltInResource.maxComputeWorkGroupSizeX << "\n"
|
||||
<< "MaxComputeWorkGroupSizeY " << DefaultTBuiltInResource.maxComputeWorkGroupSizeY << "\n"
|
||||
<< "MaxComputeWorkGroupSizeZ " << DefaultTBuiltInResource.maxComputeWorkGroupSizeZ << "\n"
|
||||
<< "MaxComputeUniformComponents " << DefaultTBuiltInResource.maxComputeUniformComponents << "\n"
|
||||
<< "MaxComputeTextureImageUnits " << DefaultTBuiltInResource.maxComputeTextureImageUnits << "\n"
|
||||
<< "MaxComputeImageUniforms " << DefaultTBuiltInResource.maxComputeImageUniforms << "\n"
|
||||
<< "MaxComputeAtomicCounters " << DefaultTBuiltInResource.maxComputeAtomicCounters << "\n"
|
||||
<< "MaxComputeAtomicCounterBuffers " << DefaultTBuiltInResource.maxComputeAtomicCounterBuffers << "\n"
|
||||
<< "MaxVaryingComponents " << DefaultTBuiltInResource.maxVaryingComponents << "\n"
|
||||
<< "MaxVertexOutputComponents " << DefaultTBuiltInResource.maxVertexOutputComponents << "\n"
|
||||
<< "MaxGeometryInputComponents " << DefaultTBuiltInResource.maxGeometryInputComponents << "\n"
|
||||
<< "MaxGeometryOutputComponents " << DefaultTBuiltInResource.maxGeometryOutputComponents << "\n"
|
||||
<< "MaxFragmentInputComponents " << DefaultTBuiltInResource.maxFragmentInputComponents << "\n"
|
||||
<< "MaxImageUnits " << DefaultTBuiltInResource.maxImageUnits << "\n"
|
||||
<< "MaxCombinedImageUnitsAndFragmentOutputs " << DefaultTBuiltInResource.maxCombinedImageUnitsAndFragmentOutputs << "\n"
|
||||
<< "MaxCombinedShaderOutputResources " << DefaultTBuiltInResource.maxCombinedShaderOutputResources << "\n"
|
||||
<< "MaxImageSamples " << DefaultTBuiltInResource.maxImageSamples << "\n"
|
||||
<< "MaxVertexImageUniforms " << DefaultTBuiltInResource.maxVertexImageUniforms << "\n"
|
||||
<< "MaxTessControlImageUniforms " << DefaultTBuiltInResource.maxTessControlImageUniforms << "\n"
|
||||
<< "MaxTessEvaluationImageUniforms " << DefaultTBuiltInResource.maxTessEvaluationImageUniforms << "\n"
|
||||
<< "MaxGeometryImageUniforms " << DefaultTBuiltInResource.maxGeometryImageUniforms << "\n"
|
||||
<< "MaxFragmentImageUniforms " << DefaultTBuiltInResource.maxFragmentImageUniforms << "\n"
|
||||
<< "MaxCombinedImageUniforms " << DefaultTBuiltInResource.maxCombinedImageUniforms << "\n"
|
||||
<< "MaxGeometryTextureImageUnits " << DefaultTBuiltInResource.maxGeometryTextureImageUnits << "\n"
|
||||
<< "MaxGeometryOutputVertices " << DefaultTBuiltInResource.maxGeometryOutputVertices << "\n"
|
||||
<< "MaxGeometryTotalOutputComponents " << DefaultTBuiltInResource.maxGeometryTotalOutputComponents << "\n"
|
||||
<< "MaxGeometryUniformComponents " << DefaultTBuiltInResource.maxGeometryUniformComponents << "\n"
|
||||
<< "MaxGeometryVaryingComponents " << DefaultTBuiltInResource.maxGeometryVaryingComponents << "\n"
|
||||
<< "MaxTessControlInputComponents " << DefaultTBuiltInResource.maxTessControlInputComponents << "\n"
|
||||
<< "MaxTessControlOutputComponents " << DefaultTBuiltInResource.maxTessControlOutputComponents << "\n"
|
||||
<< "MaxTessControlTextureImageUnits " << DefaultTBuiltInResource.maxTessControlTextureImageUnits << "\n"
|
||||
<< "MaxTessControlUniformComponents " << DefaultTBuiltInResource.maxTessControlUniformComponents << "\n"
|
||||
<< "MaxTessControlTotalOutputComponents " << DefaultTBuiltInResource.maxTessControlTotalOutputComponents << "\n"
|
||||
<< "MaxTessEvaluationInputComponents " << DefaultTBuiltInResource.maxTessEvaluationInputComponents << "\n"
|
||||
<< "MaxTessEvaluationOutputComponents " << DefaultTBuiltInResource.maxTessEvaluationOutputComponents << "\n"
|
||||
<< "MaxTessEvaluationTextureImageUnits " << DefaultTBuiltInResource.maxTessEvaluationTextureImageUnits << "\n"
|
||||
<< "MaxTessEvaluationUniformComponents " << DefaultTBuiltInResource.maxTessEvaluationUniformComponents << "\n"
|
||||
<< "MaxTessPatchComponents " << DefaultTBuiltInResource.maxTessPatchComponents << "\n"
|
||||
<< "MaxPatchVertices " << DefaultTBuiltInResource.maxPatchVertices << "\n"
|
||||
<< "MaxTessGenLevel " << DefaultTBuiltInResource.maxTessGenLevel << "\n"
|
||||
<< "MaxViewports " << DefaultTBuiltInResource.maxViewports << "\n"
|
||||
<< "MaxVertexAtomicCounters " << DefaultTBuiltInResource.maxVertexAtomicCounters << "\n"
|
||||
<< "MaxTessControlAtomicCounters " << DefaultTBuiltInResource.maxTessControlAtomicCounters << "\n"
|
||||
<< "MaxTessEvaluationAtomicCounters " << DefaultTBuiltInResource.maxTessEvaluationAtomicCounters << "\n"
|
||||
<< "MaxGeometryAtomicCounters " << DefaultTBuiltInResource.maxGeometryAtomicCounters << "\n"
|
||||
<< "MaxFragmentAtomicCounters " << DefaultTBuiltInResource.maxFragmentAtomicCounters << "\n"
|
||||
<< "MaxCombinedAtomicCounters " << DefaultTBuiltInResource.maxCombinedAtomicCounters << "\n"
|
||||
<< "MaxAtomicCounterBindings " << DefaultTBuiltInResource.maxAtomicCounterBindings << "\n"
|
||||
<< "MaxVertexAtomicCounterBuffers " << DefaultTBuiltInResource.maxVertexAtomicCounterBuffers << "\n"
|
||||
<< "MaxTessControlAtomicCounterBuffers " << DefaultTBuiltInResource.maxTessControlAtomicCounterBuffers << "\n"
|
||||
<< "MaxTessEvaluationAtomicCounterBuffers " << DefaultTBuiltInResource.maxTessEvaluationAtomicCounterBuffers << "\n"
|
||||
<< "MaxGeometryAtomicCounterBuffers " << DefaultTBuiltInResource.maxGeometryAtomicCounterBuffers << "\n"
|
||||
<< "MaxFragmentAtomicCounterBuffers " << DefaultTBuiltInResource.maxFragmentAtomicCounterBuffers << "\n"
|
||||
<< "MaxCombinedAtomicCounterBuffers " << DefaultTBuiltInResource.maxCombinedAtomicCounterBuffers << "\n"
|
||||
<< "MaxAtomicCounterBufferSize " << DefaultTBuiltInResource.maxAtomicCounterBufferSize << "\n"
|
||||
<< "MaxTransformFeedbackBuffers " << DefaultTBuiltInResource.maxTransformFeedbackBuffers << "\n"
|
||||
<< "MaxTransformFeedbackInterleavedComponents " << DefaultTBuiltInResource.maxTransformFeedbackInterleavedComponents << "\n"
|
||||
<< "MaxCullDistances " << DefaultTBuiltInResource.maxCullDistances << "\n"
|
||||
<< "MaxCombinedClipAndCullDistances " << DefaultTBuiltInResource.maxCombinedClipAndCullDistances << "\n"
|
||||
<< "MaxSamples " << DefaultTBuiltInResource.maxSamples << "\n"
|
||||
<< "MaxMeshOutputVerticesNV " << DefaultTBuiltInResource.maxMeshOutputVerticesNV << "\n"
|
||||
<< "MaxMeshOutputPrimitivesNV " << DefaultTBuiltInResource.maxMeshOutputPrimitivesNV << "\n"
|
||||
<< "MaxMeshWorkGroupSizeX_NV " << DefaultTBuiltInResource.maxMeshWorkGroupSizeX_NV << "\n"
|
||||
<< "MaxMeshWorkGroupSizeY_NV " << DefaultTBuiltInResource.maxMeshWorkGroupSizeY_NV << "\n"
|
||||
<< "MaxMeshWorkGroupSizeZ_NV " << DefaultTBuiltInResource.maxMeshWorkGroupSizeZ_NV << "\n"
|
||||
<< "MaxTaskWorkGroupSizeX_NV " << DefaultTBuiltInResource.maxTaskWorkGroupSizeX_NV << "\n"
|
||||
<< "MaxTaskWorkGroupSizeY_NV " << DefaultTBuiltInResource.maxTaskWorkGroupSizeY_NV << "\n"
|
||||
<< "MaxTaskWorkGroupSizeZ_NV " << DefaultTBuiltInResource.maxTaskWorkGroupSizeZ_NV << "\n"
|
||||
<< "MaxMeshViewCountNV " << DefaultTBuiltInResource.maxMeshViewCountNV << "\n"
|
||||
<< "nonInductiveForLoops " << DefaultTBuiltInResource.limits.nonInductiveForLoops << "\n"
|
||||
<< "whileLoops " << DefaultTBuiltInResource.limits.whileLoops << "\n"
|
||||
<< "doWhileLoops " << DefaultTBuiltInResource.limits.doWhileLoops << "\n"
|
||||
<< "generalUniformIndexing " << DefaultTBuiltInResource.limits.generalUniformIndexing << "\n"
|
||||
<< "generalAttributeMatrixVectorIndexing " << DefaultTBuiltInResource.limits.generalAttributeMatrixVectorIndexing << "\n"
|
||||
<< "generalVaryingIndexing " << DefaultTBuiltInResource.limits.generalVaryingIndexing << "\n"
|
||||
<< "generalSamplerIndexing " << DefaultTBuiltInResource.limits.generalSamplerIndexing << "\n"
|
||||
<< "generalVariableIndexing " << DefaultTBuiltInResource.limits.generalVariableIndexing << "\n"
|
||||
<< "generalConstantMatrixVectorIndexing " << DefaultTBuiltInResource.limits.generalConstantMatrixVectorIndexing << "\n"
|
||||
;
|
||||
|
||||
return ostream.str();
|
||||
}
|
||||
|
||||
void DecodeResourceLimits(TBuiltInResource* resources, char* config)
|
||||
{
|
||||
static const char* delims = " \t\n\r";
|
||||
|
||||
size_t pos = 0;
|
||||
std::string configStr(config);
|
||||
|
||||
while ((pos = configStr.find_first_not_of(delims, pos)) != std::string::npos) {
|
||||
const size_t token_s = pos;
|
||||
const size_t token_e = configStr.find_first_of(delims, token_s);
|
||||
const size_t value_s = configStr.find_first_not_of(delims, token_e);
|
||||
const size_t value_e = configStr.find_first_of(delims, value_s);
|
||||
pos = value_e;
|
||||
|
||||
// Faster to use compare(), but prefering readability.
|
||||
const std::string tokenStr = configStr.substr(token_s, token_e-token_s);
|
||||
const std::string valueStr = configStr.substr(value_s, value_e-value_s);
|
||||
|
||||
if (value_s == std::string::npos || ! (valueStr[0] == '-' || isdigit(valueStr[0]))) {
|
||||
printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n",
|
||||
valueStr.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
const int value = std::atoi(valueStr.c_str());
|
||||
|
||||
if (tokenStr == "MaxLights")
|
||||
resources->maxLights = value;
|
||||
else if (tokenStr == "MaxClipPlanes")
|
||||
resources->maxClipPlanes = value;
|
||||
else if (tokenStr == "MaxTextureUnits")
|
||||
resources->maxTextureUnits = value;
|
||||
else if (tokenStr == "MaxTextureCoords")
|
||||
resources->maxTextureCoords = value;
|
||||
else if (tokenStr == "MaxVertexAttribs")
|
||||
resources->maxVertexAttribs = value;
|
||||
else if (tokenStr == "MaxVertexUniformComponents")
|
||||
resources->maxVertexUniformComponents = value;
|
||||
else if (tokenStr == "MaxVaryingFloats")
|
||||
resources->maxVaryingFloats = value;
|
||||
else if (tokenStr == "MaxVertexTextureImageUnits")
|
||||
resources->maxVertexTextureImageUnits = value;
|
||||
else if (tokenStr == "MaxCombinedTextureImageUnits")
|
||||
resources->maxCombinedTextureImageUnits = value;
|
||||
else if (tokenStr == "MaxTextureImageUnits")
|
||||
resources->maxTextureImageUnits = value;
|
||||
else if (tokenStr == "MaxFragmentUniformComponents")
|
||||
resources->maxFragmentUniformComponents = value;
|
||||
else if (tokenStr == "MaxDrawBuffers")
|
||||
resources->maxDrawBuffers = value;
|
||||
else if (tokenStr == "MaxVertexUniformVectors")
|
||||
resources->maxVertexUniformVectors = value;
|
||||
else if (tokenStr == "MaxVaryingVectors")
|
||||
resources->maxVaryingVectors = value;
|
||||
else if (tokenStr == "MaxFragmentUniformVectors")
|
||||
resources->maxFragmentUniformVectors = value;
|
||||
else if (tokenStr == "MaxVertexOutputVectors")
|
||||
resources->maxVertexOutputVectors = value;
|
||||
else if (tokenStr == "MaxFragmentInputVectors")
|
||||
resources->maxFragmentInputVectors = value;
|
||||
else if (tokenStr == "MinProgramTexelOffset")
|
||||
resources->minProgramTexelOffset = value;
|
||||
else if (tokenStr == "MaxProgramTexelOffset")
|
||||
resources->maxProgramTexelOffset = value;
|
||||
else if (tokenStr == "MaxClipDistances")
|
||||
resources->maxClipDistances = value;
|
||||
else if (tokenStr == "MaxComputeWorkGroupCountX")
|
||||
resources->maxComputeWorkGroupCountX = value;
|
||||
else if (tokenStr == "MaxComputeWorkGroupCountY")
|
||||
resources->maxComputeWorkGroupCountY = value;
|
||||
else if (tokenStr == "MaxComputeWorkGroupCountZ")
|
||||
resources->maxComputeWorkGroupCountZ = value;
|
||||
else if (tokenStr == "MaxComputeWorkGroupSizeX")
|
||||
resources->maxComputeWorkGroupSizeX = value;
|
||||
else if (tokenStr == "MaxComputeWorkGroupSizeY")
|
||||
resources->maxComputeWorkGroupSizeY = value;
|
||||
else if (tokenStr == "MaxComputeWorkGroupSizeZ")
|
||||
resources->maxComputeWorkGroupSizeZ = value;
|
||||
else if (tokenStr == "MaxComputeUniformComponents")
|
||||
resources->maxComputeUniformComponents = value;
|
||||
else if (tokenStr == "MaxComputeTextureImageUnits")
|
||||
resources->maxComputeTextureImageUnits = value;
|
||||
else if (tokenStr == "MaxComputeImageUniforms")
|
||||
resources->maxComputeImageUniforms = value;
|
||||
else if (tokenStr == "MaxComputeAtomicCounters")
|
||||
resources->maxComputeAtomicCounters = value;
|
||||
else if (tokenStr == "MaxComputeAtomicCounterBuffers")
|
||||
resources->maxComputeAtomicCounterBuffers = value;
|
||||
else if (tokenStr == "MaxVaryingComponents")
|
||||
resources->maxVaryingComponents = value;
|
||||
else if (tokenStr == "MaxVertexOutputComponents")
|
||||
resources->maxVertexOutputComponents = value;
|
||||
else if (tokenStr == "MaxGeometryInputComponents")
|
||||
resources->maxGeometryInputComponents = value;
|
||||
else if (tokenStr == "MaxGeometryOutputComponents")
|
||||
resources->maxGeometryOutputComponents = value;
|
||||
else if (tokenStr == "MaxFragmentInputComponents")
|
||||
resources->maxFragmentInputComponents = value;
|
||||
else if (tokenStr == "MaxImageUnits")
|
||||
resources->maxImageUnits = value;
|
||||
else if (tokenStr == "MaxCombinedImageUnitsAndFragmentOutputs")
|
||||
resources->maxCombinedImageUnitsAndFragmentOutputs = value;
|
||||
else if (tokenStr == "MaxCombinedShaderOutputResources")
|
||||
resources->maxCombinedShaderOutputResources = value;
|
||||
else if (tokenStr == "MaxImageSamples")
|
||||
resources->maxImageSamples = value;
|
||||
else if (tokenStr == "MaxVertexImageUniforms")
|
||||
resources->maxVertexImageUniforms = value;
|
||||
else if (tokenStr == "MaxTessControlImageUniforms")
|
||||
resources->maxTessControlImageUniforms = value;
|
||||
else if (tokenStr == "MaxTessEvaluationImageUniforms")
|
||||
resources->maxTessEvaluationImageUniforms = value;
|
||||
else if (tokenStr == "MaxGeometryImageUniforms")
|
||||
resources->maxGeometryImageUniforms = value;
|
||||
else if (tokenStr == "MaxFragmentImageUniforms")
|
||||
resources->maxFragmentImageUniforms = value;
|
||||
else if (tokenStr == "MaxCombinedImageUniforms")
|
||||
resources->maxCombinedImageUniforms = value;
|
||||
else if (tokenStr == "MaxGeometryTextureImageUnits")
|
||||
resources->maxGeometryTextureImageUnits = value;
|
||||
else if (tokenStr == "MaxGeometryOutputVertices")
|
||||
resources->maxGeometryOutputVertices = value;
|
||||
else if (tokenStr == "MaxGeometryTotalOutputComponents")
|
||||
resources->maxGeometryTotalOutputComponents = value;
|
||||
else if (tokenStr == "MaxGeometryUniformComponents")
|
||||
resources->maxGeometryUniformComponents = value;
|
||||
else if (tokenStr == "MaxGeometryVaryingComponents")
|
||||
resources->maxGeometryVaryingComponents = value;
|
||||
else if (tokenStr == "MaxTessControlInputComponents")
|
||||
resources->maxTessControlInputComponents = value;
|
||||
else if (tokenStr == "MaxTessControlOutputComponents")
|
||||
resources->maxTessControlOutputComponents = value;
|
||||
else if (tokenStr == "MaxTessControlTextureImageUnits")
|
||||
resources->maxTessControlTextureImageUnits = value;
|
||||
else if (tokenStr == "MaxTessControlUniformComponents")
|
||||
resources->maxTessControlUniformComponents = value;
|
||||
else if (tokenStr == "MaxTessControlTotalOutputComponents")
|
||||
resources->maxTessControlTotalOutputComponents = value;
|
||||
else if (tokenStr == "MaxTessEvaluationInputComponents")
|
||||
resources->maxTessEvaluationInputComponents = value;
|
||||
else if (tokenStr == "MaxTessEvaluationOutputComponents")
|
||||
resources->maxTessEvaluationOutputComponents = value;
|
||||
else if (tokenStr == "MaxTessEvaluationTextureImageUnits")
|
||||
resources->maxTessEvaluationTextureImageUnits = value;
|
||||
else if (tokenStr == "MaxTessEvaluationUniformComponents")
|
||||
resources->maxTessEvaluationUniformComponents = value;
|
||||
else if (tokenStr == "MaxTessPatchComponents")
|
||||
resources->maxTessPatchComponents = value;
|
||||
else if (tokenStr == "MaxPatchVertices")
|
||||
resources->maxPatchVertices = value;
|
||||
else if (tokenStr == "MaxTessGenLevel")
|
||||
resources->maxTessGenLevel = value;
|
||||
else if (tokenStr == "MaxViewports")
|
||||
resources->maxViewports = value;
|
||||
else if (tokenStr == "MaxVertexAtomicCounters")
|
||||
resources->maxVertexAtomicCounters = value;
|
||||
else if (tokenStr == "MaxTessControlAtomicCounters")
|
||||
resources->maxTessControlAtomicCounters = value;
|
||||
else if (tokenStr == "MaxTessEvaluationAtomicCounters")
|
||||
resources->maxTessEvaluationAtomicCounters = value;
|
||||
else if (tokenStr == "MaxGeometryAtomicCounters")
|
||||
resources->maxGeometryAtomicCounters = value;
|
||||
else if (tokenStr == "MaxFragmentAtomicCounters")
|
||||
resources->maxFragmentAtomicCounters = value;
|
||||
else if (tokenStr == "MaxCombinedAtomicCounters")
|
||||
resources->maxCombinedAtomicCounters = value;
|
||||
else if (tokenStr == "MaxAtomicCounterBindings")
|
||||
resources->maxAtomicCounterBindings = value;
|
||||
else if (tokenStr == "MaxVertexAtomicCounterBuffers")
|
||||
resources->maxVertexAtomicCounterBuffers = value;
|
||||
else if (tokenStr == "MaxTessControlAtomicCounterBuffers")
|
||||
resources->maxTessControlAtomicCounterBuffers = value;
|
||||
else if (tokenStr == "MaxTessEvaluationAtomicCounterBuffers")
|
||||
resources->maxTessEvaluationAtomicCounterBuffers = value;
|
||||
else if (tokenStr == "MaxGeometryAtomicCounterBuffers")
|
||||
resources->maxGeometryAtomicCounterBuffers = value;
|
||||
else if (tokenStr == "MaxFragmentAtomicCounterBuffers")
|
||||
resources->maxFragmentAtomicCounterBuffers = value;
|
||||
else if (tokenStr == "MaxCombinedAtomicCounterBuffers")
|
||||
resources->maxCombinedAtomicCounterBuffers = value;
|
||||
else if (tokenStr == "MaxAtomicCounterBufferSize")
|
||||
resources->maxAtomicCounterBufferSize = value;
|
||||
else if (tokenStr == "MaxTransformFeedbackBuffers")
|
||||
resources->maxTransformFeedbackBuffers = value;
|
||||
else if (tokenStr == "MaxTransformFeedbackInterleavedComponents")
|
||||
resources->maxTransformFeedbackInterleavedComponents = value;
|
||||
else if (tokenStr == "MaxCullDistances")
|
||||
resources->maxCullDistances = value;
|
||||
else if (tokenStr == "MaxCombinedClipAndCullDistances")
|
||||
resources->maxCombinedClipAndCullDistances = value;
|
||||
else if (tokenStr == "MaxSamples")
|
||||
resources->maxSamples = value;
|
||||
else if (tokenStr == "MaxMeshOutputVerticesNV")
|
||||
resources->maxMeshOutputVerticesNV = value;
|
||||
else if (tokenStr == "MaxMeshOutputPrimitivesNV")
|
||||
resources->maxMeshOutputPrimitivesNV = value;
|
||||
else if (tokenStr == "MaxMeshWorkGroupSizeX_NV")
|
||||
resources->maxMeshWorkGroupSizeX_NV = value;
|
||||
else if (tokenStr == "MaxMeshWorkGroupSizeY_NV")
|
||||
resources->maxMeshWorkGroupSizeY_NV = value;
|
||||
else if (tokenStr == "MaxMeshWorkGroupSizeZ_NV")
|
||||
resources->maxMeshWorkGroupSizeZ_NV = value;
|
||||
else if (tokenStr == "MaxTaskWorkGroupSizeX_NV")
|
||||
resources->maxTaskWorkGroupSizeX_NV = value;
|
||||
else if (tokenStr == "MaxTaskWorkGroupSizeY_NV")
|
||||
resources->maxTaskWorkGroupSizeY_NV = value;
|
||||
else if (tokenStr == "MaxTaskWorkGroupSizeZ_NV")
|
||||
resources->maxTaskWorkGroupSizeZ_NV = value;
|
||||
else if (tokenStr == "MaxMeshViewCountNV")
|
||||
resources->maxMeshViewCountNV = value;
|
||||
else if (tokenStr == "nonInductiveForLoops")
|
||||
resources->limits.nonInductiveForLoops = (value != 0);
|
||||
else if (tokenStr == "whileLoops")
|
||||
resources->limits.whileLoops = (value != 0);
|
||||
else if (tokenStr == "doWhileLoops")
|
||||
resources->limits.doWhileLoops = (value != 0);
|
||||
else if (tokenStr == "generalUniformIndexing")
|
||||
resources->limits.generalUniformIndexing = (value != 0);
|
||||
else if (tokenStr == "generalAttributeMatrixVectorIndexing")
|
||||
resources->limits.generalAttributeMatrixVectorIndexing = (value != 0);
|
||||
else if (tokenStr == "generalVaryingIndexing")
|
||||
resources->limits.generalVaryingIndexing = (value != 0);
|
||||
else if (tokenStr == "generalSamplerIndexing")
|
||||
resources->limits.generalSamplerIndexing = (value != 0);
|
||||
else if (tokenStr == "generalVariableIndexing")
|
||||
resources->limits.generalVariableIndexing = (value != 0);
|
||||
else if (tokenStr == "generalConstantMatrixVectorIndexing")
|
||||
resources->limits.generalConstantMatrixVectorIndexing = (value != 0);
|
||||
else
|
||||
printf("Warning: unrecognized limit (%s) in configuration file.\n", tokenStr.c_str());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
||||
@@ -1,57 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2016 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef _STAND_ALONE_RESOURCE_LIMITS_INCLUDED_
|
||||
#define _STAND_ALONE_RESOURCE_LIMITS_INCLUDED_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "../glslang/Include/ResourceLimits.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
// These are the default resources for TBuiltInResources, used for both
|
||||
// - parsing this string for the case where the user didn't supply one,
|
||||
// - dumping out a template for user construction of a config file.
|
||||
extern const TBuiltInResource DefaultTBuiltInResource;
|
||||
|
||||
// Returns the DefaultTBuiltInResource as a human-readable string.
|
||||
std::string GetDefaultTBuiltInResourceString();
|
||||
|
||||
// Decodes the resource limits from |config| to |resources|.
|
||||
void DecodeResourceLimits(TBuiltInResource* resources, char* config);
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // _STAND_ALONE_RESOURCE_LIMITS_INCLUDED_
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,95 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2013 LunarG, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
#ifndef WORKLIST_H_INCLUDED
|
||||
#define WORKLIST_H_INCLUDED
|
||||
|
||||
#include "../glslang/OSDependent/osinclude.h"
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
namespace glslang {
|
||||
|
||||
class TWorkItem {
|
||||
public:
|
||||
TWorkItem() { }
|
||||
explicit TWorkItem(const std::string& s) :
|
||||
name(s) { }
|
||||
std::string name;
|
||||
std::string results;
|
||||
std::string resultsIndex;
|
||||
};
|
||||
|
||||
class TWorklist {
|
||||
public:
|
||||
TWorklist() { }
|
||||
virtual ~TWorklist() { }
|
||||
|
||||
void add(TWorkItem* item)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
worklist.push_back(item);
|
||||
}
|
||||
|
||||
bool remove(TWorkItem*& item)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
|
||||
if (worklist.empty())
|
||||
return false;
|
||||
item = worklist.front();
|
||||
worklist.pop_front();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int size()
|
||||
{
|
||||
return (int)worklist.size();
|
||||
}
|
||||
|
||||
bool empty()
|
||||
{
|
||||
return worklist.empty();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::mutex mutex;
|
||||
std::list<TWorkItem*> worklist;
|
||||
};
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // WORKLIST_H_INCLUDED
|
||||
@@ -1,65 +0,0 @@
|
||||
/**
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2020, Travis Fort
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**/
|
||||
|
||||
#include "resource_limits_c.h"
|
||||
#include "ResourceLimits.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
const glslang_resource_t* glslang_default_resource(void)
|
||||
{
|
||||
return reinterpret_cast<const glslang_resource_t*>(&glslang::DefaultTBuiltInResource);
|
||||
}
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996)
|
||||
#endif
|
||||
|
||||
const char* glslang_default_resource_string()
|
||||
{
|
||||
std::string cpp_str = glslang::GetDefaultTBuiltInResourceString();
|
||||
char* c_str = (char*)malloc(cpp_str.length() + 1);
|
||||
strcpy(c_str, cpp_str.c_str());
|
||||
return c_str;
|
||||
}
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
void glslang_decode_resource_limits(glslang_resource_t* resources, char* config)
|
||||
{
|
||||
glslang::DecodeResourceLimits(reinterpret_cast<TBuiltInResource*>(resources), config);
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/**
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2020, Travis Fort
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**/
|
||||
|
||||
#ifndef _STAND_ALONE_RESOURCE_LIMITS_C_INCLUDED_
|
||||
#define _STAND_ALONE_RESOURCE_LIMITS_C_INCLUDED_
|
||||
|
||||
#include "../glslang/Include/glslang_c_interface.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// These are the default resources for TBuiltInResources, used for both
|
||||
// - parsing this string for the case where the user didn't supply one,
|
||||
// - dumping out a template for user construction of a config file.
|
||||
const glslang_resource_t* glslang_default_resource(void);
|
||||
|
||||
// Returns the DefaultTBuiltInResource as a human-readable string.
|
||||
// NOTE: User is responsible for freeing this string.
|
||||
const char* glslang_default_resource_string();
|
||||
|
||||
// Decodes the resource limits from |config| to |resources|.
|
||||
void glslang_decode_resource_limits(glslang_resource_t* resources, char* config);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _STAND_ALONE_RESOURCE_LIMITS_C_INCLUDED_
|
||||
@@ -1,341 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2015 LunarG, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "../SPIRV/SPVRemapper.h"
|
||||
|
||||
namespace {
|
||||
|
||||
typedef unsigned int SpvWord;
|
||||
|
||||
// Poor man's basename: given a complete path, return file portion.
|
||||
// E.g:
|
||||
// Linux: /foo/bar/test -> test
|
||||
// Win: c:\foo\bar\test -> test
|
||||
// It's not very efficient, but that doesn't matter for our minimal-duty use.
|
||||
// Using boost::filesystem would be better in many ways, but want to avoid that dependency.
|
||||
|
||||
// OS dependent path separator (avoiding boost::filesystem dependency)
|
||||
#if defined(_WIN32)
|
||||
char path_sep_char() { return '\\'; }
|
||||
#else
|
||||
char path_sep_char() { return '/'; }
|
||||
#endif
|
||||
|
||||
std::string basename(const std::string filename)
|
||||
{
|
||||
const size_t sepLoc = filename.find_last_of(path_sep_char());
|
||||
|
||||
return (sepLoc == filename.npos) ? filename : filename.substr(sepLoc+1);
|
||||
}
|
||||
|
||||
void errHandler(const std::string& str) {
|
||||
std::cout << str << std::endl;
|
||||
exit(5);
|
||||
}
|
||||
|
||||
void logHandler(const std::string& str) {
|
||||
std::cout << str << std::endl;
|
||||
}
|
||||
|
||||
// Read word stream from disk
|
||||
void read(std::vector<SpvWord>& spv, const std::string& inFilename, int verbosity)
|
||||
{
|
||||
std::ifstream fp;
|
||||
|
||||
if (verbosity > 0)
|
||||
logHandler(std::string(" reading: ") + inFilename);
|
||||
|
||||
spv.clear();
|
||||
fp.open(inFilename, std::fstream::in | std::fstream::binary);
|
||||
|
||||
if (fp.fail())
|
||||
errHandler("error opening file for read: ");
|
||||
|
||||
// Reserve space (for efficiency, not for correctness)
|
||||
fp.seekg(0, fp.end);
|
||||
spv.reserve(size_t(fp.tellg()) / sizeof(SpvWord));
|
||||
fp.seekg(0, fp.beg);
|
||||
|
||||
while (!fp.eof()) {
|
||||
SpvWord inWord;
|
||||
fp.read((char *)&inWord, sizeof(inWord));
|
||||
|
||||
if (!fp.eof()) {
|
||||
spv.push_back(inWord);
|
||||
if (fp.fail())
|
||||
errHandler(std::string("error reading file: ") + inFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void write(std::vector<SpvWord>& spv, const std::string& outFile, int verbosity)
|
||||
{
|
||||
if (outFile.empty())
|
||||
errHandler("missing output filename.");
|
||||
|
||||
std::ofstream fp;
|
||||
|
||||
if (verbosity > 0)
|
||||
logHandler(std::string(" writing: ") + outFile);
|
||||
|
||||
fp.open(outFile, std::fstream::out | std::fstream::binary);
|
||||
|
||||
if (fp.fail())
|
||||
errHandler(std::string("error opening file for write: ") + outFile);
|
||||
|
||||
for (auto it = spv.cbegin(); it != spv.cend(); ++it) {
|
||||
SpvWord word = *it;
|
||||
fp.write((char *)&word, sizeof(word));
|
||||
if (fp.fail())
|
||||
errHandler(std::string("error writing file: ") + outFile);
|
||||
}
|
||||
|
||||
// file is closed by destructor
|
||||
}
|
||||
|
||||
// Print helpful usage message to stdout, and exit
|
||||
void usage(const char* const name, const char* const msg = 0)
|
||||
{
|
||||
if (msg)
|
||||
std::cout << msg << std::endl << std::endl;
|
||||
|
||||
std::cout << "Usage: " << std::endl;
|
||||
|
||||
std::cout << " " << basename(name)
|
||||
<< " [-v[v[...]] | --verbose [int]]"
|
||||
<< " [--map (all|types|names|funcs)]"
|
||||
<< " [--dce (all|types|funcs)]"
|
||||
<< " [--opt (all|loadstore)]"
|
||||
<< " [--strip-all | --strip all | -s]"
|
||||
<< " [--do-everything]"
|
||||
<< " --input | -i file1 [file2...] --output|-o DESTDIR"
|
||||
<< std::endl;
|
||||
|
||||
std::cout << " " << basename(name) << " [--version | -V]" << std::endl;
|
||||
std::cout << " " << basename(name) << " [--help | -?]" << std::endl;
|
||||
|
||||
exit(5);
|
||||
}
|
||||
|
||||
// grind through each SPIR in turn
|
||||
void execute(const std::vector<std::string>& inputFile, const std::string& outputDir,
|
||||
int opts, int verbosity)
|
||||
{
|
||||
for (auto it = inputFile.cbegin(); it != inputFile.cend(); ++it) {
|
||||
const std::string &filename = *it;
|
||||
std::vector<SpvWord> spv;
|
||||
read(spv, filename, verbosity);
|
||||
spv::spirvbin_t(verbosity).remap(spv, opts);
|
||||
|
||||
const std::string outfile = outputDir + path_sep_char() + basename(filename);
|
||||
|
||||
write(spv, outfile, verbosity);
|
||||
}
|
||||
|
||||
if (verbosity > 0)
|
||||
std::cout << "Done: " << inputFile.size() << " file(s) processed" << std::endl;
|
||||
}
|
||||
|
||||
// Parse command line options
|
||||
void parseCmdLine(int argc, char** argv, std::vector<std::string>& inputFile,
|
||||
std::string& outputDir,
|
||||
int& options,
|
||||
int& verbosity)
|
||||
{
|
||||
if (argc < 2)
|
||||
usage(argv[0]);
|
||||
|
||||
verbosity = 0;
|
||||
options = spv::spirvbin_t::NONE;
|
||||
|
||||
// Parse command line.
|
||||
// boost::program_options would be quite a bit nicer, but we don't want to
|
||||
// introduce a dependency on boost.
|
||||
for (int a=1; a<argc; ) {
|
||||
const std::string arg = argv[a];
|
||||
|
||||
if (arg == "--output" || arg == "-o") {
|
||||
// Output directory
|
||||
if (++a >= argc)
|
||||
usage(argv[0], "--output requires an argument");
|
||||
if (!outputDir.empty())
|
||||
usage(argv[0], "--output can be provided only once");
|
||||
|
||||
outputDir = argv[a++];
|
||||
|
||||
// Remove trailing directory separator characters
|
||||
while (!outputDir.empty() && outputDir.back() == path_sep_char())
|
||||
outputDir.pop_back();
|
||||
|
||||
}
|
||||
else if (arg == "-vv") { verbosity = 2; ++a; } // verbosity shortcuts
|
||||
else if (arg == "-vvv") { verbosity = 3; ++a; } // ...
|
||||
else if (arg == "-vvvv") { verbosity = 4; ++a; } // ...
|
||||
else if (arg == "-vvvvv") { verbosity = 5; ++a; } // ...
|
||||
|
||||
else if (arg == "--verbose" || arg == "-v") {
|
||||
++a;
|
||||
verbosity = 1;
|
||||
|
||||
if (a < argc) {
|
||||
char* end_ptr = 0;
|
||||
int verb = ::strtol(argv[a], &end_ptr, 10);
|
||||
// If we have not read to the end of the string or
|
||||
// the string contained no elements, then we do not want to
|
||||
// store the value.
|
||||
if (*end_ptr == '\0' && end_ptr != argv[a]) {
|
||||
verbosity = verb;
|
||||
++a;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (arg == "--version" || arg == "-V") {
|
||||
std::cout << basename(argv[0]) << " version 0.97" << std::endl;
|
||||
exit(0);
|
||||
} else if (arg == "--input" || arg == "-i") {
|
||||
// Collect input files
|
||||
for (++a; a < argc && argv[a][0] != '-'; ++a)
|
||||
inputFile.push_back(argv[a]);
|
||||
} else if (arg == "--do-everything") {
|
||||
++a;
|
||||
options = options | spv::spirvbin_t::DO_EVERYTHING;
|
||||
} else if (arg == "--strip-all" || arg == "-s") {
|
||||
++a;
|
||||
options = options | spv::spirvbin_t::STRIP;
|
||||
} else if (arg == "--strip") {
|
||||
++a;
|
||||
if (strncmp(argv[a], "all", 3) == 0) {
|
||||
options = options | spv::spirvbin_t::STRIP;
|
||||
++a;
|
||||
}
|
||||
} else if (arg == "--dce") {
|
||||
// Parse comma (or colon, etc) separated list of things to dce
|
||||
++a;
|
||||
for (const char* c = argv[a]; *c; ++c) {
|
||||
if (strncmp(c, "all", 3) == 0) {
|
||||
options = (options | spv::spirvbin_t::DCE_ALL);
|
||||
c += 3;
|
||||
} else if (strncmp(c, "*", 1) == 0) {
|
||||
options = (options | spv::spirvbin_t::DCE_ALL);
|
||||
c += 1;
|
||||
} else if (strncmp(c, "funcs", 5) == 0) {
|
||||
options = (options | spv::spirvbin_t::DCE_FUNCS);
|
||||
c += 5;
|
||||
} else if (strncmp(c, "types", 5) == 0) {
|
||||
options = (options | spv::spirvbin_t::DCE_TYPES);
|
||||
c += 5;
|
||||
}
|
||||
}
|
||||
++a;
|
||||
} else if (arg == "--map") {
|
||||
// Parse comma (or colon, etc) separated list of things to map
|
||||
++a;
|
||||
for (const char* c = argv[a]; *c; ++c) {
|
||||
if (strncmp(c, "all", 3) == 0) {
|
||||
options = (options | spv::spirvbin_t::MAP_ALL);
|
||||
c += 3;
|
||||
} else if (strncmp(c, "*", 1) == 0) {
|
||||
options = (options | spv::spirvbin_t::MAP_ALL);
|
||||
c += 1;
|
||||
} else if (strncmp(c, "types", 5) == 0) {
|
||||
options = (options | spv::spirvbin_t::MAP_TYPES);
|
||||
c += 5;
|
||||
} else if (strncmp(c, "names", 5) == 0) {
|
||||
options = (options | spv::spirvbin_t::MAP_NAMES);
|
||||
c += 5;
|
||||
} else if (strncmp(c, "funcs", 5) == 0) {
|
||||
options = (options | spv::spirvbin_t::MAP_FUNCS);
|
||||
c += 5;
|
||||
}
|
||||
}
|
||||
++a;
|
||||
} else if (arg == "--opt") {
|
||||
++a;
|
||||
for (const char* c = argv[a]; *c; ++c) {
|
||||
if (strncmp(c, "all", 3) == 0) {
|
||||
options = (options | spv::spirvbin_t::OPT_ALL);
|
||||
c += 3;
|
||||
} else if (strncmp(c, "*", 1) == 0) {
|
||||
options = (options | spv::spirvbin_t::OPT_ALL);
|
||||
c += 1;
|
||||
} else if (strncmp(c, "loadstore", 9) == 0) {
|
||||
options = (options | spv::spirvbin_t::OPT_LOADSTORE);
|
||||
c += 9;
|
||||
}
|
||||
}
|
||||
++a;
|
||||
} else if (arg == "--help" || arg == "-?") {
|
||||
usage(argv[0]);
|
||||
} else {
|
||||
usage(argv[0], "Unknown command line option");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
std::vector<std::string> inputFile;
|
||||
std::string outputDir;
|
||||
int opts;
|
||||
int verbosity;
|
||||
|
||||
#ifdef use_cpp11
|
||||
// handle errors by exiting
|
||||
spv::spirvbin_t::registerErrorHandler(errHandler);
|
||||
|
||||
// Log messages to std::cout
|
||||
spv::spirvbin_t::registerLogHandler(logHandler);
|
||||
#endif
|
||||
|
||||
if (argc < 2)
|
||||
usage(argv[0]);
|
||||
|
||||
parseCmdLine(argc, argv, inputFile, outputDir, opts, verbosity);
|
||||
|
||||
if (outputDir.empty())
|
||||
usage(argv[0], "Output directory required");
|
||||
|
||||
// Main operations: read, remap, and write.
|
||||
execute(inputFile, outputDir, opts, verbosity);
|
||||
|
||||
// If we get here, everything went OK! Nothing more to be done.
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
MaxLights 32
|
||||
MaxClipPlanes 6
|
||||
MaxTextureUnits 32
|
||||
MaxTextureCoords 32
|
||||
MaxVertexAttribs 8
|
||||
MaxVertexUniformComponents 4096
|
||||
MaxVaryingFloats 64
|
||||
MaxVertexTextureImageUnits 0
|
||||
MaxCombinedTextureImageUnits 8
|
||||
MaxTextureImageUnits 8
|
||||
MaxFragmentUniformComponents 4096
|
||||
MaxDrawBuffers 1
|
||||
MaxVertexUniformVectors 16
|
||||
MaxVaryingVectors 8
|
||||
MaxFragmentUniformVectors 16
|
||||
MaxVertexOutputVectors 16
|
||||
MaxFragmentInputVectors 15
|
||||
MinProgramTexelOffset -8
|
||||
MaxProgramTexelOffset 7
|
||||
nonInductiveForLoops 0
|
||||
whileLoops 0
|
||||
doWhileLoops 0
|
||||
generalUniformIndexing 0
|
||||
generalAttributeMatrixVectorIndexing 0
|
||||
generalVaryingIndexing 0
|
||||
generalSamplerIndexing 0
|
||||
generalVariableIndexing 0
|
||||
generalConstantMatrixVectorIndexing 0
|
||||
@@ -1,230 +0,0 @@
|
||||
// okay
|
||||
#version 100
|
||||
int a[3] = { 2, 3, 4, }; // ERROR (lots)
|
||||
#version 100
|
||||
int uint;
|
||||
|
||||
attribute vec4 v[3]; // ERROR
|
||||
|
||||
float f = 2; // ERROR
|
||||
|
||||
uniform block { // ERROR
|
||||
int x;
|
||||
};
|
||||
|
||||
void foo(float);
|
||||
|
||||
void main()
|
||||
{
|
||||
foo(3); // ERROR
|
||||
int s = 1 << 4; // ERROR
|
||||
s = 16 >> 2; // ERROR
|
||||
if (a == a); // ERROR
|
||||
int b, c;
|
||||
b = c & 4; // ERROR
|
||||
b = c % 4; // ERROR
|
||||
b = c | 4; // ERROR
|
||||
b >>= 2; // ERROR
|
||||
b <<= 2; // ERROR
|
||||
b %= 3; // ERROR
|
||||
|
||||
struct S {
|
||||
float f;
|
||||
float a[10];
|
||||
} s1, s2;
|
||||
|
||||
s1 = s2; // ERROR
|
||||
if (s1 == s2); // ERROR
|
||||
if (s1 != s2); // ERROR
|
||||
|
||||
switch(b) { // ERROR
|
||||
}
|
||||
}
|
||||
|
||||
invariant gl_FragColor;
|
||||
float fa[]; // ERROR
|
||||
float f13;
|
||||
invariant f13; // ERROR
|
||||
struct S { int a; };
|
||||
invariant S; // ERROR, not an input or output
|
||||
invariant float fi; // ERROR
|
||||
varying vec4 av;
|
||||
invariant av; // okay in v100
|
||||
|
||||
void foo10()
|
||||
{
|
||||
invariant f; // ERROR
|
||||
invariant float f2; // ERROR
|
||||
float f3;
|
||||
invariant f3; // ERROR
|
||||
}
|
||||
|
||||
uniform vec2 uv2;
|
||||
invariant uv2; // ERROR
|
||||
invariant uniform vec3 uv3; // ERROR
|
||||
|
||||
sampler2D glob2D; // ERROR
|
||||
void f11(sampler2D p2d)
|
||||
{
|
||||
sampler2D v2D; // ERROR
|
||||
}
|
||||
varying sampler2D vary2D; // ERROR
|
||||
|
||||
struct sp {
|
||||
highp float f;
|
||||
in float g; // ERROR
|
||||
uniform float h; // ERROR
|
||||
invariant float i; // ERROR
|
||||
};
|
||||
|
||||
uniform sampler3D s3D; // ERROR
|
||||
|
||||
#extension GL_OES_texture_3D : enable
|
||||
|
||||
precision highp sampler3D;
|
||||
uniform sampler3D s3D2;
|
||||
|
||||
void foo234()
|
||||
{
|
||||
texture3D(s3D2, vec3(0.2), 0.2);
|
||||
texture3DProj(s3D2, v[1], 0.4);
|
||||
dFdx(v[0]); // ERROR
|
||||
dFdy(3.2); // ERROR
|
||||
fwidth(f13); // ERROR
|
||||
}
|
||||
|
||||
#extension GL_OES_standard_derivatives : enable
|
||||
|
||||
void foo236()
|
||||
{
|
||||
dFdx(v[0]);
|
||||
dFdy(3.2);
|
||||
fwidth(f13);
|
||||
gl_FragDepth = f13; // ERROR
|
||||
gl_FragDepthEXT = f13; // ERROR
|
||||
}
|
||||
|
||||
#extension GL_EXT_frag_depth : enable
|
||||
|
||||
void foo239()
|
||||
{
|
||||
gl_FragDepth = f13; // ERROR
|
||||
gl_FragDepthEXT = f13;
|
||||
}
|
||||
|
||||
#extension GL_OES_EGL_image_external : enable
|
||||
|
||||
uniform samplerExternalOES sExt;
|
||||
|
||||
void foo245()
|
||||
{
|
||||
texture2D(sExt, vec2(0.2));
|
||||
texture2DProj(sExt, vec3(f13));
|
||||
texture2DProj(sExt, v[2]);
|
||||
}
|
||||
|
||||
precision mediump samplerExternalOES;
|
||||
uniform samplerExternalOES mediumExt;
|
||||
uniform highp samplerExternalOES highExt;
|
||||
|
||||
void foo246()
|
||||
{
|
||||
texture2D(mediumExt, vec2(0.2));
|
||||
texture2DProj(highExt, v[2]);
|
||||
texture3D(sExt, vec3(f13)); // ERROR
|
||||
texture2DProjLod(sExt, vec3(f13), f13); // ERROR
|
||||
int a;
|
||||
~a; // ERROR
|
||||
a | a; // ERROR
|
||||
a & a; // ERROR
|
||||
}
|
||||
|
||||
#extension GL_OES_EGL_image_external : disable
|
||||
uniform sampler2D s2Dg;
|
||||
|
||||
int foo203940(int a, float b, float a) // ERROR, a redefined
|
||||
{
|
||||
texture2DProjGradEXT(s2Dg, vec3(f13), uv2, uv2); // ERROR, extension not enabled
|
||||
return a;
|
||||
}
|
||||
|
||||
float f123 = 4.0f; // ERROR
|
||||
float f124 = 5e10F; // ERROR
|
||||
|
||||
#extension GL_EXT_shader_texture_lod : enable
|
||||
|
||||
uniform samplerCube sCube;
|
||||
|
||||
void foo323433()
|
||||
{
|
||||
texture2DLodEXT(s2Dg, uv2, f13);
|
||||
texture2DProjGradEXT(s2Dg, vec3(f13), uv2, uv2);
|
||||
texture2DGradEXT(s2Dg, uv2, uv2, uv2);
|
||||
textureCubeGradEXT(sCube, vec3(f13), vec3(f13), vec3(f13));
|
||||
}
|
||||
|
||||
int fgfg(float f, mediump int i);
|
||||
int fgfg(float f, highp int i) { return 2; } // ERROR, precision qualifier difference
|
||||
|
||||
int fffg(float f);
|
||||
int fffg(float f); // ERROR, can't have multiple prototypes
|
||||
|
||||
int gggf(float f);
|
||||
int gggf(float f) { return 2; }
|
||||
|
||||
int agggf(float f) { return 2; }
|
||||
int agggf(float f);
|
||||
int agggf(float f); // ERROR, second prototype
|
||||
|
||||
varying struct SSS { float f; } s; // ERROR
|
||||
|
||||
int vf(void);
|
||||
int vf2();
|
||||
int vf3(void v); // ERROR
|
||||
int vf4(int, void); // ERROR
|
||||
int vf5(int, void v); // ERROR
|
||||
|
||||
void badswizzle()
|
||||
{
|
||||
vec3 a[5];
|
||||
a.y; // ERROR, no array swizzle
|
||||
a.zy; // ERROR, no array swizzle
|
||||
a.nothing; // ERROR
|
||||
a.length(); // ERROR, not this version
|
||||
a.method(); // ERROR
|
||||
}
|
||||
|
||||
float fooinit();
|
||||
|
||||
float fooinittest()
|
||||
{
|
||||
return fooinit();
|
||||
}
|
||||
|
||||
// Test extra-function initializers
|
||||
const float fi1 = 3.0;
|
||||
const float fi2 = 4.0;
|
||||
const float fi3 = 5.0;
|
||||
|
||||
float fooinit()
|
||||
{
|
||||
return fi1 + fi2 + fi3; // should make a constant of 12.0
|
||||
}
|
||||
|
||||
int init1 = gl_FrontFacing ? 1 : 2; // ERROR, non-const initializer
|
||||
|
||||
#ifdef GL_EXT_shader_non_constant_global_initializers
|
||||
#extension GL_EXT_shader_non_constant_global_initializers : enable
|
||||
#endif
|
||||
|
||||
int init2 = gl_FrontFacing ? 1 : 2;
|
||||
|
||||
#define A__B // error
|
||||
int a__b; // error
|
||||
|
||||
#pragma STDGL invariant(all)
|
||||
|
||||
#line 3000
|
||||
#error line of this error should be 3000
|
||||
|
||||
uniform samplerExternalOES badExt; // syntax ERROR
|
||||
@@ -1,76 +0,0 @@
|
||||
#version 100
|
||||
|
||||
int ga, gb;
|
||||
float f;
|
||||
|
||||
uniform sampler2D fsa[3];
|
||||
uniform float fua[10];
|
||||
attribute mat3 am3;
|
||||
attribute vec2 av2;
|
||||
varying vec4 va[4];
|
||||
|
||||
const mat2 m2 = mat2(1.0);
|
||||
const vec3 v3 = vec3(2.0);
|
||||
|
||||
void foo(inout float a) {}
|
||||
|
||||
int bar()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
while (ga < gb) { }
|
||||
|
||||
do { } while (false);
|
||||
|
||||
for ( ; ; ); // ERROR
|
||||
for ( ; ga==gb; ); // ERROR
|
||||
for ( ; ; f++); // ERROR
|
||||
for ( ga = 0; ; ); // ERROR
|
||||
for ( bool a = false; ; ); // ERROR
|
||||
for (float a = 0.0; a == sin(f); ); // ERROR
|
||||
for ( int a = 0; a < 10; a *= 2); // ERROR
|
||||
for ( int a = 0; a <= 20; a++) --a; // ERROR
|
||||
for ( int a = 0; a <= 20; a++) { if (ga==0) a = 4; } // ERROR
|
||||
for (float a = 0.0; a <= 20.0; a += 2.0);
|
||||
for (float a = 0.0; a != 20.0; a -= 2.0) { if (ga==0) ga = 4; }
|
||||
for (float a = 0.0; a == 20.0; a--) for (float a = 0.0; a == 20.0; a--); // two different 'a's, everything okay
|
||||
for (float a = 0.0; a <= 20.0; a += 2.0);
|
||||
for (float a = 0.0; a <= 20.0; a += 2.0);
|
||||
for (float a = 0.0; a > 2.0 * 20.0; a += v3.y);
|
||||
for (float a = 0.0; a >= 20.0; a += 2.0) foo(a); // ERROR
|
||||
|
||||
int ia[9];
|
||||
|
||||
fsa[ga]; // ERROR
|
||||
fua[ga];
|
||||
am3[ga]; // ERROR
|
||||
av2[ga]; // ERROR
|
||||
va[2+ga]; // ERROR
|
||||
m2[ga]; // ERROR
|
||||
v3[ga/2]; // ERROR
|
||||
ia[ga]; // ERROR
|
||||
|
||||
for (int a = 3; a >= 0; a--) {
|
||||
fsa[a];
|
||||
fua[a+2];
|
||||
am3[3*a];
|
||||
av2[3*a];
|
||||
va[a-1];
|
||||
m2[a/2];
|
||||
v3[a];
|
||||
ia[a];
|
||||
ia[bar()]; // ERROR
|
||||
}
|
||||
|
||||
fsa[2];
|
||||
fua[3];
|
||||
am3[2];
|
||||
av2[1];
|
||||
va[1];
|
||||
m2[1];
|
||||
v3[1];
|
||||
ia[3];
|
||||
}
|
||||
Loaded 100 of 2771 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user